diff --git a/.gitignore b/.gitignore index 3090417dd..7023aaa80 100644 --- a/.gitignore +++ b/.gitignore @@ -13,11 +13,11 @@ Win32_LIB_ASM_Release *.dgb *.debug *.debug.txt -/bin/VC10/ -/objs/VC10/ *.user *.db *.opendb /.vs /debian /assets/debian +/make +/bin diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d2d4a7e6..6f901d3d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.13) # Enable CCache early set(SRB2_USE_CCACHE OFF CACHE BOOL "Use CCache") @@ -34,12 +34,11 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") ### Useful functions -# Prepend sources with current source directory -function(prepend_sources SOURCE_FILES) - foreach(SOURCE_FILE ${${SOURCE_FILES}}) - set(MODIFIED ${MODIFIED} ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE_FILE}) - endforeach() - set(${SOURCE_FILES} ${MODIFIED} PARENT_SCOPE) +# Add sources from Sourcefile +function(target_sourcefile type) + file(STRINGS Sourcefile list + REGEX "[-0-9A-Za-z_]+\.${type}") + target_sources(SRB2SDL2 PRIVATE ${list}) endfunction() # Macro to add OSX framework diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..7ee12d837 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +ifdef SILENT +MAKEFLAGS+=--no-print-directory +endif + +all : + +% :: + @$(MAKE) -C src $(MAKECMDGOALS) diff --git a/README.md b/README.md index 8a5ca1a1f..49a3cc36d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Sonic Robo Blast 2 +[![latest release](https://badgen.net/github/release/STJr/SRB2/stable)](https://github.com/STJr/SRB2/releases/latest) [![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2) [![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2) diff --git a/appveyor.yml b/appveyor.yml index 2acc2f712..348b727b1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,16 +1,12 @@ -version: 2.2.8.{branch}-{build} +version: 2.2.10.{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,43 +61,31 @@ 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 "BUILD_PATH=bin\Mingw64\Release" - ) else ( - set "BUILD_PATH=bin\Mingw\Release" - ) -- if [%X86_64%] == [1] ( set "CONFIGURATION=%CONFIGURATION%64" ) - ccache -s - set BUILD_ARCHIVE=%REPO%-%GITSHORT%-%CONFIGURATION%.7z - set BUILDSARCHIVE=%REPO%-%CONFIGURATION%.7z -- cmd: 7z a %BUILD_ARCHIVE% %BUILD_PATH% -xr!.gitignore +- cmd: 7z a %BUILD_ARCHIVE% bin -xr!.gitignore - appveyor PushArtifact %BUILD_ARCHIVE% #- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE% #- appveyor PushArtifact %BUILDSARCHIVE% @@ -139,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/assets/CMakeLists.txt b/assets/CMakeLists.txt index 3ea7c28df..ef228759c 100644 --- a/assets/CMakeLists.txt +++ b/assets/CMakeLists.txt @@ -22,8 +22,7 @@ set(SRB2_ASSET_INSTALL ON set(SRB2_ASSET_HASHED "srb2.pk3;\ player.dta;\ -zones.pk3;\ -patch.pk3" +zones.pk3" CACHE STRING "Asset filenames to apply MD5 checks. No spaces between entries!" ) diff --git a/assets/README.txt b/assets/README.txt index 8d2fefa54..5480cb7b0 100644 --- a/assets/README.txt +++ b/assets/README.txt @@ -1,24 +1,21 @@ SONIC ROBO BLAST 2 -Sonic Robo Blast 2 (SRB2) is a 3D Sonic the Hedgehog fangame based on a -modified version of Doom Legacy. +Sonic Robo Blast 2 (SRB2) is a 3D Sonic the Hedgehog fangame, based on a modified version of Doom Legacy. + +https://www.srb2.org LICENSE -The source code for SRB2 is licensed under the GNU General Public -License, Version 2. See LICENSE.txt for the full text of this license. +The source code for SRB2 is licensed under the GNU General Public License, Version 2. See LICENSE.txt for the full text of this license. -SRB2 uses various third-party libraries, including SDL, SDL Mixer, and -their dependencies. See LICENSE-3RD-PARTY.txt for the licenses of these -libraries. +SRB2 uses various third-party libraries, including SDL, SDL Mixer, and their dependencies. See LICENSE-3RD-PARTY.txt for the licenses of these libraries. SOURCE CODE -You may obtain the source code for SRB2, including the source code for -specific version releases, at the following web sites: +You may obtain the source code for SRB2, including the source code for specific version releases, at the following web sites: STJr GitLab: -https://git.magicalgirl.moe/STJr/SRB2 +https://git.do.srb2.org/STJr/SRB2 GitHub: https://github.com/STJr/SRB2 @@ -27,25 +24,27 @@ CONTACT You may contact Sonic Team Junior via the following web sites: -SRB2.ORG: -https://www.srb2.org - SRB2 Message Board: https://mb.srb2.org SRB2 Official Discord: -https://discord.gg/pYDXzpX (13+) +https://discord.gg/b3BGb8A + +Twitter: +https://twitter.com/SonicTeamJr + +Facebook: +https://facebook.com/SonicRoboBlast2 + COPYRIGHT AND DISCLAIMER -Design and content on SRB2 is copyright 1998-2019 by Sonic Team Junior. -All non-original material on SRB2.ORG is copyrighted by their -respective owners, and no copyright infringement is intended. The owner -of the SRB2.ORG domain is only acting as an ISP, and is therefore not -responsible for any content on SRB2.ORG under the 1998 DMCA. This -site, its webmaster, and its staff make no profit whatsoever (in fact, -we lose money). Sonic Team Junior assumes no responsibility for the -content on any Sonic Team Junior fan sites. +Design and content in Sonic Robo Blast 2 is copyright 1998-2022 by Sonic Team Jr. -Sonic Team Junior is in no way affiliated with SEGA or Sonic Team. We do -not claim ownership of any of SEGA's intellectual property used in SRB2. +All original material in this game is copyrighted by their respective owners, and no copyright infringement is intended. Sonic Team Jr. is in no way affiliated with SEGA or Sonic Team, and we do not claim ownership of any of SEGA's intellectual property used in SRB2. + +Sonic Robo Blast 2 is not commercial software. If you purchased this game, you have been scammed! Sonic Team Jr.'s staff makes no profit whatsoever (in fact, we lose money). + +The owner of the srb2.org domain is only acting as an ISP, and is therefore not responsible for any content on srb2.org under the 1998 DMCA. Sonic Team Jr. assumes no responsibility for the content on any Sonic Team Jr. fan sites. + +This software is provided as-is with no warranty whatsoever. diff --git a/bin/FreeBSD/Debug/.gitignore b/bin/FreeBSD/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/bin/FreeBSD/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/bin/FreeBSD/Release/.gitignore b/bin/FreeBSD/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/bin/FreeBSD/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/bin/Linux/Debug/.gitignore b/bin/Linux/Debug/.gitignore deleted file mode 100644 index 56dee6f95..000000000 --- a/bin/Linux/Debug/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/lsdlsrb2 diff --git a/bin/Linux/Release/.gitignore b/bin/Linux/Release/.gitignore deleted file mode 100644 index 5b5c54a54..000000000 --- a/bin/Linux/Release/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/lsdlsrb2 -/pnd -/*.mo diff --git a/bin/Linux64/Debug/.gitignore b/bin/Linux64/Debug/.gitignore deleted file mode 100644 index 56dee6f95..000000000 --- a/bin/Linux64/Debug/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/lsdlsrb2 diff --git a/bin/Linux64/Release/.gitignore b/bin/Linux64/Release/.gitignore deleted file mode 100644 index 56dee6f95..000000000 --- a/bin/Linux64/Release/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/lsdlsrb2 diff --git a/bin/Mingw/Debug/.gitignore b/bin/Mingw/Debug/.gitignore deleted file mode 100644 index 834f313e3..000000000 --- a/bin/Mingw/Debug/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.exe -*.mo -r_opengl.dll diff --git a/bin/Mingw/Release/.gitignore b/bin/Mingw/Release/.gitignore deleted file mode 100644 index 3458ff764..000000000 --- a/bin/Mingw/Release/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.exe -*.mo -r_opengl.dll -*.bat diff --git a/bin/Mingw64/Debug/.gitignore b/bin/Mingw64/Debug/.gitignore deleted file mode 100644 index e431dca5d..000000000 --- a/bin/Mingw64/Debug/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/srb2sdl.exe -/srb2win.exe -/r_opengl.dll diff --git a/bin/Mingw64/Release/.gitignore b/bin/Mingw64/Release/.gitignore deleted file mode 100644 index e431dca5d..000000000 --- a/bin/Mingw64/Release/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/srb2sdl.exe -/srb2win.exe -/r_opengl.dll diff --git a/bin/SDL/Debug/.gitignore b/bin/SDL/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/bin/SDL/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/bin/SDL/Release/.gitignore b/bin/SDL/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/bin/SDL/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/bin/VC/.gitignore b/bin/VC/.gitignore deleted file mode 100644 index e52f825b2..000000000 --- a/bin/VC/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Release -/Debug diff --git a/bin/VC9/.gitignore b/bin/VC9/.gitignore deleted file mode 100644 index 205fe45de..000000000 --- a/bin/VC9/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/Win32 -/x64 diff --git a/bin/dummy/.gitignore b/bin/dummy/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/bin/dummy/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/debian-template/rules b/debian-template/rules index 0a77624cb..12ceaf98b 100644 --- a/debian-template/rules +++ b/debian-template/rules @@ -78,7 +78,7 @@ NONX86 = $(shell test "`echo $(CROSS_COMPILE_HOST) | grep 'i[3-6]86'`" || echo " MAKEARGS = $(OS) $(NONX86) $(PREFIX) EXENAME=$(EXENAME) DBGNAME=$(DBGNAME) NOOBJDUMP=1 # SDL_PKGCONFIG=sdl2 PNG_PKGCONFIG=libpng MENUFILE1 = ?package($(PACKAGE)):needs="X11" section="$(SECTION)" MENUFILE2 = title="$(TITLE)" command="/$(PKGDIR)/$(PACKAGE)" -BINDIR := $(DIR)/bin/Linux/Release +BINDIR := $(DIR)/bin/ # FIXME pkg-config dir hacks # Launchpad doesn't need this; it actually makes i386 builds fail due to cross-compile diff --git a/extras/conf/SRB2-22.cfg b/extras/conf/SRB2-22.cfg index a0d40cdf0..969f645f3 100644 --- a/extras/conf/SRB2-22.cfg +++ b/extras/conf/SRB2-22.cfg @@ -425,20 +425,18 @@ sectortypes 12 = "Space Countdown"; 13 = "Ramp Sector (double step-up/down)"; 14 = "Non-Ramp Sector (no step-down)"; - 15 = "Bouncy FOF"; + 15 = "Bouncy FOF "; 16 = "Trigger Line Ex. (Pushable Objects)"; 32 = "Trigger Line Ex. (Anywhere, All Players)"; 48 = "Trigger Line Ex. (Floor Touch, All Players)"; 64 = "Trigger Line Ex. (Anywhere in Sector)"; 80 = "Trigger Line Ex. (Floor Touch)"; - 96 = "Trigger Line Ex. (Emerald Check)"; - 112 = "Trigger Line Ex. (NiGHTS Mare)"; + 96 = "Trigger Line Ex. (Emerald Check) "; + 112 = "Trigger Line Ex. (NiGHTS Mare) "; 128 = "Check for Linedef Executor on FOFs"; 144 = "Egg Capsule"; - 160 = "Special Stage Time/Spheres Parameters"; - 176 = "Custom Global Gravity"; - 512 = "Wind/Current"; - 1024 = "Conveyor Belt"; + 160 = "Special Stage Time/Spheres Parameters "; + 176 = "Custom Global Gravity "; 1280 = "Speed Pad"; 4096 = "Star Post Activator"; 8192 = "Exit/Special Stage Pit/Return Flag"; @@ -475,7 +473,7 @@ gen_sectortypes 12 = "Space Countdown"; 13 = "Ramp Sector (double step-up/down)"; 14 = "Non-Ramp Sector (no step-down)"; - 15 = "Bouncy FOF"; + 15 = "Bouncy FOF "; } second @@ -486,19 +484,17 @@ gen_sectortypes 48 = "Trigger Line Ex. (Floor Touch, All Players)"; 64 = "Trigger Line Ex. (Anywhere in Sector)"; 80 = "Trigger Line Ex. (Floor Touch)"; - 96 = "Trigger Line Ex. (Emerald Check)"; - 112 = "Trigger Line Ex. (NiGHTS Mare)"; + 96 = "Trigger Line Ex. (Emerald Check) "; + 112 = "Trigger Line Ex. (NiGHTS Mare) "; 128 = "Check for Linedef Executor on FOFs"; 144 = "Egg Capsule"; - 160 = "Special Stage Time/Spheres Parameters"; - 176 = "Custom Global Gravity"; + 160 = "Special Stage Time/Spheres Parameters "; + 176 = "Custom Global Gravity "; } third { 0 = "Normal"; - 512 = "Wind/Current"; - 1024 = "Conveyor Belt"; 1280 = "Speed Pad"; } @@ -640,6 +636,39 @@ linedeftypes prefix = "(63)"; } + 96 + { + title = "Apply Tag to Tagged Sectors"; + prefix = "(96)"; + flags1024text = "[10] Offsets are target tags"; + flags8192text = "[13] Use front side offsets"; + flags32768text = "[15] Use back side offsets"; + } + + 97 + { + title = "Apply Tag to Front Sector"; + prefix = "(97)"; + flags8192text = "[13] Use front side offsets"; + flags32768text = "[15] Use back side offsets"; + } + + 98 + { + title = "Apply Tag to Back Sector"; + prefix = "(98)"; + flags8192text = "[13] Use front side offsets"; + flags32768text = "[15] Use back side offsets"; + } + + 99 + { + title = "Apply Tag to Front and Back Sectors"; + prefix = "(99)"; + flags8192text = "[13] Use front side offsets"; + flags32768text = "[15] Use back side offsets"; + } + 540 { title = "Floor Friction"; @@ -738,6 +767,12 @@ linedeftypes flags2text = "[1] Use control sector tag"; flags64text = "[6] No sound effect"; } + + 76 + { + title = "Make FOF Bouncy"; + prefix = "(76)"; + } } polyobject @@ -746,13 +781,13 @@ linedeftypes 20 { - title = "First Line"; + title = "PolyObject First Line"; prefix = "(20)"; } 22 { - title = "Parameters"; + title = "PolyObject Parameters"; prefix = "(22)"; flags8text = "[3] Set translucency by X offset"; flags32text = "[5] Render outer sides only"; @@ -765,19 +800,19 @@ linedeftypes 30 { - title = "Waving Flag"; + title = "PolyObject Waving Flag"; prefix = "(30)"; } 31 { - title = "Displacement by Front Sector"; + title = "Move PolyObject by Front Sector Displacement"; prefix = "(31)"; } 32 { - title = "Angular Displacement by Front Sector"; + title = "Rotate PolyObject by Front Sector Displacement"; prefix = "(32)"; flags64text = "[6] Don't turn players"; flags512text = "[9] Turn all objects"; @@ -1058,6 +1093,7 @@ linedeftypes { title = "Water, Opaque"; prefix = "(120)"; + flags2text = "[1] Make lava intangible"; flags8text = "[3] Slope skew sides"; flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; @@ -1073,6 +1109,7 @@ linedeftypes { title = "Water, Translucent"; prefix = "(121)"; + flags2text = "[1] Make lava intangible"; flags8text = "[3] Slope skew sides"; flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; @@ -1089,6 +1126,7 @@ linedeftypes { title = "Water, Opaque, No Sides"; prefix = "(122)"; + flags2text = "[1] Make lava intangible"; flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; flags1024text = "[10] Ripple effect"; @@ -1103,6 +1141,7 @@ linedeftypes { title = "Water, Translucent, No Sides"; prefix = "(123)"; + flags2text = "[1] Make lava intangible"; flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; flags1024text = "[10] Ripple effect"; @@ -1118,6 +1157,7 @@ linedeftypes { title = "Goo Water, Translucent"; prefix = "(124)"; + flags2text = "[1] Make lava intangible"; flags8text = "[3] Slope skew sides"; flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; @@ -1134,6 +1174,7 @@ linedeftypes { title = "Goo Water, Translucent, No Sides"; prefix = "(125)"; + flags2text = "[1] Make lava intangible"; flags64text = "[6] Use two light levels"; flags512text = "[9] Use target light level"; flags1024text = "[10] Ripple effect"; @@ -1240,7 +1281,7 @@ linedeftypes 160 { - title = "Floating, Bobbing"; + title = "Water Bobbing"; prefix = "(160)"; flags8text = "[3] Slope skew sides"; flags32text = "[5] Only block player"; @@ -1636,12 +1677,14 @@ linedeftypes { title = "Continuous"; prefix = "(300)"; + flags1024text = "[10] Use faster, unordered execution"; } 301 { title = "Each Time"; prefix = "(301)"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Also trigger on exit"; } @@ -1649,6 +1692,7 @@ linedeftypes { title = "Once"; prefix = "(302)"; + flags1024text = "[10] Use faster, unordered execution"; } 303 @@ -1658,6 +1702,7 @@ linedeftypes flags2text = "[1] Rings greater or equal"; flags64text = "[6] Rings less or equal"; flags512text = "[9] Consider all players"; + flags1024text = "[10] Use faster, unordered execution"; } 304 @@ -1667,18 +1712,21 @@ linedeftypes flags2text = "[1] Rings greater or equal"; flags64text = "[6] Rings less or equal"; flags512text = "[9] Consider all players"; + flags1024text = "[10] Use faster, unordered execution"; } 305 { title = "Character Ability - Continuous"; prefix = "(305)"; + flags1024text = "[10] Use faster, unordered execution"; } 306 { title = "Character Ability - Each Time"; prefix = "(306)"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Also trigger on exit"; } @@ -1686,24 +1734,28 @@ linedeftypes { title = "Character Ability - Once"; prefix = "(307)"; + flags1024text = "[10] Use faster, unordered execution"; } 308 { title = "Race Only - Once"; prefix = "(308)"; + flags1024text = "[10] Use faster, unordered execution"; } 309 { title = "CTF Red Team - Continuous"; prefix = "(309)"; + flags1024text = "[10] Use faster, unordered execution"; } 310 { title = "CTF Red Team - Each Time"; prefix = "(310)"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Also trigger on exit"; } @@ -1711,12 +1763,14 @@ linedeftypes { title = "CTF Blue Team - Continuous"; prefix = "(311)"; + flags1024text = "[10] Use faster, unordered execution"; } 312 { title = "CTF Blue Team - Each Time"; prefix = "(312)"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Also trigger on exit"; } @@ -1724,6 +1778,7 @@ linedeftypes { title = "No More Enemies - Once"; prefix = "(313)"; + flags1024text = "[10] Use faster, unordered execution"; } 314 @@ -1732,6 +1787,7 @@ linedeftypes prefix = "(314)"; flags64text = "[6] Number greater or equal"; flags512text = "[9] Number less"; + flags1024text = "[10] Use faster, unordered execution"; } 315 @@ -1740,30 +1796,35 @@ linedeftypes prefix = "(315)"; flags64text = "[6] Number greater or equal"; flags512text = "[9] Number less"; + flags1024text = "[10] Use faster, unordered execution"; } 317 { title = "Condition Set Trigger - Continuous"; prefix = "(317)"; + flags1024text = "[10] Use faster, unordered execution"; } 318 { title = "Condition Set Trigger - Once"; prefix = "(318)"; + flags1024text = "[10] Use faster, unordered execution"; } 319 { title = "Unlockable - Continuous"; prefix = "(319)"; + flags1024text = "[10] Use faster, unordered execution"; } 320 { title = "Unlockable - Once"; prefix = "(320)"; + flags1024text = "[10] Use faster, unordered execution"; } 321 @@ -1771,6 +1832,7 @@ linedeftypes title = "Trigger After X Calls - Continuous"; prefix = "(321)"; flags64text = "[6] Trigger more than once"; + flags1024text = "[10] Use faster, unordered execution"; } @@ -1779,6 +1841,7 @@ linedeftypes title = "Trigger After X Calls - Each Time"; prefix = "(322)"; flags64text = "[6] Trigger more than once"; + flags1024text = "[10] Use faster, unordered execution"; } 323 @@ -1793,6 +1856,7 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Run if no more mares"; flags32768text = "[15] Run if player is not NiGHTS"; } @@ -1800,6 +1864,7 @@ linedeftypes 324 { title = "NiGHTSerize - Once"; + prefix = "(324)"; flags2text = "[1] Mare >= Front X Offset"; flags8text = "[3] Run only if player is NiGHTS"; flags16text = "[4] Count from lowest of players"; @@ -1808,14 +1873,15 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Run if no more mares"; flags32768text = "[15] Run if player is not NiGHTS"; - prefix = "(324)"; } 325 { title = "De-NiGHTSerize - Each Time"; + prefix = "(325)"; flags2text = "[1] Mare >= Front X Offset"; flags8text = "[3] Run if anyone is NiGHTS"; flags16text = "[4] Count from lowest of players"; @@ -1824,13 +1890,14 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; + flags1024text = "[10] Use faster, unordered execution"; flags32768text = "[15] Run if no one is NiGHTS"; - prefix = "(325)"; } 326 { title = "De-NiGHTSerize - Once"; + prefix = "(326)"; flags2text = "[1] Mare >= Front X Offset"; flags8text = "[3] Run if anyone is NiGHTS"; flags16text = "[4] Count from lowest of players"; @@ -1839,13 +1906,14 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; + flags1024text = "[10] Use faster, unordered execution"; flags32768text = "[15] Run if no one is NiGHTS"; - prefix = "(326)"; } 327 { title = "NiGHTS Lap - Each Time"; + prefix = "(327)"; flags2text = "[1] Mare >= Front X Offset"; flags16text = "[4] Count from lowest of players"; flags32text = "[5] Lap <= Front Y Offset"; @@ -1853,12 +1921,13 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; - prefix = "(327)"; + flags1024text = "[10] Use faster, unordered execution"; } 328 { title = "NiGHTS Lap - Once"; + prefix = "(328)"; flags2text = "[1] Mare >= Front X Offset"; flags16text = "[4] Count from lowest of players"; flags32text = "[5] Lap <= Front Y Offset"; @@ -1866,12 +1935,13 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; - prefix = "(328)"; + flags1024text = "[10] Use faster, unordered execution"; } 329 { title = "Ideya Capture Touch - Each Time"; + prefix = "(329)"; flags2text = "[1] Mare >= Front X Offset"; flags8text = "[3] Run regardless of spheres"; flags16text = "[4] Count from lowest of players"; @@ -1880,14 +1950,15 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Only if not enough spheres"; flags32768text = "[15] Run when entering Capture"; - prefix = "(329)"; } 330 { title = "Ideya Capture Touch - Once"; + prefix = "(330)"; flags2text = "[1] Mare >= Front X Offset"; flags8text = "[3] Run regardless of spheres"; flags16text = "[4] Count from lowest of players"; @@ -1896,57 +1967,106 @@ linedeftypes flags128text = "[7] Lap >= Front Y Offset"; flags256text = "[8] Count laps from Bonus Time"; flags512text = "[9] Count from triggering player"; + flags1024text = "[10] Use faster, unordered execution"; flags16384text = "[14] Only if not enough spheres"; flags32768text = "[15] Run when entering Capture"; - prefix = "(330)"; } 331 { title = "Player Skin - Continuous"; - flags64text = "[6] Disable for this skin"; prefix = "(331)"; + flags64text = "[6] Disable for this skin"; + flags1024text = "[10] Use faster, unordered execution"; } 332 { title = "Player Skin - Each Time"; - flags64text = "[6] Disable for this skin"; prefix = "(332)"; + flags64text = "[6] Disable for this skin"; + flags1024text = "[10] Use faster, unordered execution"; } 333 { title = "Player Skin - Once"; - flags64text = "[6] Disable for this skin"; prefix = "(333)"; + flags64text = "[6] Disable for this skin"; + flags1024text = "[10] Use faster, unordered execution"; } 334 { title = "Object Dye - Continuous"; - flags64text = "[6] Disable for this color"; prefix = "(334)"; + flags64text = "[6] Disable for this color"; + flags1024text = "[10] Use faster, unordered execution"; } 335 { title = "Object Dye - Each Time"; - flags64text = "[6] Disable for this color"; prefix = "(335)"; + flags64text = "[6] Disable for this color"; + flags1024text = "[10] Use faster, unordered execution"; } 336 { title = "Object Dye - Once"; - flags64text = "[6] Disable for this color"; prefix = "(336)"; + flags64text = "[6] Disable for this color"; + flags1024text = "[10] Use faster, unordered execution"; + } + + 337 + { + title = "Emerald Check - Continuous"; + prefix = "(337)"; + } + + 338 + { + title = "Emerald Check - Each Time"; + prefix = "(338)"; + } + + 339 + { + title = "Emerald Check - Once"; + prefix = "(339)"; + } + + 340 + { + title = "NiGHTS Mare - Continuous"; + flags2text = "[1] Mare greater or equal"; + flags64text = "[6] Mare less or equal"; + prefix = "(340)"; + } + + 341 + { + title = "NiGHTS Mare - Each Time"; + flags2text = "[1] Mare greater or equal"; + flags64text = "[6] Mare less or equal"; + prefix = "(341)"; + } + + 342 + { + title = "NiGHTS Mare - Once"; + flags2text = "[1] Mare greater or equal"; + flags64text = "[6] Mare less or equal"; + prefix = "(342)"; } 399 { title = "Level Load"; prefix = "(399)"; + flags1024text = "[10] Use faster, unordered execution"; } } @@ -1959,7 +2079,7 @@ linedeftypes title = "Set Tagged Sector's Floor Height/Texture"; prefix = "(400)"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Keep floor flat"; + flags64text = "[6] Don't change floor texture"; } 401 @@ -1967,27 +2087,40 @@ linedeftypes title = "Set Tagged Sector's Ceiling Height/Texture"; prefix = "(401)"; flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Don't change ceiling texture"; } 402 { - title = "Set Tagged Sector's Light Level"; + title = "Copy Light Level to Tagged Sectors"; prefix = "(402)"; flags8text = "[3] Set delay by backside sector"; } + 408 + { + title = "Set Tagged Sector's Flats"; + prefix = "(408)"; + flags64text = "[6] Don't set floor flat"; + flags512text = "[9] Don't set ceiling flat"; + } + 409 { title = "Change Tagged Sector's Tag"; prefix = "(409)"; + flags2text = "[1] Remove tag"; flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Add tag"; } 410 { title = "Change Front Sector's Tag"; prefix = "(410)"; + flags2text = "[1] Remove tag"; flags8text = "[3] Set delay by backside sector"; + flags64text = "[6] Add tag"; } 416 @@ -2045,6 +2178,14 @@ linedeftypes prefix = "(435)"; flags8text = "[3] Set delay by backside sector"; } + + 467 + { + title = "Set Tagged Sector's Light Level"; + prefix = "(467)"; + flags8text = "[3] Set delay by backside sector"; + flags256text = "[8] Set relative to current"; + } } linedefexecplane @@ -2057,7 +2198,7 @@ linedeftypes prefix = "(403)"; flags2text = "[1] Trigger linedef executor"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Change floor flat"; + flags64text = "[6] Change floor texture"; } 404 @@ -2066,7 +2207,7 @@ linedeftypes prefix = "(404)"; flags2text = "[1] Trigger linedef executor"; flags8text = "[3] Set delay by backside sector"; - flags64text = "[6] Change ceiling flat"; + flags64text = "[6] Change ceiling texture"; } 405 @@ -2498,35 +2639,35 @@ linedeftypes 480 { - title = "Door Slide"; + title = "PolyObject Door Slide"; prefix = "(480)"; flags8text = "[3] Set delay by backside sector"; } 481 { - title = "Door Swing"; + title = "PolyObject Door Swing"; prefix = "(481)"; flags8text = "[3] Set delay by backside sector"; } 482 { - title = "Move"; + title = "Move PolyObject"; prefix = "(482)"; flags8text = "[3] Set delay by backside sector"; } 483 { - title = "Move, Override"; + title = "Move PolyObject, Override"; prefix = "(483)"; flags8text = "[3] Set delay by backside sector"; } 484 { - title = "Rotate Right"; + title = "Rotate PolyObject Right"; prefix = "(484)"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] Don't turn players"; @@ -2535,7 +2676,7 @@ linedeftypes 485 { - title = "Rotate Right, Override"; + title = "Rotate PolyObject Right, Override"; prefix = "(485)"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] Don't turn players"; @@ -2544,7 +2685,7 @@ linedeftypes 486 { - title = "Rotate Left"; + title = "Rotate PolyObject Left"; prefix = "(486)"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] Don't turn players"; @@ -2553,7 +2694,7 @@ linedeftypes 487 { - title = "Rotate Left, Override"; + title = "Rotate PolyObject Left, Override"; prefix = "(487)"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] Don't turn players"; @@ -2562,7 +2703,7 @@ linedeftypes 488 { - title = "Move by Waypoints"; + title = "Move PolyObject by Waypoints"; prefix = "(488)"; flags8text = "[3] Set delay by backside sector"; flags32text = "[5] Reverse order"; @@ -2573,7 +2714,7 @@ linedeftypes 489 { - title = "Turn Invisible, Intangible"; + title = "Turn PolyObject Invisible, Intangible"; prefix = "(489)"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] Only invisible"; @@ -2581,7 +2722,7 @@ linedeftypes 490 { - title = "Turn Visible, Tangible"; + title = "Turn PolyObject Visible, Tangible"; prefix = "(490)"; flags8text = "[3] Set delay by backside sector"; flags64text = "[6] Only visible"; @@ -2589,7 +2730,7 @@ linedeftypes 491 { - title = "Set Translucency"; + title = "Set PolyObject Translucency"; prefix = "(491)"; flags8text = "[3] Set delay by backside sector"; flags16text = "[4] Set raw alpha by Front X"; @@ -2598,7 +2739,7 @@ linedeftypes 492 { - title = "Fade Translucency"; + title = "Fade PolyObject Translucency"; prefix = "(492)"; flags8text = "[3] Set delay by backside sector"; flags16text = "[4] Set raw alpha by Front X"; @@ -2628,7 +2769,7 @@ linedeftypes 502 { - title = "Scroll Tagged Wall"; + title = "Scroll Tagged Walls"; prefix = "(502)"; flags128text = "[7] Use texture offsets"; flags256text = "[8] Scroll back side"; @@ -2636,7 +2777,7 @@ linedeftypes 503 { - title = "Scroll Tagged Wall (Accelerative)"; + title = "Scroll Tagged Walls (Accelerative)"; prefix = "(503)"; flags128text = "[7] Use texture offsets"; flags256text = "[8] Scroll back side"; @@ -2644,7 +2785,7 @@ linedeftypes 504 { - title = "Scroll Tagged Wall (Displacement)"; + title = "Scroll Tagged Walls (Displacement)"; prefix = "(504)"; flags128text = "[7] Use texture offsets"; flags256text = "[8] Scroll back side"; @@ -2917,8 +3058,10 @@ linedeftypes prefix = "(700)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 1; + copyslopeargs = 1; } 701 @@ -2927,8 +3070,10 @@ linedeftypes prefix = "(701)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 2; + copyslopeargs = 4; } 702 @@ -2937,8 +3082,10 @@ linedeftypes prefix = "(702)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 3; + copyslopeargs = 5; } 703 @@ -2947,8 +3094,10 @@ linedeftypes prefix = "(703)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 9; + copyslopeargs = 8; } 704 @@ -2979,8 +3128,10 @@ linedeftypes prefix = "(710)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 4; + copyslopeargs = 2; } 711 @@ -2989,8 +3140,10 @@ linedeftypes prefix = "(711)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 8; + copyslopeargs = 8; } 712 @@ -2999,8 +3152,10 @@ linedeftypes prefix = "(712)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 12; + copyslopeargs = 10; } 713 @@ -3009,8 +3164,10 @@ linedeftypes prefix = "(713)"; flags2048text = "[11] No physics"; flags4096text = "[12] Dynamic"; + flags32768text = "[15] Copy to other side"; slope = "regular"; slopeargs = 6; + copyslopeargs = 6; } 714 @@ -3059,16 +3216,89 @@ linedeftypes slopeargs = 3; } + 723 + { + title = "Copy Backside Floor Slope from Line Tag"; + prefix = "(723)"; + slope = "copy"; + slopeargs = 4; + } + + 724 + { + title = "Copy Backside Ceiling Slope from Line Tag"; + prefix = "(724)"; + slope = "copy"; + slopeargs = 8; + } + + 725 + { + title = "Copy Backside Floor and Ceiling Slope from Line Tag"; + prefix = "(725)"; + slope = "copy"; + slopeargs = 12; + } + + 730 + { + title = "Copy Frontside Floor Slope to Backside"; + prefix = "(730)"; + slope = "copy"; + copyslopeargs = 1; + } + + 731 + { + title = "Copy Frontside Ceiling Slope to Backside"; + prefix = "(731)"; + slope = "copy"; + copyslopeargs = 4; + } + + 732 + { + title = "Copy Frontside Floor and Ceiling Slope to Backside"; + prefix = "(732)"; + slope = "copy"; + copyslopeargs = 5; + } + + 733 + { + title = "Copy Backside Floor Slope to Frontside"; + prefix = "(733)"; + slope = "copy"; + copyslopeargs = 2; + } + + 734 + { + title = "Copy Backside Ceiling Slope to Frontside"; + prefix = "(734)"; + slope = "copy"; + copyslopeargs = 8; + } + + 735 + { + title = "Copy Backside Floor and Ceiling Slope to Frontside"; + prefix = "(735)"; + slope = "copy"; + copyslopeargs = 10; + } + 799 { title = "Set Tagged Dynamic Slope Vertex to Front Sector Height"; prefix = "(799)"; + flags64text = "[6] Use relative heights"; } } transwall { - title = "Translucent Wall"; + title = "Translucent Walls"; 900 { @@ -3129,6 +3359,192 @@ linedeftypes title = "Fog Wall"; prefix = "(909)"; } + + 910 + { + title = "100% Additive"; + prefix = "(910)"; + } + + 911 + { + title = "90% Additive"; + prefix = "(911)"; + } + + 912 + { + title = "80% Additive"; + prefix = "(912)"; + } + + 913 + { + title = "70% Additive"; + prefix = "(913)"; + } + + 914 + { + title = "60% Additive"; + prefix = "(914)"; + } + + 915 + { + title = "50% Additive"; + prefix = "(915)"; + } + + 916 + { + title = "40% Additive"; + prefix = "(916)"; + } + + 917 + { + title = "30% Additive"; + prefix = "(917)"; + } + + 918 + { + title = "20% Additive"; + prefix = "(918)"; + } + + 919 + { + title = "10% Additive"; + prefix = "(919)"; + } + + 920 + { + title = "100% Subtractive"; + prefix = "(920)"; + } + + 921 + { + title = "90% Subtractive"; + prefix = "(921)"; + } + + 922 + { + title = "80% Subtractive"; + prefix = "(922)"; + } + + 923 + { + title = "70% Subtractive"; + prefix = "(923)"; + } + + 924 + { + title = "60% Subtractive"; + prefix = "(924)"; + } + + 925 + { + title = "50% Subtractive"; + prefix = "(925)"; + } + + 926 + { + title = "40% Subtractive"; + prefix = "(926)"; + } + + 927 + { + title = "30% Subtractive"; + prefix = "(927)"; + } + + 928 + { + title = "20% Subtractive"; + prefix = "(928)"; + } + + 929 + { + title = "10% Subtractive"; + prefix = "(929)"; + } + + 930 + { + title = "100% Reverse Subtractive"; + prefix = "(930)"; + } + + 931 + { + title = "90% Reverse Subtractive"; + prefix = "(931)"; + } + + 932 + { + title = "80% Reverse Subtractive"; + prefix = "(932)"; + } + + 933 + { + title = "70% Reverse Subtractive"; + prefix = "(933)"; + } + + 934 + { + title = "60% Reverse Subtractive"; + prefix = "(934)"; + } + + 935 + { + title = "50% Reverse Subtractive"; + prefix = "(935)"; + } + + 936 + { + title = "40% Reverse Subtractive"; + prefix = "(936)"; + } + + 937 + { + title = "30% Reverse Subtractive"; + prefix = "(937)"; + } + + 938 + { + title = "20% Reverse Subtractive"; + prefix = "(938)"; + } + + 939 + { + title = "10% Reverse Subtractive"; + prefix = "(939)"; + } + + 940 + { + title = "Modulate"; + prefix = "(940)"; + } } } @@ -3393,6 +3809,7 @@ thingtypes width = 8; height = 28; angletext = "Jump strength"; + fixedrotation = 1; } 103 { @@ -3431,6 +3848,7 @@ thingtypes width = 12; height = 64; angletext = "Firing delay"; + fixedrotation = 1; } 122 { @@ -3482,6 +3900,7 @@ thingtypes sprite = "ARCHA1"; width = 24; height = 32; + flags8text = "[8] Don't jump away"; } 118 { @@ -3547,9 +3966,10 @@ thingtypes { title = "Pterabyte Spawner"; sprite = "PTERA2A8"; - width = 16; - height = 16; - parametertext = "No. Pterabytes"; + width = 24; + height = 48; + parametertext = "Spawns +1"; + arrow = 0; } 136 { @@ -3654,6 +4074,7 @@ thingtypes sprite = "BUMBA1"; width = 16; height = 32; + flags8text = "[8] Cannot move"; } 124 { @@ -3681,17 +4102,16 @@ thingtypes { title = "Egg Mobile"; sprite = "EGGMA1"; - width = 24; - height = 76; + width = 36; + height = 84; flags4text = "[4] End level on death"; - flags8text = "[8] Alternate laser attack"; } 201 { title = "Egg Slimer"; sprite = "EGGNA1"; - width = 24; - height = 76; + width = 36; + height = 84; flags4text = "[4] End level on death"; flags8text = "[8] Speed up when hit"; } @@ -3699,7 +4119,7 @@ thingtypes { title = "Sea Egg"; sprite = "EGGOA1"; - width = 32; + width = 36; height = 116; flags4text = "[4] End level on death"; } @@ -3707,8 +4127,8 @@ thingtypes { title = "Egg Colosseum"; sprite = "EGGPA1"; - width = 24; - height = 76; + width = 36; + height = 84; flags4text = "[4] End level on death"; } 204 @@ -3719,6 +4139,7 @@ thingtypes height = 60; flags1text = "[1] Grayscale mode"; flags4text = "[4] End level on death"; + flags8text = "[8] Skip intro"; } 206 { @@ -3771,6 +4192,7 @@ thingtypes height = 16; sprite = "internal:capsule"; angletext = "Tag"; + fixedrotation = 1; } 292 { @@ -3781,11 +4203,13 @@ thingtypes flags8text = "[8] Sea Egg shooting point"; sprite = "internal:eggmanway"; angletext = "No. (Sea Egg)"; + fixedrotation = 1; flagsvaluetext = "No. (Brak)"; parametertext = "Next"; } 293 { + arrow = 0; title = "Metal Sonic Gather Point"; sprite = "internal:metal"; width = 8; @@ -3793,6 +4217,7 @@ thingtypes } 294 { + arrow = 0; title = "Fang Waypoint"; flags8text = "[8] Center waypoint"; sprite = "internal:eggmanway"; @@ -3820,79 +4245,79 @@ thingtypes 301 { title = "Bounce Ring"; - sprite = "internal:RNGBA0"; + sprite = "RNGBA0"; } 302 { title = "Rail Ring"; - sprite = "internal:RNGRA0"; + sprite = "RNGRA0"; } 303 { title = "Infinity Ring"; - sprite = "internal:RNGIA0"; + sprite = "RNGIA0"; } 304 { title = "Automatic Ring"; - sprite = "internal:RNGAA0"; + sprite = "RNGAA0"; } 305 { title = "Explosion Ring"; - sprite = "internal:RNGEA0"; + sprite = "RNGEA0"; } 306 { title = "Scatter Ring"; - sprite = "internal:RNGSA0"; + sprite = "RNGSA0"; } 307 { title = "Grenade Ring"; - sprite = "internal:RNGGA0"; + sprite = "RNGGA0"; } 308 { title = "CTF Team Ring (Red)"; - sprite = "internal:RRNGA0"; + sprite = "internal:TRNGA0r"; width = 16; } 309 { title = "CTF Team Ring (Blue)"; - sprite = "internal:BRNGA0"; + sprite = "internal:TRNGA0b"; width = 16; } 330 { title = "Bounce Ring Panel"; - sprite = "internal:PIKBA0"; + sprite = "PIKBA0"; } 331 { title = "Rail Ring Panel"; - sprite = "internal:PIKRA0"; + sprite = "PIKRA0"; } 332 { title = "Automatic Ring Panel"; - sprite = "internal:PIKAA0"; + sprite = "PIKAA0"; } 333 { title = "Explosion Ring Panel"; - sprite = "internal:PIKEA0"; + sprite = "PIKEA0"; } 334 { title = "Scatter Ring Panel"; - sprite = "internal:PIKSA0"; + sprite = "PIKSA0"; } 335 { title = "Grenade Ring Panel"; - sprite = "internal:PIKGA0"; + sprite = "PIKGA0"; } } @@ -3986,6 +4411,7 @@ thingtypes flags8height = 24; flags8text = "[8] Float"; angletext = "Tag"; + fixedrotation = 1; } } @@ -4000,6 +4426,7 @@ thingtypes flags4text = "[4] Random (Strong)"; flags8text = "[8] Random (Weak)"; angletext = "Tag"; + fixedrotation = 1; 400 { @@ -4131,6 +4558,7 @@ thingtypes height = 44; flags1text = "[1] Run linedef executor on pop"; angletext = "Tag"; + fixedrotation = 1; 431 { @@ -4228,6 +4656,7 @@ thingtypes height = 128; flags4text = "[4] Respawn at center"; angletext = "Angle/Order"; + fixedrotation = 1; parametertext = "Order"; } 520 @@ -4259,7 +4688,7 @@ thingtypes flags1text = "[1] Start retracted"; flags4text = "[4] Retractable"; flags8text = "[8] Intangible"; - parametertext = "Initial delay"; + parametertext = "Start delay"; } 523 { @@ -4271,7 +4700,8 @@ thingtypes flags4text = "[4] Retractable"; flags8text = "[8] Intangible"; angletext = "Retraction interval"; - parametertext = "Initial delay"; + fixedrotation = 1; + parametertext = "Start delay"; } 1130 { @@ -4320,6 +4750,7 @@ thingtypes flags4text = "[4] Invisible"; flags8text = "[8] No distance check"; angletext = "Lift height"; + fixedrotation = 1; } 541 { @@ -4335,6 +4766,7 @@ thingtypes width = 32; height = 64; angletext = "Strength"; + fixedrotation = 1; } 543 { @@ -4344,6 +4776,7 @@ thingtypes height = 64; flags8text = "[8] Respawn"; angletext = "Color"; + fixedrotation = 1; } 550 { @@ -4617,6 +5050,9 @@ thingtypes title = "Slope Vertex"; sprite = "internal:vertexslope"; angletext = "Tag"; + fixedrotation = 1; + parametertext = "Absolute?"; + flagsvaluetext = "Absolute Z"; } 751 @@ -4638,6 +5074,7 @@ thingtypes title = "Zoom Tube Waypoint"; sprite = "internal:zoom"; angletext = "Order"; + fixedrotation = 1; } 754 @@ -4647,6 +5084,7 @@ thingtypes flags8text = "[8] Push using XYZ"; sprite = "GWLGA0"; angletext = "Radius"; + fixedrotation = 1; } 755 { @@ -4655,6 +5093,7 @@ thingtypes flags8text = "[8] Pull using XYZ"; sprite = "GWLRA0"; angletext = "Radius"; + fixedrotation = 1; } 756 { @@ -4663,6 +5102,7 @@ thingtypes width = 32; height = 16; angletext = "Tag"; + fixedrotation = 1; } 757 { @@ -4671,6 +5111,7 @@ thingtypes width = 8; height = 16; angletext = "Tag"; + fixedrotation = 1; } 758 { @@ -4681,21 +5122,24 @@ thingtypes { title = "PolyObject Anchor"; sprite = "internal:polyanchor"; - angletext = "ID"; + angletext = "Tag"; + fixedrotation = 1; } 761 { title = "PolyObject Spawn Point"; sprite = "internal:polycenter"; - angletext = "ID"; + angletext = "Tag"; + fixedrotation = 1; } 762 { title = "PolyObject Spawn Point (Crush)"; sprite = "internal:polycentercrush"; - angletext = "ID"; + angletext = "Tag"; + fixedrotation = 1; } 780 { @@ -4703,6 +5147,7 @@ thingtypes sprite = "internal:skyb"; flags4text = "[4] In-map centerpoint"; parametertext = "ID"; + fixedrotation = 1; } } @@ -4896,7 +5341,8 @@ thingtypes width = 8; height = 16; hangs = 1; - angletext = "Dripping interval"; + angletext = "Dripping delay"; + fixedrotation = 1; } 1003 { @@ -4953,7 +5399,7 @@ thingtypes 1011 { title = "Stalagmite (DSZ2)"; - sprite = "DSTGA0"; + sprite = "DSTGB0"; width = 8; height = 116; flags4text = "[4] Double size"; @@ -5038,6 +5484,8 @@ thingtypes flags4text = "[4] No sounds"; flags8text = "[8] Double size"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1105 { @@ -5048,6 +5496,8 @@ thingtypes flags4text = "[4] No sounds"; flags8text = "[8] Double size"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1106 { @@ -5058,6 +5508,8 @@ thingtypes flags4text = "[4] No sounds"; flags8text = "[8] Red spring"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1107 { @@ -5067,6 +5519,8 @@ thingtypes height = 34; flags8text = "[8] Double size"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1108 { @@ -5086,6 +5540,8 @@ thingtypes flags4text = "[4] No sounds"; flags8text = "[8] Double size"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1110 { @@ -5095,6 +5551,8 @@ thingtypes height = 34; flags4text = "[4] No sounds"; angletext = "Tag"; + parametertext = "Spokes"; + fixedrotation = 1; } 1111 { @@ -5224,6 +5682,9 @@ thingtypes sprite = "EGR1A1"; width = 20; height = 72; + arrow = 1; + flags4text = "[4] Move right"; + flags8text = "[8] Move left"; } 1128 { @@ -5272,6 +5733,7 @@ thingtypes width = 8; height = 16; angletext = "Tag"; + fixedrotation = 1; } 1203 { @@ -5342,6 +5804,7 @@ thingtypes sprite = "WWSGAR"; width = 22; height = 64; + arrow = 1; } 1213 { @@ -5349,6 +5812,7 @@ thingtypes sprite = "WWS2AR"; width = 22; height = 64; + arrow = 1; } 1214 { @@ -5356,6 +5820,7 @@ thingtypes sprite = "WWS3ALAR"; width = 16; height = 192; + arrow = 1; } 1215 { @@ -5371,6 +5836,8 @@ thingtypes sprite = "BARRA1"; width = 24; height = 63; + arrow = 1; + flags8text = "[8] Not pushable"; } 1217 { @@ -5392,6 +5859,7 @@ thingtypes sprite = "MCRTCLFR"; width = 22; height = 32; + arrow = 1; } 1220 { @@ -5399,6 +5867,7 @@ thingtypes sprite = "MCRTIR"; width = 32; height = 32; + arrow = 1; } 1221 { @@ -5406,6 +5875,7 @@ thingtypes sprite = "SALDARAL"; width = 96; height = 160; + arrow = 1; flags8text = "[8] Allow non-minecart players"; } 1222 @@ -5467,6 +5937,7 @@ thingtypes height = 40; flags8text = "[8] Waves vertically"; angletext = "On/Off time"; + fixedrotation = 1; parametertext = "Strength"; } 1301 @@ -5477,6 +5948,7 @@ thingtypes height = 40; flags8text = "[8] Shoot downwards"; angletext = "On/Off time"; + fixedrotation = 1; parametertext = "Strength"; } 1302 @@ -5500,6 +5972,8 @@ thingtypes width = 30; height = 32; angletext = "Initial delay"; + fixedrotation = 1; + hangs = 1; flags8text = "[8] Double size"; } 1305 @@ -5537,6 +6011,7 @@ thingtypes sprite = "WVINALAR"; width = 1; height = 288; + arrow = 1; } 1310 { @@ -5544,6 +6019,7 @@ thingtypes sprite = "WVINBLBR"; width = 1; height = 288; + arrow = 1; } } @@ -5887,10 +6363,10 @@ thingtypes } 1602 { - title = "Pian"; - sprite = "NTPNALAR"; + title = "Nightopian"; + sprite = "NTPNA1"; width = 16; - height = 32; + height = 40; } } @@ -5901,6 +6377,7 @@ thingtypes width = 8; height = 4096; sprite = "UNKNA0"; + fixedrotation = 1; 1700 { @@ -5959,6 +6436,7 @@ thingtypes flags4text = "[4] Align player to top"; flags8text = "[8] Die upon time up"; angletext = "Time limit"; + fixedrotation = 1; parametertext = "Height"; } 1704 @@ -5971,6 +6449,7 @@ thingtypes unflippable = true; flagsvaluetext = "Pitch"; angletext = "Yaw"; + fixedrotation = 1; } 1705 { @@ -5983,6 +6462,7 @@ thingtypes centerHitbox = true; flagsvaluetext = "Height"; angletext = "Pitch/Yaw"; + fixedrotation = 1; } 1706 { @@ -6104,6 +6584,7 @@ thingtypes width = 8; height = 16; angletext = "Jump strength"; + fixedrotation = 1; } 1806 { @@ -6336,6 +6817,7 @@ thingtypes width = 18; height = 28; angletext = "Initial delay"; + fixedrotation = 1; } 2001 { @@ -6459,9 +6941,24 @@ thingtypes sprite = "XMS6A0"; width = 52; height = 106; + hangs = 1; } } + tutorial + { + color = 10; // Green + title = "Tutorial"; + + 799 + { + title = "Tutorial Plant"; + sprite = "TUPFH0"; + width = 40; + height = 144; + parametertext = "Start frame"; + } + flickies { color = 10; // Green @@ -6472,6 +6969,7 @@ thingtypes flags4text = "[4] No movement"; flags8text = "[8] Hop"; angletext = "Radius"; + fixedrotation = 1; 2200 { diff --git a/extras/conf/udb/Includes/SRB222_common.cfg b/extras/conf/udb/Includes/SRB222_common.cfg index d67835aeb..0ff044a6d 100644 --- a/extras/conf/udb/Includes/SRB222_common.cfg +++ b/extras/conf/udb/Includes/SRB222_common.cfg @@ -191,6 +191,12 @@ mapformat_doom // that make the same thing appear in the same modes thingflagsmask1 = 7; // 1 + 2 + 4 thingflagsmask2 = 0; + + // THING TYPES + thingtypes + { + include("SRB222_things.cfg", "doom"); + } } mapformat_udmf @@ -240,17 +246,7 @@ mapformat_udmf include("SRB222_misc.cfg", "sectorbrightness"); } - // SECTOR TYPES - sectortypes - { - include("SRB222_sectors.cfg", "sectortypes"); - } - - // GENERALISED SECTOR TYPES - gen_sectortypes - { - include("SRB222_sectors.cfg", "gen_sectortypes"); - } + damagetypes = "Generic Water Fire Lava Electric Spike DeathPitTilt DeathPitNoTilt Instakill SpecialStage"; // LINEDEF FLAGS linedefflags @@ -264,10 +260,10 @@ mapformat_udmf } // LINEDEF RENDERSTYLES - /*linedefrenderstyles + linedefrenderstyles { include("SRB222_misc.cfg", "linedefrenderstyles"); - }*/ + } // THING FLAGS thingflags @@ -289,6 +285,12 @@ mapformat_udmf include("UDMF_misc.cfg", "thingflagscompare"); } + // THING TYPES + thingtypes + { + include("SRB222_things.cfg", "udmf"); + } + // LINEDEF TYPES linedeftypes { diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg index 1f87c2c3a..fff9edf10 100644 --- a/extras/conf/udb/Includes/SRB222_linedefs.cfg +++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg @@ -16,7 +16,7 @@ doom } 5 { - title = "Camera Scanner"; + title = "Camera Scanner "; prefix = "(5)"; } 7 @@ -125,10 +125,10 @@ doom title = "Continuously Appearing/Disappearing FOF"; prefix = "(64)"; } - 65 + 76 { - title = "Bridge Thinker "; - prefix = "(65)"; + title = "Make FOF Bouncy"; + prefix = "(76)"; } } @@ -397,7 +397,7 @@ doom } 160 { - title = "Floating, Bobbing"; + title = "Water Bobbing"; prefix = "(160)"; } 190 @@ -734,6 +734,51 @@ doom title = "Player Skin - Once"; prefix = "(333)"; } + 334 + { + title = "Object Dye - Continuous"; + prefix = "(334)"; + } + 335 + { + title = "Object Dye - Each Time"; + prefix = "(335)"; + } + 336 + { + title = "Object Dye - Once"; + prefix = "(336)"; + } + 337 + { + title = "Emerald Check - Continuous"; + prefix = "(337)"; + } + 338 + { + title = "Emerald Check - Each Time"; + prefix = "(338)"; + } + 339 + { + title = "Emerald Check - Once"; + prefix = "(339)"; + } + 340 + { + title = "NiGHTS Mare - Continuous"; + prefix = "(340)"; + } + 341 + { + title = "NiGHTS Mare - Each Time"; + prefix = "(341)"; + } + 342 + { + title = "NiGHTS Mare - Once"; + prefix = "(342)"; + } 399 { title = "Level Load"; @@ -757,9 +802,14 @@ doom } 402 { - title = "Set Tagged Sector's Light Level"; + title = "Copy Light Level to Tagged Sectors"; prefix = "(402)"; } + 408 + { + title = "Set Tagged Sector's Flats"; + prefix = "(408)"; + } 409 { title = "Change Tagged Sector's Tag"; @@ -805,6 +855,11 @@ doom title = "Change Plane Scroller Direction"; prefix = "(435)"; } + 467 + { + title = "Set Tagged Sector's Light Level"; + prefix = "(467)"; + } } linedefexecplane @@ -937,6 +992,21 @@ doom title = "Stop Timer/Exit Stage in Record Attack"; prefix = "(462)"; } + 463 + { + title = "Dye Object"; + prefix = "(463)"; + } + 464 + { + title = "Trigger Egg Capsule"; + prefix = "(464)"; + } + 466 + { + title = "Set Level Failure State"; + prefix = "(466)"; + } } linedefexecmisc @@ -1500,6 +1570,161 @@ doom title = "Fog Wall"; prefix = "(909)"; } + 910 + { + title = "100% Additive"; + prefix = "(910)"; + } + 911 + { + title = "90% Additive"; + prefix = "(911)"; + } + 912 + { + title = "80% Additive"; + prefix = "(912)"; + } + 913 + { + title = "70% Additive"; + prefix = "(913)"; + } + 914 + { + title = "60% Additive"; + prefix = "(914)"; + } + 915 + { + title = "50% Additive"; + prefix = "(915)"; + } + 916 + { + title = "40% Additive"; + prefix = "(916)"; + } + 917 + { + title = "30% Additive"; + prefix = "(917)"; + } + 918 + { + title = "20% Additive"; + prefix = "(918)"; + } + 919 + { + title = "10% Additive"; + prefix = "(919)"; + } + 920 + { + title = "100% Subtractive"; + prefix = "(920)"; + } + 921 + { + title = "90% Subtractive"; + prefix = "(921)"; + } + 922 + { + title = "80% Subtractive"; + prefix = "(922)"; + } + 923 + { + title = "70% Subtractive"; + prefix = "(923)"; + } + 924 + { + title = "60% Subtractive"; + prefix = "(924)"; + } + 925 + { + title = "50% Subtractive"; + prefix = "(925)"; + } + 926 + { + title = "40% Subtractive"; + prefix = "(926)"; + } + 927 + { + title = "30% Subtractive"; + prefix = "(927)"; + } + 928 + { + title = "20% Subtractive"; + prefix = "(928)"; + } + 929 + { + title = "10% Subtractive"; + prefix = "(929)"; + } + 930 + { + title = "100% Reverse Subtractive"; + prefix = "(930)"; + } + 931 + { + title = "90% Reverse Subtractive"; + prefix = "(931)"; + } + 932 + { + title = "80% Reverse Subtractive"; + prefix = "(932)"; + } + 933 + { + title = "70% Reverse Subtractive"; + prefix = "(933)"; + } + 934 + { + title = "60% Reverse Subtractive"; + prefix = "(934)"; + } + 935 + { + title = "50% Reverse Subtractive"; + prefix = "(935)"; + } + 936 + { + title = "40% Reverse Subtractive"; + prefix = "(936)"; + } + 937 + { + title = "30% Reverse Subtractive"; + prefix = "(937)"; + } + 938 + { + title = "20% Reverse Subtractive"; + prefix = "(938)"; + } + 939 + { + title = "10% Reverse Subtractive"; + prefix = "(939)"; + } + 940 + { + title = "Modulate"; + prefix = "(940)"; + } } } @@ -1514,6 +1739,248 @@ udmf title = "None"; prefix = "(0)"; } + + 7 + { + title = "Sector Flat Alignment"; + prefix = "(7)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + default = 2; + } + } + + 10 + { + title = "Culling Plane"; + prefix = "(10)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Culling behavior"; + type = 11; + enum + { + 0 = "Always"; + 1 = "Only while in sector"; + } + } + } + + 40 + { + title = "Visual Portal Between Tagged Linedefs"; + prefix = "(40)"; + } + + 41 + { + title = "Horizon Effect"; + prefix = "(41)"; + } + + 63 + { + title = "Fake Floor/Ceiling Planes"; + prefix = "(63)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + } + + parameters + { + title = "Parameters"; + + 2 + { + title = "Custom Exit"; + prefix = "(2)"; + arg0 + { + title = "Next map"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Skip score tally"; + 2 = "Check emeralds"; + } + } + arg2 + { + title = "Next map (all emeralds)"; + } + } + + 3 + { + title = "Zoom Tube Parameters"; + prefix = "(3)"; + arg0 + { + title = "Speed"; + } + arg1 + { + title = "Sequence"; + } + arg2 + { + title = "Check player direction?"; + type = 11; + enum = "yesno"; + } + } + + 4 + { + title = "Speed Pad Parameters"; + prefix = "(4)"; + arg0 + { + title = "Speed"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "No teleport to center"; + 2 = "Force spinning frames"; + } + } + stringarg0 + { + title = "Sound"; + type = 2; + } + } + + 8 + { + title = "Set Camera Collision Planes"; + prefix = "(8)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + + 11 + { + title = "Rope Hang Parameters"; + prefix = "(11)"; + arg0 + { + title = "Speed"; + } + arg1 + { + title = "Sequence"; + } + arg2 + { + title = "Loop?"; + type = 11; + enum = "yesno"; + } + } + + 14 + { + title = "Bustable Block Parameters"; + prefix = "(14)"; + arg0 + { + title = "Debris spacing"; + } + arg1 + { + title = "Debris lifetime"; + } + arg2 + { + title = "Launch from center?"; + type = 11; + enum = "noyes"; + } + stringarg0 + { + title = "Debris object type"; + type = 2; + } + } + + 15 + { + title = "Fan Particle Generator Heights"; + prefix = "(15)"; + } + + 16 + { + title = "Minecart Parameters"; + prefix = "(16)"; + arg0 + { + title = "Order"; + } + } + + 64 + { + title = "Continuously Appearing/Disappearing FOF"; + prefix = "(64)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Control sector tag"; + type = 13; + } + arg2 + { + title = "On time"; + } + arg3 + { + title = "Off time"; + } + arg4 + { + title = "Initial delay"; + } + arg5 + { + title = "Play sound?"; + type = 11; + enum = "yesno"; + } + } } polyobject @@ -1559,6 +2026,412 @@ udmf type = 15; } } + + 30 + { + title = "Waving Flag"; + prefix = "(30)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Distance"; + } + } + + 31 + { + title = "Displacement by Front Sector"; + prefix = "(31)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Base speed"; + } + } + + 32 + { + title = "Angular Displacement by Front Sector"; + prefix = "(32)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Plane factor"; + default = 128; + } + arg2 + { + title = "Rotation factor"; + default = 90; + } + arg3 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Don't turn others"; + 2 = "Turn players"; + } + } + } + } + + planemove + { + title = "Plane Movement"; + + 52 + { + title = "Continuously Falling Sector"; + prefix = "(52)"; + arg0 + { + title = "Speed"; + } + arg1 + { + title = "Direction"; + type = 11; + enum + { + 0 = "Fall"; + 1 = "Rise"; + } + } + } + + 53 + { + title = "Continuous Plane Mover (Slowdown)"; + prefix = "(53)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Forward speed"; + } + arg3 + { + title = "Return speed"; + } + arg4 + { + title = "Starting delay"; + } + arg5 + { + title = "Delay before flip"; + } + } + + 56 + { + title = "Continuous Plane Mover (Constant)"; + prefix = "(56)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Forward speed"; + } + arg3 + { + title = "Return speed"; + } + arg4 + { + title = "Starting delay"; + } + arg5 + { + title = "Delay before flip"; + } + } + + 60 + { + title = "Activate Moving Platform"; + prefix = "(60)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Starting delay"; + } + arg3 + { + title = "Delay before flip"; + } + arg4 + { + title = "Starting direction"; + type = 11; + enum = "downup"; + } + } + + 61 + { + title = "Ceiling Crusher"; + prefix = "(61)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Starting direction"; + type = 11; + enum + { + 0 = "Crush"; + 1 = "Retract"; + } + } + arg2 + { + title = "Crush speed"; + } + arg3 + { + title = "Retract speed"; + } + } + + 66 + { + title = "Move Planes by Displacement"; + prefix = "(66)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Translation factor"; + default = 256; + } + } + } + + fofmodifiers + { + title = "FOF Modifiers"; + + 70 + { + title = "Add Raise Thinker"; + prefix = "(70)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Destination height"; + } + arg3 + { + title = "Require spindash?"; + type = 11; + enum = "noyes"; + } + } + + 71 + { + title = "Add Air Bobbing Thinker"; + prefix = "(71)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Bobbing distance"; + } + arg2 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Raise"; + 2 = "Require spindash"; + 4 = "Dynamic"; + } + } + } + + 72 + { + title = "Add Thwomp Thinker"; + prefix = "(72)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Falling speed"; + } + arg2 + { + title = "Rising speed"; + } + stringarg0 + { + title = "Crushing sound"; + type = 2; + } + } + + 73 + { + title = "Add Laser Thinker"; + prefix = "(73)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Damage bosses?"; + type = 11; + enum = "yesno"; + } + } + + 74 + { + title = "Make FOF Bustable"; + prefix = "(74)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Bustable type"; + type = 11; + enum + { + 0 = "Touch"; + 1 = "Spin"; + 2 = "Regular"; + 3 = "Strong"; + } + } + arg2 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Bustable by pushables"; + 2 = "Trigger linedef executor"; + 4 = "Only bustable from below"; + } + } + arg3 + { + title = "Linedef executor tag"; + type = 15; + } + } + + 75 + { + title = "Make FOF Quicksand"; + prefix = "(75)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Sinking speed"; + } + arg2 + { + title = "Friction"; + } + } + + 76 + { + title = "Make FOF Bouncy"; + prefix = "(76)"; + arg0 + { + title = "Control linedef tag"; + type = 15; + } + arg1 + { + title = "Bounce strength"; + } + } } fof @@ -1576,37 +2449,35 @@ udmf } arg1 { - title = "Visibility"; + title = "Alpha"; + default = 255; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 + { + title = "Appearance"; type = 12; enum { 1 = "Don't render planes"; 2 = "Don't render sides"; + 4 = "Render insides"; + 8 = "Render only insides"; + 16 = "No shadow"; + 32 = "Cut cyan flat pixels"; } } - arg2 - { - title = "Translucency"; - type = 11; - enum - { - 0 = "Opaque"; - 1 = "Translucent, no insides"; - 2 = "Translucent, render insides"; - } - } - arg3 + arg4 { title = "Tangibility"; type = 12; enum = "tangibility"; } - arg4 - { - title = "Cast shadow?"; - type = 11; - enum = "yesno"; - } } 120 @@ -1619,17 +2490,1900 @@ udmf type = 13; } arg1 + { + title = "Alpha"; + default = 128; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 { title = "Flags"; type = 12; enum { - 1 = "Opaque"; + 1 = "Don't render sides"; + 2 = "Render separate light level"; + 4 = "Use target light level"; + 8 = "No ripple effect"; + 16 = "Goo physics"; + 32 = "Cut cyan flat pixels"; + } + } + } + + 150 + { + title = "Air Bobbing"; + prefix = "(150)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Bobbing distance"; + } + arg2 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Raise"; + 2 = "Require spindash"; + 4 = "Dynamic"; + } + } + } + + 160 + { + title = "Water Bobbing"; + prefix = "(160)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + + 170 + { + title = "Crumbling"; + prefix = "(170)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Alpha"; + default = 255; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 + { + title = "Tangibility"; + type = 12; + enum = "tangibility"; + } + arg4 + { + title = "Flags"; + type = 12; + enum + { + 1 = "No shadow"; + 2 = "No respawn"; + 4 = "Air bobbing"; + 8 = "Float on water"; + 16 = "Cut cyan flat pixels"; + } + } + } + + 190 + { + title = "Rising"; + prefix = "(190)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Alpha"; + default = 255; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 + { + title = "Appearance"; + type = 12; + enum + { + 1 = "Don't render planes"; 2 = "Don't render sides"; - 4 = "Render separate light level"; - 8 = "Use target light level"; - 16 = "No ripple effect"; - 32 = "Goo physics"; + 4 = "Render insides"; + 8 = "Render only insides"; + 16 = "No shadow"; + 32 = "Cut cyan flat pixels"; + } + } + arg4 + { + title = "Tangibility"; + type = 12; + enum = "tangibility"; + } + arg5 + { + title = "Speed"; + } + arg6 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Lower"; + 2 = "Require spindash"; + } + } + } + + 200 + { + title = "Light Block"; + prefix = "(200)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Expand to bottom?"; + type = 11; + enum = "noyes"; + } + } + + 202 + { + title = "Fog Block"; + prefix = "(202)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + + 220 + { + title = "Intangible"; + prefix = "(220)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Alpha"; + default = 255; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 + { + title = "Appearance"; + type = 12; + enum + { + 1 = "Don't render planes"; + 2 = "Don't render sides"; + 4 = "Don't render insides"; + 8 = "Render only insides"; + 16 = "No shadow"; + 32 = "Cut cyan flat pixels"; + } + } + } + + 223 + { + title = "Intangible, Invisible"; + prefix = "(223)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + + 250 + { + title = "Mario Block"; + prefix = "(250)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Block type"; + type = 12; + enum + { + 1 = "Brick"; + 2 = "Invisible"; + } + } + } + + 251 + { + title = "Thwomp Block"; + prefix = "(251)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Falling speed"; + } + arg2 + { + title = "Rising speed"; + } + stringarg0 + { + title = "Crushing sound"; + type = 2; + } + } + + 254 + { + title = "Bustable Block"; + prefix = "(254)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Alpha"; + default = 255; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 + { + title = "Bustable type"; + type = 11; + enum + { + 0 = "Touch"; + 1 = "Spin"; + 2 = "Regular"; + 3 = "Strong"; + } + } + arg4 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Bustable by pushables"; + 2 = "Trigger linedef executor"; + 4 = "Only bustable from below"; + 8 = "Cut cyan flat pixels"; + } + } + arg5 + { + title = "Linedef executor tag"; + type = 15; + } + } + + 257 + { + title = "Quicksand"; + prefix = "(257)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Ripple effect?"; + type = 11; + enum = "yesno"; + } + arg2 + { + title = "Sinking speed"; + } + arg3 + { + title = "Friction"; + } + } + + 258 + { + title = "Laser"; + prefix = "(258)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Alpha"; + default = 128; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Don't damage bosses"; + 2 = "Cut cyan flat pixels"; + } + } + } + + 259 + { + title = "Custom"; + prefix = "(259)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Alpha"; + default = 255; + } + arg2 + { + title = "Blending mode"; + type = 11; + enum = "blendmodes"; + } + arg3 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Exists"; + 2 = "Block player"; + 4 = "Block others"; + 8 = "Render sides"; + 16 = "Render planes"; + 32 = "Water"; + 64 = "No shadow"; + 128 = "Cut solid walls"; + 256 = "Cut extra walls"; + 512 = "Split sprites"; + 1024 = "Render inside planes"; + 2048 = "Extra"; + 8192 = "Fog"; + 16384 = "Only render inside planes"; + 32768 = "Render inside walls"; + 65536 = "Only render inside walls"; + 131072 = "Double shadow"; + 262144 = "Water bobbing"; + 524288 = "Don't respawn"; + 1048576 = "Crumbling"; + 2097152 = "Goo water"; + 4194304 = "Mario block"; + 33554432 = "Intangible from below"; + 67108864 = "Intangible from above"; + 134217728 = "Ripple effect"; + 268435456 = "Don't copy light level"; + 536870912 = "Bouncy"; + 1073741824 = "Cut cyan flat pixels"; + } + } + } + 260 + { + title = "Generalized 3D Floor"; + prefix = "(260)"; + id = "Sector_Set3dFloor"; + requiresactivation = false; + + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Type"; + type = 26; + default = 1; + enum + { + 1 = "Solid"; + 2 = "Water"; + 3 = "Intangible"; + } + flags + { + 4 = "Render insides"; + 16 = "Only render insides"; + } + } + arg2 + { + title = "Flags"; + type = 12; + enum + { + 1 = "No shadow"; + 2 = "Double shadow"; + 4 = "Fog"; + } + } + arg3 + { + title = "Alpha"; + default = 255; + } + } + } + + linedeftrigger + { + title = "Linedef Executor Trigger"; + + 300 + { + title = "Basic"; + prefix = "(300)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + } + + 303 + { + title = "Ring Count"; + prefix = "(303)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Rings"; + } + arg2 + { + title = "Comparison"; + type = 11; + enum = "comparison"; + } + arg3 + { + title = "Count all players?"; + type = 11; + enum = "noyes"; + } + } + + 305 + { + title = "Character Ability"; + prefix = "(305)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Ability"; + type = 11; + enum + { + 0 = "None"; + 1 = "Thok"; + 2 = "Fly"; + 3 = "Glide and climb"; + 4 = "Homing attack"; + 5 = "Swim"; + 6 = "Double jump"; + 7 = "Float"; + 8 = "Float with slow descent"; + 9 = "Telekinesis"; + 10 = "Fall switch"; + 11 = "Jump boost"; + 12 = "Air drill"; + 13 = "Jump-thok"; + 14 = "Pogo bounce"; + 15 = "Twin spin"; + } + } + } + + 308 + { + title = "Gametype"; + prefix = "(308)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Rules"; + type = 12; + enum + { + 1 = "Campaign"; + 2 = "Ringslinger"; + 4 = "Spectators"; + 8 = "Lives"; + 16 = "Teams"; + 32 = "First person"; + 64 = "Match emeralds"; + 128 = "Team flags"; + 256 = "Coop"; + 512 = "Allow special stages"; + 1024 = "Spawn emerald tokens"; + 2048 = "Emerald hunt"; + 4096 = "Race"; + 8192 = "Tag"; + 16384 = "Point limit"; + 32768 = "Time limit"; + 65536 = "Overtime"; + 131072 = "Hurt messages"; + 262144 = "Friendly fire"; + 524288 = "Hide time countdown"; + 1048576 = "Frozen after hide time"; + 2097152 = "Blindfolded view"; + 4194304 = "Respawn delay"; + 8388608 = "Award pity shield"; + 16777216 = "Death score penalty"; + 33554432 = "No spectator spawn"; + 67108864 = "Use match starts"; + 134217728 = "Spawn invincibility"; + 268435456 = "Allow enemies"; + 536870912 = "Allow exit sectors"; + 1073741824 = "No title card"; + 2147483648 = "Allow cutscenes"; + } + } + arg2 + { + title = "Check if"; + type = 11; + enum = "flagcheck"; + } + } + + 309 + { + title = "CTF Team"; + prefix = "(309)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Team"; + type = 11; + enum = "team"; + } + } + + 313 + { + title = "No More Enemies"; + prefix = "(313)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + + 314 + { + title = "Number of Pushables"; + prefix = "(314)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Pushables"; + } + arg2 + { + title = "Comparison"; + type = 11; + enum = "comparison"; + } + } + + 317 + { + title = "Condition Set Trigger"; + prefix = "(317)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Trigger ID"; + } + } + + 319 + { + title = "Unlockable"; + prefix = "(319)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Unlockable ID"; + } + } + + 321 + { + title = "Trigger After X Calls"; + prefix = "(321)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "xtriggertype"; + } + arg1 + { + title = "Calls"; + } + arg2 + { + title = "Can retrigger?"; + type = 11; + enum = "noyes"; + } + arg3 + { + title = "Starting calls"; + } + } + + 323 + { + title = "NiGHTSerize"; + prefix = "(323)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum + { + 0 = "Each time"; + 1 = "Once"; + } + } + arg1 + { + title = "Mare number"; + } + arg2 + { + title = "Lap number"; + } + arg3 + { + title = "Mare comparison"; + type = 11; + enum = "comparison"; + } + arg4 + { + title = "Lap comparison"; + type = 11; + enum = "comparison"; + } + arg5 + { + title = "Compared player"; + type = 11; + enum + { + 0 = "Fastest"; + 1 = "Slowest"; + 2 = "Triggerer"; + } + } + arg6 + { + title = "NiGHTS check"; + type = 11; + enum + { + 0 = "No check"; + 1 = "Trigger if player was not NiGHTS"; + 2 = "Trigger if player was already NiGHTS"; + } + } + arg7 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Only count bonus time laps"; + 2 = "Only trigger if final mare completed"; + } + } + } + 325 + { + title = "De-NiGHTSerize"; + prefix = "(325)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum + { + 0 = "Each time"; + 1 = "Once"; + } + } + arg1 + { + title = "Mare number"; + } + arg2 + { + title = "Lap number"; + } + arg3 + { + title = "Mare comparison"; + type = 11; + enum = "comparison"; + } + arg4 + { + title = "Lap comparison"; + type = 11; + enum = "comparison"; + } + arg5 + { + title = "Compared player"; + type = 11; + enum + { + 0 = "Fastest"; + 1 = "Slowest"; + 2 = "Triggerer"; + } + } + arg6 + { + title = "NiGHTS check"; + type = 11; + enum + { + 0 = "No check"; + 1 = "Trigger if nobody is now NiGHTS"; + 2 = "Trigger if somebody is still NiGHTS"; + } + } + arg7 + { + title = "Only bonus laps?"; + type = 11; + enum = "noyes"; + } + } + 327 + { + title = "NiGHTS Lap"; + prefix = "(327)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum + { + 0 = "Each time"; + 1 = "Once"; + } + } + arg1 + { + title = "Mare number"; + } + arg2 + { + title = "Lap number"; + } + arg3 + { + title = "Mare comparison"; + type = 11; + enum = "comparison"; + } + arg4 + { + title = "Lap comparison"; + type = 11; + enum = "comparison"; + } + arg5 + { + title = "Compared player"; + type = 11; + enum + { + 0 = "Fastest"; + 1 = "Slowest"; + 2 = "Triggerer"; + } + } + arg6 + { + title = "Only bonus laps?"; + type = 11; + enum = "noyes"; + } + } + 329 + { + title = "Ideya Capture Touch"; + prefix = "(329)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum + { + 0 = "Each time"; + 1 = "Once"; + } + } + arg1 + { + title = "Mare number"; + } + arg2 + { + title = "Lap number"; + } + arg3 + { + title = "Mare comparison"; + type = 11; + enum = "comparison"; + } + arg4 + { + title = "Lap comparison"; + type = 11; + enum = "comparison"; + } + arg5 + { + title = "Compared player"; + type = 11; + enum + { + 0 = "Fastest"; + 1 = "Slowest"; + 2 = "Triggerer"; + } + } + arg6 + { + title = "Spheres check"; + type = 11; + enum + { + 0 = "Trigger if enough spheres"; + 1 = "Trigger if not enough spheres"; + 2 = "Trigger regardless of spheres"; + } + } + arg7 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Only count bonus time laps"; + 2 = "Trigger upon entering Ideya Capture"; + } + } + } + + 331 + { + title = "Player Skin"; + prefix = "(331)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Invert choice?"; + type = 11; + enum = "noyes"; + } + stringarg0 + { + title = "Skin name"; + type = 2; + } + } + + 334 + { + title = "Object Dye"; + prefix = "(334)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Invert choice?"; + type = 11; + enum = "noyes"; + } + stringarg0 + { + title = "Color"; + type = 2; + } + } + + 337 + { + title = "Emerald Check"; + prefix = "(337)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Emeralds"; + type = 12; + enum + { + 1 = "Emerald 1"; + 2 = "Emerald 2"; + 4 = "Emerald 3"; + 8 = "Emerald 4"; + 16 = "Emerald 5"; + 32 = "Emerald 6"; + 64 = "Emerald 7"; + } + } + arg2 + { + title = "Check if"; + type = 11; + enum = "flagcheck"; + } + } + + 340 + { + title = "NiGHTS Mare"; + prefix = "(340)"; + arg0 + { + title = "Trigger type"; + type = 11; + enum = "triggertype"; + } + arg1 + { + title = "Mare"; + } + arg2 + { + title = "Comparison"; + type = 11; + enum = "comparison"; + } + } + + 399 + { + title = "Level Load"; + prefix = "(399)"; + } + } + + linedefexecsector + { + title = "Linedef Executor (sector)"; + + 400 + { + title = "Set Tagged Sector's Heights/Textures"; + prefix = "(400)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Set flats?"; + type = 11; + enum = "noyes"; + } + } + + 402 + { + title = "Copy Light Level to Tagged Sectors"; + prefix = "(402)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Don't copy main light level"; + 2 = "Don't copy floor light level"; + 4 = "Don't copy ceiling light level"; + } + } + } + + 408 + { + title = "Set Tagged Sector's Flats"; + prefix = "(408)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + } + + 409 + { + title = "Change Tagged Sector's Tag"; + prefix = "(409)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Tag"; + type = 13; + } + arg2 + { + title = "Behavior"; + type = 11; + enum + { + 0 = "Add tag"; + 1 = "Remove tag"; + 2 = "Replace first tag"; + 3 = "Change trigger tag"; + } + } + } + + 410 + { + title = "Change Front Sector's Tag"; + prefix = "(410)"; + arg0 + { + title = "Tag"; + type = 13; + } + arg1 + { + title = "Behavior"; + type = 11; + enum + { + 0 = "Add tag"; + 1 = "Remove tag"; + 2 = "Replace first tag"; + 3 = "Change trigger tag"; + } + } + } + + 416 + { + title = "Start Adjustable Flickering Light"; + prefix = "(416)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Brightness 1"; + } + arg3 + { + title = "Use target brightness?"; + type = 11; + enum = "noyes"; + } + arg4 + { + title = "Brightness 2"; + } + } + + 417 + { + title = "Start Adjustable Pulsating Light"; + prefix = "(417)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Brightness 1"; + } + arg3 + { + title = "Use target brightness?"; + type = 11; + enum = "noyes"; + } + arg4 + { + title = "Brightness 2"; + } + } + + 418 + { + title = "Start Adjustable Blinking Light"; + prefix = "(418)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Brightness 1 tics"; + } + arg2 + { + title = "Brightness 2 tics"; + } + arg3 + { + title = "Brightness 1"; + } + arg4 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Use target brightness"; + 2 = "Synchronized"; + } + } + arg5 + { + title = "Brightness 2"; + } + } + + 420 + { + title = "Fade Light Level"; + prefix = "(420)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Destination light level"; + } + arg2 + { + title = "Fading speed"; + } + arg3 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Add to current light level"; + 2 = "Interrupt ongoing fades"; + 4 = "Speed is duration"; + } + } + } + + 421 + { + title = "Stop Lighting Effect"; + prefix = "(421)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + + 435 + { + title = "Change Plane Scroller Direction"; + prefix = "(435)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Speed"; + } + } + + 467 + { + title = "Set Tagged Sector's Light Level"; + prefix = "(467)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Light level"; + } + arg2 + { + title = "Affected area"; + type = 11; + enum + { + 0 = "Sector"; + 1 = "Floor"; + 2 = "Ceiling"; + } + } + arg3 + { + title = "Set/Add?"; + type = 11; + enum = "setadd"; + } + } + + 469 + { + title = "Change Tagged Sector's Gravity"; + prefix = "(469)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Set/Multiply?"; + type = 11; + enum + { + 0 = "Set"; + 1 = "Multiply"; + } + } + arg2 + { + title = "Flip flag"; + type = 11; + enum + { + 0 = "Don't change"; + 1 = "Set"; + 2 = "Remove"; + } + } + stringarg0 + { + title = "Gravity value"; + type = 2; + } + } + } + + linedefexecplane + { + title = "Linedef Executor (plane movement)"; + + 403 + { + title = "Move Tagged Sector's Planes"; + prefix = "(403)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Speed"; + } + arg3 + { + title = "Linedef executor tag"; + type = 15; + } + arg4 + { + title = "Set flats?"; + type = 11; + enum = "noyes"; + } + } + + 405 + { + title = "Move Planes by Distance"; + prefix = "(405)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Distance"; + } + arg3 + { + title = "Speed"; + } + arg4 + { + title = "Instant?"; + type = 11; + enum = "noyes"; + } + } + + 411 + { + title = "Stop Plane Movement"; + prefix = "(411)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + } + + 428 + { + title = "Start Platform Movement"; + prefix = "(428)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Starting delay"; + } + arg3 + { + title = "Delay before flip"; + } + arg4 + { + title = "Starting direction"; + type = 11; + enum + { + 0 = "Down"; + 1 = "Up"; + } + } + } + + 429 + { + title = "Crush Planes Once"; + prefix = "(429)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Crush speed"; + } + arg3 + { + title = "Retract speed"; + } + } + } + + linedefexecplayer + { + title = "Linedef Executor (player/object)"; + + 412 + { + title = "Teleporter"; + prefix = "(412)"; + arg0 + { + title = "Destination tag"; + type = 14; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Silent"; + 2 = "Keep angle"; + 4 = "Keep momentum"; + 8 = "Relative silent"; + } + } + arg2 + { + title = "X offset"; + } + arg3 + { + title = "Y offset"; + } + arg4 + { + title = "Z offset"; + } + } + + 425 + { + title = "Change Object State"; + prefix = "(425)"; + stringarg0 + { + title = "State"; + type = 2; + } + } + + 426 + { + title = "Stop Object"; + prefix = "(426)"; + arg0 + { + title = "Move to center?"; + type = 11; + enum = "noyes"; + } + } + + 427 + { + title = "Award Score"; + prefix = "(427)"; + arg0 + { + title = "Score"; + } + } + + 432 + { + title = "Enable/Disable 2D Mode"; + prefix = "(432)"; + arg0 + { + title = "Mode"; + type = 11; + enum + { + 0 = "2D"; + 1 = "3D"; + } + } + } + + 433 + { + title = "Enable/Disable Gravity Flip"; + prefix = "(433)"; + arg0 + { + title = "Gravity"; + type = 11; + enum + { + 0 = "Reverse"; + 1 = "Normal"; + } + } + } + + 434 + { + title = "Award Power-Up"; + prefix = "(434)"; + stringarg0 + { + title = "Power"; + type = 2; + } + stringarg1 + { + title = "Duration/Amount"; + type = 2; + } + } + + 437 + { + title = "Disable Player Control"; + prefix = "(437)"; + arg0 + { + title = "Time"; + } + arg1 + { + title = "Allow jumping?"; + type = 11; + enum = "noyes"; + } + } + + 438 + { + title = "Change Object Size"; + prefix = "(438)"; + arg0 + { + title = "Size (%)"; + default = 100; + } + } + + 442 + { + title = "Change Object Type State"; + prefix = "(442)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Change to"; + type = 11; + enum + { + 0 = "Specified state"; + 1 = "Next state"; + } + } + stringarg0 + { + title = "Object type"; + type = 2; + } + stringarg1 + { + title = "State"; + type = 2; + } + } + + 457 + { + title = "Track Object's Angle"; + prefix = "(457)"; + arg0 + { + title = "Anchor tag"; + type = 14; + } + arg1 + { + title = "Angle tolerance"; + type = 8; + } + arg2 + { + title = "Time tolerance"; + } + arg3 + { + title = "Trigger linedef tag"; + type = 15; + } + arg4 + { + title = "Track after failure?"; + type = 11; + enum = "noyes"; + } + } + + 458 + { + title = "Stop Tracking Object's Angle"; + prefix = "(458)"; + } + + 460 + { + title = "Award Rings"; + prefix = "(460)"; + arg0 + { + title = "Rings"; + } + arg1 + { + title = "Periodicity"; + } + } + + 461 + { + title = "Spawn Object"; + prefix = "(461)"; + arg0 + { + title = "X position"; + } + arg1 + { + title = "Y position"; + } + arg2 + { + title = "Z position"; + } + arg3 + { + title = "Angle"; + type = 8; + } + arg4 + { + title = "Randomize position?"; + type = 11; + enum = "noyes"; + } + arg5 + { + title = "Max X position"; + } + arg6 + { + title = "Max Y position"; + } + arg7 + { + title = "Max Z position"; + } + stringarg0 + { + title = "Object type"; + type = 2; + } + } + + 462 + { + title = "Stop Timer/Exit Stage in Record Attack"; + prefix = "(462)"; + } + + 463 + { + title = "Dye Object"; + prefix = "(463)"; + stringarg0 + { + title = "Skin color"; + type = 2; + } + } + + 464 + { + title = "Trigger Egg Capsule"; + prefix = "(464)"; + arg0 + { + title = "Egg Capsule tag"; + type = 14; + } + arg1 + { + title = "End level?"; + type = 11; + enum = "yesno"; + } + } + + 466 + { + title = "Set Level Failure State"; + prefix = "(466)"; + arg0 + { + title = "State"; + type = 11; + enum + { + 0 = "Failure"; + 1 = "Success"; } } } @@ -1639,6 +4393,219 @@ udmf { title = "Linedef Executor (misc.)"; + 413 + { + title = "Change Music"; + prefix = "(413)"; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "For all players"; + 2 = "Seek offset from current position"; + 4 = "Fade to custom volume"; + 8 = "Don't reload after death"; + 16 = "Force music reload"; + 32 = "Don't loop"; + } + } + arg1 + { + title = "Position"; + } + arg2 + { + title = "Fade out time"; + } + arg3 + { + title = "Fade in time"; + } + arg4 + { + title = "Fade destination volume"; + } + arg5 + { + title = "Fade start volume"; + default = -1; + } + arg6 + { + title = "Track number"; + } + stringarg0 + { + title = "Music name"; + type = 2; + } + } + + 414 + { + title = "Play Sound Effect"; + prefix = "(414)"; + arg0 + { + title = "Source"; + type = 11; + enum + { + 0 = "Triggering object"; + 1 = "Trigger sector"; + 2 = "Nowhere"; + 3 = "Tagged sectors"; + } + } + arg1 + { + title = "Listener"; + type = 11; + enum + { + 0 = "Triggering player"; + 1 = "Everyone"; + 2 = "Everyone touching tagged sectors"; + } + } + arg2 + { + title = "Target sector tag"; + type = 13; + } + stringarg0 + { + title = "Sound name"; + type = 2; + } + } + + 415 + { + title = "Run Script"; + prefix = "(415)"; + stringarg0 + { + title = "Lump name"; + type = 2; + } + } + + 422 + { + title = "Switch to Cut-Away View"; + prefix = "(422)"; + arg0 + { + title = "Viewpoint tag"; + type = 14; + } + arg1 + { + title = "Time"; + } + } + + 423 + { + title = "Change Sky"; + prefix = "(423)"; + arg0 + { + title = "Sky number"; + } + arg1 + { + title = "For all players?"; + type = 11; + enum = "noyes"; + } + } + + 424 + { + title = "Change Weather"; + prefix = "(424)"; + arg0 + { + title = "Weather"; + type = 11; + enum + { + 0 = "None"; + 1 = "Storm (thunder, lightning and rain)"; + 2 = "Snow"; + 3 = "Rain"; + 4 = "Preloaded"; + 5 = "Storm (no rain)"; + 6 = "Storm (no lightning)"; + } + } + arg1 + { + title = "For all players?"; + type = 11; + enum = "noyes"; + } + } + + 436 + { + title = "Shatter FOF"; + prefix = "(436)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Control sector tag"; + type = 13; + } + } + + 439 + { + title = "Change Tagged Linedef's Textures"; + prefix = "(439)"; + arg0 + { + title = "Target linedef tag"; + type = 15; + } + arg1 + { + title = "Affected sides"; + type = 11; + enum = "frontbackboth"; + } + arg2 + { + title = "Change unset textures?"; + type = 11; + enum = "yesno"; + } + } + + 440 + { + title = "Start Metal Sonic Race"; + prefix = "(440)"; + } + + 441 + { + title = "Condition Set Trigger"; + prefix = "(441)"; + arg0 + { + title = "Trigger number"; + } + } + 443 { title = "Call Lua Function"; @@ -1650,6 +4617,74 @@ udmf } } + 444 + { + title = "Earthquake"; + prefix = "(444)"; + arg0 + { + title = "Duration"; + } + arg1 + { + title = "Intensity"; + } + } + + 445 + { + title = "Make FOF Disappear/Reappear"; + prefix = "(445)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Control sector tag"; + type = 13; + } + arg2 + { + title = "Effect"; + type = 11; + enum + { + 0 = "Disappear"; + 1 = "Reappear"; + } + } + } + + 446 + { + title = "Make FOF Crumble"; + prefix = "(446)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Control sector tag"; + type = 13; + } + arg2 + { + title = "Respawn?"; + type = 11; + enum + { + 0 = "Yes"; + 1 = "No"; + 2 = "Unless FF_NORETURN"; + 3 = "Only if FF_NORETURN"; + } + } + } + 447 { title = "Change Tagged Sector's Colormap"; @@ -1686,6 +4721,178 @@ udmf } } + 448 + { + title = "Change Skybox"; + prefix = "(448)"; + arg0 + { + title = "Viewpoint ID"; + } + arg1 + { + title = "Centerpoint ID"; + } + arg2 + { + title = "Change?"; + type = 11; + enum + { + 0 = "Viewpoint"; + 1 = "Centerpoint"; + 2 = "Both"; + } + } + arg3 + { + title = "For all players?"; + type = 11; + enum = "noyes"; + } + } + + 449 + { + title = "Enable Bosses with Parameter"; + prefix = "(449)"; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "Effect"; + type = 11; + enum + { + 0 = "Enable"; + 1 = "Disable"; + } + } + } + + 450 + { + title = "Execute Linedef Executor (specific tag)"; + prefix = "(450)"; + arg0 + { + title = "Trigger linedef tag"; + type = 15; + } + } + + 451 + { + title = "Execute Linedef Executor (random tag in range)"; + prefix = "(451)"; + arg0 + { + title = "Start of tag range"; + type = 15; + } + arg1 + { + title = "End of tag range"; + type = 15; + } + } + + 452 + { + title = "Set FOF Translucency"; + prefix = "(452)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Control sector tag"; + type = 13; + } + arg2 + { + title = "Alpha"; + } + arg3 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Add to current translucency"; + 2 = "Don't handle FF_TRANSLUCENT"; + } + } + } + + 453 + { + title = "Fade FOF"; + prefix = "(453)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Control sector tag"; + type = 13; + } + arg2 + { + title = "Alpha"; + } + arg3 + { + title = "Fading speed"; + } + arg4 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Add to current translucency"; + 2 = "Interrupt ongoing fades"; + 4 = "Speed is duration"; + 8 = "Don't change collision"; + 16 = "No collision during fade"; + 32 = "Don't handle FF_TRANSLUCENT"; + 64 = "Don't handle FF_EXISTS"; + 128 = "Don't fade lighting"; + 256 = "Don't fade colormap"; + 512 = "Use exact alpha in OpenGL"; + } + } + } + + 454 + { + title = "Stop Fading FOF"; + prefix = "(454)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Control sector tag"; + type = 13; + } + arg2 + { + title = "Finalize collision?"; + type = 11; + enum = "yesno"; + } + } + 455 { title = "Fade Tagged Sector's Colormap"; @@ -1739,6 +4946,42 @@ udmf } } + 459 + { + title = "Control Text Prompt"; + prefix = "(459)"; + arg0 + { + title = "Prompt number"; + } + arg1 + { + title = "Page number"; + } + arg2 + { + title = "Flags"; + type = 11; + enum + { + 1 = "Close current text prompt"; + 2 = "Trigger linedef executor on close"; + 4 = "Find prompt by name"; + 8 = "Don't disable controls"; + } + } + arg3 + { + title = "Trigger linedef tag"; + type = 15; + } + stringarg0 + { + title = "Prompt name"; + type = 2; + } + } + 465 { title = "Set Linedef Executor Delay"; @@ -1754,12 +4997,400 @@ udmf } arg2 { - title = "Set/add?"; + title = "Set/Add?"; + type = 11; + enum = "setadd"; + } + } + + 468 + { + title = "Change Linedef Argument"; + prefix = "(468)"; + arg0 + { + title = "Linedef tag"; + type = 15; + } + arg1 + { + title = "Argument"; + } + arg2 + { + title = "Value"; + } + arg3 + { + title = "Set/Add?"; + type = 11; + enum = "setadd"; + } + } + } + + linedefexecpoly + { + title = "Linedef Executor (polyobject)"; + + 480 + { + title = "Door Slide"; + prefix = "(480)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Distance"; + } + arg3 + { + title = "Return delay"; + } + } + + 481 + { + title = "Door Swing"; + prefix = "(481)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Rotation"; + type = 8; + } + arg3 + { + title = "Return delay"; + } + } + + 482 + { + title = "Move"; + prefix = "(482)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Distance"; + } + arg3 + { + title = "Override?"; + type = 11; + enum = "noyes"; + } + } + + 484 + { + title = "Rotate"; + prefix = "(484)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Rotation"; + type = 8; + } + arg3 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Don't turn others"; + 2 = "Turn players"; + 4 = "Continuous rotation"; + 8 = "Override"; + } + } + } + + 488 + { + title = "Move by Waypoints"; + prefix = "(488)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Waypoint sequence"; + } + arg3 + { + title = "Return behavior"; type = 11; enum { - 0 = "Set"; - 1 = "Add"; + 0 = "Don't return"; + 1 = "Return to first waypoint"; + 2 = "Repeat sequence in reverse"; + } + } + arg4 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move in reverse"; + 2 = "Loop movement"; + } + } + } + + 489 + { + title = "Set Visibility, Tangibility"; + prefix = "(489)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Visibility"; + type = 11; + enum + { + 0 = "No change"; + 1 = "Visible"; + 2 = "Invisible"; + } + } + arg2 + { + title = "Tangibility"; + type = 11; + enum + { + 0 = "No change"; + 1 = "Tangible"; + 2 = "Intangible"; + } + } + } + + 491 + { + title = "Set Translucency"; + prefix = "(491)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Translucency level"; + } + arg2 + { + title = "Set/Add?"; + type = 11; + enum = "setadd"; + } + } + + 492 + { + title = "Fade Translucency"; + prefix = "(492)"; + arg0 + { + title = "PolyObject ID"; + type = 14; + } + arg1 + { + title = "Translucency level"; + } + arg2 + { + title = "Fading speed"; + } + arg3 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Add to current translucency"; + 2 = "Interrupt ongoing fades"; + 4 = "Speed is duration"; + 8 = "Don't change collision"; + 16 = "No collision during fade"; + } + } + } + } + + scrollpush + { + title = "Scrollers and Pushers"; + + 500 + { + title = "Scroll Walls"; + prefix = "(500)"; + arg0 + { + title = "Side"; + type = 11; + enum = "frontbackboth"; + } + arg1 + { + title = "Horizontal speed"; + } + arg2 + { + title = "Vertical speed"; + } + } + + 502 + { + title = "Scroll Walls Remotely"; + prefix = "(502)"; + arg0 + { + title = "Linedef tag"; + type = 15; + } + arg1 + { + title = "Side"; + type = 11; + enum = "frontbackboth"; + } + arg2 + { + title = "Horizontal speed"; + } + arg3 + { + title = "Vertical speed"; + } + arg4 + { + title = "Type"; + type = 11; + enum = "scrolltype"; + } + } + + 510 + { + title = "Scroll Planes"; + prefix = "(510)"; + arg0 + { + title = "Sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + arg2 + { + title = "Scroll/Carry?"; + type = 11; + enum = "scrollcarry"; + } + arg3 + { + title = "Base speed"; + } + arg4 + { + title = "Type"; + type = 26; + enum = "scrolltype"; + flags + { + 4 = "Non-exclusive"; + } + } + } + + 541 + { + title = "Wind/Current"; + prefix = "(541)"; + arg0 + { + title = "Sector tag"; + type = 13; + } + arg1 + { + title = "Horizontal speed"; + } + arg2 + { + title = "Vertical speed"; + } + arg3 + { + title = "Type"; + type = 11; + enum + { + 0 = "Wind"; + 1 = "Current"; + } + } + arg4 + { + title = "Flags"; + type = 12; + flags + { + 1 = "Slide"; + 2 = "Non-exclusive"; } } } @@ -1767,6 +5398,120 @@ udmf light { + title = "Lighting"; + + 600 + { + title = "Copy Light Level to Tagged Sector's Planes"; + prefix = "(600)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Affected planes"; + type = 11; + enum = "floorceiling"; + } + } + + 602 + { + title = "Adjustable Pulsating Light"; + prefix = "(602)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Brightness 1"; + } + arg3 + { + title = "Use target brightness?"; + type = 11; + enum = "noyes"; + } + arg4 + { + title = "Brightness 2"; + } + } + + 603 + { + title = "Adjustable Flickering Light"; + prefix = "(603)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Speed"; + } + arg2 + { + title = "Brightness 1"; + } + arg3 + { + title = "Use target brightness?"; + type = 11; + enum = "noyes"; + } + arg4 + { + title = "Brightness 2"; + } + } + + 604 + { + title = "Adjustable Blinking Light"; + prefix = "(604)"; + arg0 + { + title = "Target sector tag"; + type = 13; + } + arg1 + { + title = "Brightness 1 tics"; + } + arg2 + { + title = "Brightness 2 tics"; + } + arg3 + { + title = "Brightness 1"; + } + arg4 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Use target brightness"; + 2 = "Synchronized"; + } + } + arg5 + { + title = "Brightness 2"; + } + } + 606 { title = "Copy Colormap"; @@ -1813,6 +5558,7 @@ udmf { 1 = "No physics"; 2 = "Dynamic"; + 4 = "Copy to other side"; } } } @@ -1897,5 +5643,21 @@ udmf } } } + + 799 + { + title = "Set Tagged Dynamic Slope Vertex to Front Sector Height"; + prefix = "(799)"; + arg0 + { + title = "Apply height"; + type = 11; + enum + { + 0 = "Absolute"; + 1 = "Relative"; + } + } + } } -} \ No newline at end of file +} diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg index 68629149e..fcc24741e 100644 --- a/extras/conf/udb/Includes/SRB222_misc.cfg +++ b/extras/conf/udb/Includes/SRB222_misc.cfg @@ -58,22 +58,52 @@ linedefflags_udmf wrapmidtex = "Repeat Midtexture"; netonly = "Netgame Only"; nonet = "No Netgame"; - effect6 = "Effect 6"; bouncy = "Bouncy Wall"; transfer = "Transfer Line"; } -/*linedefrenderstyles +linedefrenderstyles { translucent = "Translucent"; + add = "Add"; + subtract = "Subtract"; + reversesubtract = "Reverse subtract"; + modulate = "Modulate"; fog = "Fog"; -}*/ +} sectorflags { colormapfog = "Fog Planes in Colormap"; colormapfadesprites = "Fade Fullbright in Colormap"; colormapprotected = "Protected Colormap"; + flipspecial_nofloor = "No Trigger on Floor Touch"; + flipspecial_ceiling = "Trigger on Ceiling Touch"; + triggerspecial_touch = "Trigger on Edge Touch"; + triggerspecial_headbump = "Trigger on Headbump"; + triggerline_plane = "Linedef Trigger Requires Plane Touch"; + triggerline_mobj = "Non-Pushables Can Trigger Linedef"; + invertprecip = "Invert Precipitation"; + gravityflip = "Flip Objects in Reverse Gravity"; + heatwave = "Heat Wave"; + noclipcamera = "Intangible to the Camera"; + outerspace = "Space Countdown"; + doublestepup = "Ramp Sector (double step-up/down)"; + nostepdown = "Non-Ramp Sector (No step-down)"; + speedpad = "Speed Pad"; + starpostactivator = "Star Post Activator"; + exit = "Exit"; + specialstagepit = "Special Stage Pit"; + returnflag = "Return Flag"; + redteambase = "Red Team Base"; + blueteambase = "Blue Team Base"; + fan = "Fan Sector"; + supertransform = "Super Sonic Transform"; + forcespin = "Force Spin"; + zoomtubestart = "Zoom Tube Start"; + zoomtubeend = "Zoom Tube End"; + finishline = "Circuit Finish Line"; + ropehang = "Rope Hang"; } thingflags @@ -87,10 +117,7 @@ thingflags // THING FLAGS thingflags_udmf { - extra = "Extra"; flip = "Flip"; - special = "Special"; - ambush = "Ambush"; } @@ -223,6 +250,30 @@ universalfields type = 3; default = false; } + + friction + { + type = 1; + default = 0.90625; + } + + triggertag + { + type = 15; + default = 0; + } + + triggerer + { + type = 0; + default = 0; + enum + { + 0 = "Player"; + 1 = "All players"; + 2 = "Object"; + } + } } linedef @@ -232,6 +283,26 @@ universalfields type = 0; default = 0; } + arg6 + { + type = 0; + default = 0; + } + arg7 + { + type = 0; + default = 0; + } + arg8 + { + type = 0; + default = 0; + } + arg9 + { + type = 0; + default = 0; + } stringarg0 { type = 2; @@ -260,6 +331,41 @@ universalfields thing { + arg5 + { + type = 0; + default = 0; + } + arg6 + { + type = 0; + default = 0; + } + arg7 + { + type = 0; + default = 0; + } + arg8 + { + type = 0; + default = 0; + } + arg9 + { + type = 0; + default = 0; + } + stringarg0 + { + type = 2; + default = ""; + } + stringarg1 + { + type = 2; + default = ""; + } } } @@ -406,6 +512,12 @@ enums 1 = "Yes"; } + setadd + { + 0 = "Set"; + 1 = "Add"; + } + onoff { 0 = "On"; @@ -437,6 +549,13 @@ enums 2 = "Back"; } + frontbackboth + { + 0 = "Front"; + 1 = "Back"; + 2 = "Front and back"; + } + tangibility { 1 = "Intangible from top"; @@ -444,6 +563,100 @@ enums 4 = "Don't block players"; 8 = "Don't block non-players"; } + + floorceiling + { + 0 = "Floor"; + 1 = "Ceiling"; + 2 = "Both"; + } + + scrollcarry + { + 0 = "Scroll and carry"; + 1 = "Scroll"; + 2 = "Carry"; + } + + scrolltype + { + 0 = "Regular"; + 1 = "Accelerative"; + 2 = "Displacement"; + } + + comparison + { + 0 = "Equal"; + 1 = "Less than or equal"; + 2 = "Greater than or equal"; + } + + triggertype + { + 0 = "Continuous"; + 1 = "Once"; + 2 = "Each time on entry"; + 3 = "Each time on entry/exit"; + } + + xtriggertype + { + 0 = "Continuous"; + 1 = "Each time on entry"; + 2 = "Each time on entry/exit"; + } + + team + { + 0 = "Red"; + 1 = "Blue"; + } + + flagcheck + { + 0 = "Has all"; + 1 = "Has any"; + 2 = "Has exactly"; + 3 = "Doesn't have all"; + 4 = "Doesn't have any"; + } + + maceflags + { + 1 = "Double size"; + 2 = "No sounds"; + 4 = "Player-turnable chain"; + 8 = "Swing instead of spin"; + 16 = "Make chain from end item"; + 32 = "Spawn link at origin"; + 64 = "Clip inside ground"; + 128 = "No distance check"; + } + + pushablebehavior + { + 0 = "Normal"; + 1 = "Slide"; + 2 = "Immovable"; + 3 = "Classic"; + } + + monitorrespawn + { + 0 = "Same item"; + 1 = "Random (Weak)"; + 2 = "Random (Strong)"; + } + + blendmodes + { + 0 = "Translucent"; + 1 = "Add"; + 2 = "Subtract"; + 3 = "Reverse subtract"; + 4 = "Modulate"; + } } //Default things filters @@ -622,4 +835,4 @@ flats start = "F_START"; end = "FF_END"; } -} \ No newline at end of file +} diff --git a/extras/conf/udb/Includes/SRB222_sectors.cfg b/extras/conf/udb/Includes/SRB222_sectors.cfg index 5cc14ad0f..f9df297e7 100644 --- a/extras/conf/udb/Includes/SRB222_sectors.cfg +++ b/extras/conf/udb/Includes/SRB222_sectors.cfg @@ -15,20 +15,18 @@ sectortypes 12 = "Space Countdown"; 13 = "Ramp Sector (double step-up/down)"; 14 = "Non-Ramp Sector (no step-down)"; - 15 = "Bouncy FOF"; + 15 = "Bouncy FOF "; 16 = "Trigger Line Ex. (Pushable Objects)"; 32 = "Trigger Line Ex. (Anywhere, All Players)"; 48 = "Trigger Line Ex. (Floor Touch, All Players)"; 64 = "Trigger Line Ex. (Anywhere in Sector)"; 80 = "Trigger Line Ex. (Floor Touch)"; - 96 = "Trigger Line Ex. (Emerald Check)"; - 112 = "Trigger Line Ex. (NiGHTS Mare)"; + 96 = "Trigger Line Ex. (Emerald Check) "; + 112 = "Trigger Line Ex. (NiGHTS Mare) "; 128 = "Check for Linedef Executor on FOFs"; 144 = "Egg Capsule"; - 160 = "Special Stage Time/Spheres Parameters"; - 176 = "Custom Global Gravity"; - 512 = "Wind/Current"; - 1024 = "Conveyor Belt"; + 160 = "Special Stage Time/Spheres Parameters "; + 176 = "Custom Global Gravity "; 1280 = "Speed Pad"; 4096 = "Star Post Activator"; 8192 = "Exit/Special Stage Pit/Return Flag"; @@ -63,7 +61,7 @@ gen_sectortypes 12 = "Space Countdown"; 13 = "Ramp Sector (double step-up/down)"; 14 = "Non-Ramp Sector (no step-down)"; - 15 = "Bouncy FOF"; + 15 = "Bouncy FOF "; } second @@ -74,19 +72,17 @@ gen_sectortypes 48 = "Trigger Line Ex. (Floor Touch, All Players)"; 64 = "Trigger Line Ex. (Anywhere in Sector)"; 80 = "Trigger Line Ex. (Floor Touch)"; - 96 = "Trigger Line Ex. (Emerald Check)"; - 112 = "Trigger Line Ex. (NiGHTS Mare)"; + 96 = "Trigger Line Ex. (Emerald Check) "; + 112 = "Trigger Line Ex. (NiGHTS Mare) "; 128 = "Check for Linedef Executor on FOFs"; 144 = "Egg Capsule"; - 160 = "Special Stage Time/Spheres Parameters"; - 176 = "Custom Global Gravity"; + 160 = "Special Stage Time/Spheres Parameters "; + 176 = "Custom Global Gravity "; } third { 0 = "Normal"; - 512 = "Wind/Current"; - 1024 = "Conveyor Belt"; 1280 = "Speed Pad"; } diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg index 0ea452155..1de661e29 100644 --- a/extras/conf/udb/Includes/SRB222_things.cfg +++ b/extras/conf/udb/Includes/SRB222_things.cfg @@ -3,3139 +3,8037 @@ // 8-Dark_Gray 9-Blue 10-Green 11-Cyan 12-Red 13-Magenta // 14-Yellow 15-White 16-Pink 17-Orange 18-Gold 19-Cream -editor +doom { - color = 15; // White - arrow = 1; - title = ""; - error = -1; - width = 8; - height = 16; - sort = 1; - - 3328 = "3D Mode Start"; -} - -starts -{ - color = 1; // Blue - arrow = 1; - title = "Player Starts"; - width = 16; - height = 48; - sprite = "PLAYA0"; - - 1 + editor { - title = "Player 01 Start"; - sprite = "PLAYA0"; - } - 2 - { - title = "Player 02 Start"; - sprite = "PLAYA0"; - } - 3 - { - title = "Player 03 Start"; - sprite = "PLAYA0"; - } - 4 - { - title = "Player 04 Start"; - sprite = "PLAYA0"; - } - 5 - { - title = "Player 05 Start"; - sprite = "PLAYA0"; - } - 6 - { - title = "Player 06 Start"; - sprite = "PLAYA0"; - } - 7 - { - title = "Player 07 Start"; - sprite = "PLAYA0"; - } - 8 - { - title = "Player 08 Start"; - sprite = "PLAYA0"; - } - 9 - { - title = "Player 09 Start"; - sprite = "PLAYA0"; - } - 10 - { - title = "Player 10 Start"; - sprite = "PLAYA0"; - } - 11 - { - title = "Player 11 Start"; - sprite = "PLAYA0"; - } - 12 - { - title = "Player 12 Start"; - sprite = "PLAYA0"; - } - 13 - { - title = "Player 13 Start"; - sprite = "PLAYA0"; - } - 14 - { - title = "Player 14 Start"; - sprite = "PLAYA0"; - } - 15 - { - title = "Player 15 Start"; - sprite = "PLAYA0"; - } - 16 - { - title = "Player 16 Start"; - sprite = "PLAYA0"; - } - 17 - { - title = "Player 17 Start"; - sprite = "PLAYA0"; - } - 18 - { - title = "Player 18 Start"; - sprite = "PLAYA0"; - } - 19 - { - title = "Player 19 Start"; - sprite = "PLAYA0"; - } - 20 - { - title = "Player 20 Start"; - sprite = "PLAYA0"; - } - 21 - { - title = "Player 21 Start"; - sprite = "PLAYA0"; - } - 22 - { - title = "Player 22 Start"; - sprite = "PLAYA0"; - } - 23 - { - title = "Player 23 Start"; - sprite = "PLAYA0"; - } - 24 - { - title = "Player 24 Start"; - sprite = "PLAYA0"; - } - 25 - { - title = "Player 25 Start"; - sprite = "PLAYA0"; - } - 26 - { - title = "Player 26 Start"; - sprite = "PLAYA0"; - } - 27 - { - title = "Player 27 Start"; - sprite = "PLAYA0"; - } - 28 - { - title = "Player 28 Start"; - sprite = "PLAYA0"; - } - 29 - { - title = "Player 29 Start"; - sprite = "PLAYA0"; - } - 30 - { - title = "Player 30 Start"; - sprite = "PLAYA0"; - } - 31 - { - title = "Player 31 Start"; - sprite = "PLAYA0"; - } - 32 - { - title = "Player 32 Start"; - sprite = "PLAYA0"; - } - 33 - { - title = "Match Start"; - sprite = "NDRNA2A8"; - } - 34 - { - title = "CTF Red Team Start"; - sprite = "SIGNG0"; - } - 35 - { - title = "CTF Blue Team Start"; - sprite = "SIGNE0"; - } -} - -enemies -{ - color = 9; // Light_Blue - arrow = 1; - title = "Enemies"; - - 100 - { - title = "Crawla (Blue)"; - sprite = "POSSA1"; - width = 24; - height = 32; - } - 101 - { - title = "Crawla (Red)"; - sprite = "SPOSA1"; - width = 24; - height = 32; - } - 102 - { - title = "Stupid Dumb Unnamed RoboFish"; - sprite = "FISHA0"; + color = 15; // White + arrow = 1; + title = ""; + error = -1; width = 8; - height = 28; + height = 16; + sort = 1; + + 3328 = "3D Mode Start"; } - 103 + + starts { - title = "Buzz (Gold)"; - sprite = "BUZZA1"; - width = 28; - height = 40; - } - 104 - { - title = "Buzz (Red)"; - sprite = "RBUZA1"; - width = 28; - height = 40; - } - 108 - { - title = "Deton"; - sprite = "DETNA1"; - width = 20; - height = 32; - } - 110 - { - title = "Turret"; - sprite = "TRETA1"; - width = 16; - height = 32; - } - 111 - { - title = "Pop-up Turret"; - sprite = "TURRI1"; - width = 12; - height = 64; - } - 122 - { - title = "Spring Shell (Green)"; - sprite = "SSHLA1"; - width = 24; - height = 40; - } - 125 - { - title = "Spring Shell (Yellow)"; - sprite = "SSHLI1"; - width = 24; - height = 40; - } - 109 - { - title = "Skim"; - sprite = "SKIMA1"; - width = 16; - height = 24; - } - 113 - { - title = "Jet Jaw"; - sprite = "JJAWA3A7"; - width = 12; - height = 20; - } - 126 - { - title = "Crushstacean"; - sprite = "CRABA0"; - width = 24; - height = 32; - } - 138 - { - title = "Banpyura"; - sprite = "CR2BA0"; - width = 24; - height = 32; - } - 117 - { - title = "Robo-Hood"; - sprite = "ARCHA1"; - width = 24; - height = 32; - } - 118 - { - title = "Lance-a-Bot"; - sprite = "CBFSA1"; - width = 32; - height = 72; - } - 1113 - { - title = "Suspicious Lance-a-Bot Statue"; - sprite = "CBBSA1"; - width = 32; - height = 72; - } - 119 - { - title = "Egg Guard"; - sprite = "ESHIA1"; + color = 1; // Blue + arrow = 1; + title = "Player Starts"; width = 16; height = 48; - } - 115 - { - title = "Bird Aircraft Strike Hazard"; - sprite = "VLTRF1"; - width = 12; - height = 24; - } - 120 - { - title = "Green Snapper"; - sprite = "GSNPA1"; - width = 24; - height = 24; - } - 121 - { - title = "Minus"; - sprite = "MNUSA0"; - width = 24; - height = 32; - } - 134 - { - title = "Canarivore"; - sprite = "CANAA0"; - width = 12; - height = 80; - hangs = 1; - } - 123 - { - title = "Unidus"; - sprite = "UNIDA1"; - width = 18; - height = 36; - } - 135 - { - title = "Pterabyte Spawner"; - sprite = "PTERA2A8"; - width = 16; - height = 16; - } - 136 - { - title = "Pyre Fly"; - sprite = "PYREA0"; - width = 24; - height = 34; - } - 137 - { - title = "Dragonbomber"; - sprite = "DRABA1"; - width = 28; - height = 48; - } - 105 - { - title = "Jetty-Syn Bomber"; - sprite = "JETBB1"; - width = 20; - height = 50; - } - 106 - { - title = "Jetty-Syn Gunner"; - sprite = "JETGB1"; - width = 20; - height = 48; - } - 112 - { - title = "Spincushion"; - sprite = "SHRPA1"; - width = 16; - height = 24; - } - 114 - { - title = "Snailer"; - sprite = "SNLRA3A7"; - width = 24; - height = 48; - } - 129 - { - title = "Penguinator"; - sprite = "PENGA1"; - width = 24; - height = 32; - } - 130 - { - title = "Pophat"; - sprite = "POPHA1"; - width = 24; - height = 32; - } - 107 - { - title = "Crawla Commander"; - sprite = "CCOMA1"; - width = 16; - height = 32; - } - 131 - { - title = "Spinbobert"; - sprite = "SBOBB0"; - width = 32; - height = 32; - } - 132 - { - title = "Cacolantern"; - sprite = "CACOA0"; - width = 32; - height = 32; - } - 133 - { - title = "Hangster"; - sprite = "HBATC1"; - width = 24; - height = 24; - hangs = 1; - } - 127 - { - title = "Hive Elemental"; - sprite = "HIVEA0"; - width = 32; - height = 80; - } - 128 - { - title = "Bumblebore"; - sprite = "BUMBA1"; - width = 16; - height = 32; - } - 124 - { - title = "Buggle"; - sprite = "BBUZA1"; - width = 20; - height = 24; - } - 116 - { - title = "Pointy"; - sprite = "PNTYA1"; - width = 8; - height = 16; - } -} + sprite = "PLAYA0"; -bosses -{ - color = 8; // Dark_Gray - arrow = 1; - title = "Bosses"; + 1 + { + title = "Player 01 Start"; + sprite = "PLAYA0"; + } + 2 + { + title = "Player 02 Start"; + sprite = "PLAYA0"; + } + 3 + { + title = "Player 03 Start"; + sprite = "PLAYA0"; + } + 4 + { + title = "Player 04 Start"; + sprite = "PLAYA0"; + } + 5 + { + title = "Player 05 Start"; + sprite = "PLAYA0"; + } + 6 + { + title = "Player 06 Start"; + sprite = "PLAYA0"; + } + 7 + { + title = "Player 07 Start"; + sprite = "PLAYA0"; + } + 8 + { + title = "Player 08 Start"; + sprite = "PLAYA0"; + } + 9 + { + title = "Player 09 Start"; + sprite = "PLAYA0"; + } + 10 + { + title = "Player 10 Start"; + sprite = "PLAYA0"; + } + 11 + { + title = "Player 11 Start"; + sprite = "PLAYA0"; + } + 12 + { + title = "Player 12 Start"; + sprite = "PLAYA0"; + } + 13 + { + title = "Player 13 Start"; + sprite = "PLAYA0"; + } + 14 + { + title = "Player 14 Start"; + sprite = "PLAYA0"; + } + 15 + { + title = "Player 15 Start"; + sprite = "PLAYA0"; + } + 16 + { + title = "Player 16 Start"; + sprite = "PLAYA0"; + } + 17 + { + title = "Player 17 Start"; + sprite = "PLAYA0"; + } + 18 + { + title = "Player 18 Start"; + sprite = "PLAYA0"; + } + 19 + { + title = "Player 19 Start"; + sprite = "PLAYA0"; + } + 20 + { + title = "Player 20 Start"; + sprite = "PLAYA0"; + } + 21 + { + title = "Player 21 Start"; + sprite = "PLAYA0"; + } + 22 + { + title = "Player 22 Start"; + sprite = "PLAYA0"; + } + 23 + { + title = "Player 23 Start"; + sprite = "PLAYA0"; + } + 24 + { + title = "Player 24 Start"; + sprite = "PLAYA0"; + } + 25 + { + title = "Player 25 Start"; + sprite = "PLAYA0"; + } + 26 + { + title = "Player 26 Start"; + sprite = "PLAYA0"; + } + 27 + { + title = "Player 27 Start"; + sprite = "PLAYA0"; + } + 28 + { + title = "Player 28 Start"; + sprite = "PLAYA0"; + } + 29 + { + title = "Player 29 Start"; + sprite = "PLAYA0"; + } + 30 + { + title = "Player 30 Start"; + sprite = "PLAYA0"; + } + 31 + { + title = "Player 31 Start"; + sprite = "PLAYA0"; + } + 32 + { + title = "Player 32 Start"; + sprite = "PLAYA0"; + } + 33 + { + title = "Match Start"; + sprite = "NDRNA2A8"; + } + 34 + { + title = "CTF Red Team Start"; + sprite = "SIGNG0"; + } + 35 + { + title = "CTF Blue Team Start"; + sprite = "SIGNE0"; + } + } - 200 + enemies { - title = "Egg Mobile"; - sprite = "EGGMA1"; - width = 24; - height = 76; - } - 201 - { - title = "Egg Slimer"; - sprite = "EGGNA1"; - width = 24; - height = 76; - } - 202 - { - title = "Sea Egg"; - sprite = "EGGOA1"; - width = 32; - height = 116; - } - 203 - { - title = "Egg Colosseum"; - sprite = "EGGPA1"; - width = 24; - height = 76; - } - 204 - { - title = "Fang"; - sprite = "FANGA1"; - width = 24; - height = 60; - } - 206 - { - title = "Brak Eggman (Old)"; - sprite = "BRAKB1"; - width = 48; - height = 160; - } - 207 - { - title = "Metal Sonic (Race)"; - sprite = "METLI1"; - width = 16; - height = 48; - } - 208 - { - title = "Metal Sonic (Battle)"; - sprite = "METLC1"; - width = 16; - height = 48; - } - 209 - { - title = "Brak Eggman"; - sprite = "BRAK01"; - width = 48; - height = 160; - } - 290 - { - arrow = 0; - title = "Boss Escape Point"; - width = 8; - height = 16; - sprite = "internal:eggmanend"; - } - 291 - { - arrow = 0; - title = "Egg Capsule Center"; - width = 8; - height = 16; - sprite = "internal:capsule"; - } - 292 - { - arrow = 0; - title = "Boss Waypoint"; - width = 8; - height = 16; - sprite = "internal:eggmanway"; - } - 293 - { - title = "Metal Sonic Gather Point"; - sprite = "internal:metal"; - width = 8; - height = 16; - } - 294 - { - title = "Fang Waypoint"; - sprite = "internal:eggmanway"; - width = 8; - height = 16; - } -} + color = 9; // Light_Blue + arrow = 1; + title = "Enemies"; -rings -{ - color = 14; // Yellow - title = "Rings and Weapon Panels"; - width = 24; - height = 24; - sprite = "RINGA0"; + 100 + { + title = "Crawla (Blue)"; + sprite = "POSSA1"; + width = 24; + height = 32; + } + 101 + { + title = "Crawla (Red)"; + sprite = "SPOSA1"; + width = 24; + height = 32; + } + 102 + { + title = "Stupid Dumb Unnamed RoboFish"; + sprite = "FISHA0"; + width = 8; + height = 28; + } + 103 + { + title = "Buzz (Gold)"; + sprite = "BUZZA1"; + width = 28; + height = 40; + } + 104 + { + title = "Buzz (Red)"; + sprite = "RBUZA1"; + width = 28; + height = 40; + } + 108 + { + title = "Deton"; + sprite = "DETNA1"; + width = 20; + height = 32; + } + 110 + { + title = "Turret"; + sprite = "TRETA1"; + width = 16; + height = 32; + } + 111 + { + title = "Pop-up Turret"; + sprite = "TURRI1"; + width = 12; + height = 64; + } + 122 + { + title = "Spring Shell (Green)"; + sprite = "SSHLA1"; + width = 24; + height = 40; + } + 125 + { + title = "Spring Shell (Yellow)"; + sprite = "SSHLI1"; + width = 24; + height = 40; + } + 109 + { + title = "Skim"; + sprite = "SKIMA1"; + width = 16; + height = 24; + } + 113 + { + title = "Jet Jaw"; + sprite = "JJAWA3A7"; + width = 12; + height = 20; + } + 126 + { + title = "Crushstacean"; + sprite = "CRABA0"; + width = 24; + height = 32; + } + 138 + { + title = "Banpyura"; + sprite = "CR2BA0"; + width = 24; + height = 32; + } + 117 + { + title = "Robo-Hood"; + sprite = "ARCHA1"; + width = 24; + height = 32; + } + 118 + { + title = "Lance-a-Bot"; + sprite = "CBFSA1"; + width = 32; + height = 72; + } + 1113 + { + title = "Suspicious Lance-a-Bot Statue"; + sprite = "CBBSA1"; + width = 32; + height = 72; + } + 119 + { + title = "Egg Guard"; + sprite = "ESHIA1"; + width = 16; + height = 48; + } + 115 + { + title = "Bird Aircraft Strike Hazard"; + sprite = "VLTRF1"; + width = 12; + height = 24; + } + 120 + { + title = "Green Snapper"; + sprite = "GSNPA1"; + width = 24; + height = 24; + } + 121 + { + title = "Minus"; + sprite = "MNUSA0"; + width = 24; + height = 32; + } + 134 + { + title = "Canarivore"; + sprite = "CANAA0"; + width = 12; + height = 80; + hangs = 1; + } + 123 + { + title = "Unidus"; + sprite = "UNIDA1"; + width = 18; + height = 36; + } + 135 + { + title = "Pterabyte Spawner"; + sprite = "PTERA2A8"; + width = 16; + height = 16; + } + 136 + { + title = "Pyre Fly"; + sprite = "PYREA0"; + width = 24; + height = 34; + } + 137 + { + title = "Dragonbomber"; + sprite = "DRABA1"; + width = 28; + height = 48; + } + 105 + { + title = "Jetty-Syn Bomber"; + sprite = "JETBB1"; + width = 20; + height = 50; + } + 106 + { + title = "Jetty-Syn Gunner"; + sprite = "JETGB1"; + width = 20; + height = 48; + } + 112 + { + title = "Spincushion"; + sprite = "SHRPA1"; + width = 16; + height = 24; + } + 114 + { + title = "Snailer"; + sprite = "SNLRA3A7"; + width = 24; + height = 48; + } + 129 + { + title = "Penguinator"; + sprite = "PENGA1"; + width = 24; + height = 32; + } + 130 + { + title = "Pophat"; + sprite = "POPHA1"; + width = 24; + height = 32; + } + 107 + { + title = "Crawla Commander"; + sprite = "CCOMA1"; + width = 16; + height = 32; + } + 131 + { + title = "Spinbobert"; + sprite = "SBOBB0"; + width = 32; + height = 32; + } + 132 + { + title = "Cacolantern"; + sprite = "CACOA0"; + width = 32; + height = 32; + } + 133 + { + title = "Hangster"; + sprite = "HBATC1"; + width = 24; + height = 24; + hangs = 1; + } + 127 + { + title = "Hive Elemental"; + sprite = "HIVEA0"; + width = 32; + height = 80; + } + 128 + { + title = "Bumblebore"; + sprite = "BUMBA1"; + width = 16; + height = 32; + } + 124 + { + title = "Buggle"; + sprite = "BBUZA1"; + width = 20; + height = 24; + } + 116 + { + title = "Pointy"; + sprite = "PNTYA1"; + width = 8; + height = 16; + } + } - 300 + bosses { - title = "Ring"; + color = 8; // Dark_Gray + arrow = 1; + title = "Bosses"; + + 200 + { + title = "Egg Mobile"; + sprite = "EGGMA1"; + width = 24; + height = 76; + } + 201 + { + title = "Egg Slimer"; + sprite = "EGGNA1"; + width = 24; + height = 76; + } + 202 + { + title = "Sea Egg"; + sprite = "EGGOA1"; + width = 32; + height = 116; + } + 203 + { + title = "Egg Colosseum"; + sprite = "EGGPA1"; + width = 24; + height = 76; + } + 204 + { + title = "Fang"; + sprite = "FANGA1"; + width = 24; + height = 60; + } + 206 + { + title = "Brak Eggman (Old)"; + sprite = "BRAKB1"; + width = 48; + height = 160; + } + 207 + { + title = "Metal Sonic (Race)"; + sprite = "METLI1"; + width = 16; + height = 48; + } + 208 + { + title = "Metal Sonic (Battle)"; + sprite = "METLC1"; + width = 16; + height = 48; + } + 209 + { + title = "Brak Eggman"; + sprite = "BRAK01"; + width = 48; + height = 160; + } + 290 + { + arrow = 0; + title = "Boss Escape Point"; + width = 8; + height = 16; + sprite = "internal:eggmanend"; + } + 291 + { + arrow = 0; + title = "Egg Capsule Center"; + width = 8; + height = 16; + sprite = "internal:capsule"; + } + 292 + { + arrow = 0; + title = "Boss Waypoint"; + width = 8; + height = 16; + sprite = "internal:eggmanway"; + } + 293 + { + title = "Metal Sonic Gather Point"; + sprite = "internal:metal"; + width = 8; + height = 16; + } + 294 + { + title = "Fang Waypoint"; + sprite = "internal:eggmanway"; + width = 8; + height = 16; + } + } + + rings + { + color = 14; // Yellow + title = "Rings and Weapon Panels"; + width = 24; + height = 24; sprite = "RINGA0"; - width = 16; - } - 301 - { - title = "Bounce Ring"; - sprite = "internal:RNGBA0"; - } - 302 - { - title = "Rail Ring"; - sprite = "internal:RNGRA0"; - } - 303 - { - title = "Infinity Ring"; - sprite = "internal:RNGIA0"; - } - 304 - { - title = "Automatic Ring"; - sprite = "internal:RNGAA0"; - } - 305 - { - title = "Explosion Ring"; - sprite = "internal:RNGEA0"; - } - 306 - { - title = "Scatter Ring"; - sprite = "internal:RNGSA0"; - } - 307 - { - title = "Grenade Ring"; - sprite = "internal:RNGGA0"; - } - 308 - { - title = "CTF Team Ring (Red)"; - sprite = "internal:RRNGA0"; - width = 16; - } - 309 - { - title = "CTF Team Ring (Blue)"; - sprite = "internal:BRNGA0"; - width = 16; - } - 330 - { - title = "Bounce Ring Panel"; - sprite = "internal:PIKBA0"; - } - 331 - { - title = "Rail Ring Panel"; - sprite = "internal:PIKRA0"; - } - 332 - { - title = "Automatic Ring Panel"; - sprite = "internal:PIKAA0"; - } - 333 - { - title = "Explosion Ring Panel"; - sprite = "internal:PIKEA0"; - } - 334 - { - title = "Scatter Ring Panel"; - sprite = "internal:PIKSA0"; - } - 335 - { - title = "Grenade Ring Panel"; - sprite = "internal:PIKGA0"; - } -} -collectibles -{ - color = 10; // Light_Green - title = "Other Collectibles"; - width = 16; - height = 32; - sort = 1; - sprite = "CEMGA0"; + 300 + { + title = "Ring"; + sprite = "RINGA0"; + width = 16; + } + 301 + { + title = "Bounce Ring"; + sprite = "internal:RNGBA0"; + } + 302 + { + title = "Rail Ring"; + sprite = "internal:RNGRA0"; + } + 303 + { + title = "Infinity Ring"; + sprite = "internal:RNGIA0"; + } + 304 + { + title = "Automatic Ring"; + sprite = "internal:RNGAA0"; + } + 305 + { + title = "Explosion Ring"; + sprite = "internal:RNGEA0"; + } + 306 + { + title = "Scatter Ring"; + sprite = "internal:RNGSA0"; + } + 307 + { + title = "Grenade Ring"; + sprite = "internal:RNGGA0"; + } + 308 + { + title = "CTF Team Ring (Red)"; + sprite = "internal:RRNGA0"; + width = 16; + } + 309 + { + title = "CTF Team Ring (Blue)"; + sprite = "internal:BRNGA0"; + width = 16; + } + 330 + { + title = "Bounce Ring Panel"; + sprite = "internal:PIKBA0"; + } + 331 + { + title = "Rail Ring Panel"; + sprite = "internal:PIKRA0"; + } + 332 + { + title = "Automatic Ring Panel"; + sprite = "internal:PIKAA0"; + } + 333 + { + title = "Explosion Ring Panel"; + sprite = "internal:PIKEA0"; + } + 334 + { + title = "Scatter Ring Panel"; + sprite = "internal:PIKSA0"; + } + 335 + { + title = "Grenade Ring Panel"; + sprite = "internal:PIKGA0"; + } + } - 310 + collectibles { - title = "CTF Red Flag"; - sprite = "RFLGA0"; - width = 24; - height = 64; - } - 311 - { - title = "CTF Blue Flag"; - sprite = "BFLGA0"; - width = 24; - height = 64; - } - 312 - { - title = "Emerald Token"; - sprite = "TOKEA0"; + color = 10; // Light_Green + title = "Other Collectibles"; width = 16; height = 32; - } - 313 - { - title = "Chaos Emerald 1 (Green)"; + sort = 1; sprite = "CEMGA0"; - } - 314 - { - title = "Chaos Emerald 2 (Purple)"; - sprite = "CEMGB0"; - } - 315 - { - title = "Chaos Emerald 3 (Blue)"; - sprite = "CEMGC0"; - } - 316 - { - title = "Chaos Emerald 4 (Cyan)"; - sprite = "CEMGD0"; - } - 317 - { - title = "Chaos Emerald 5 (Orange)"; - sprite = "CEMGE0"; - } - 318 - { - title = "Chaos Emerald 6 (Red)"; - sprite = "CEMGF0"; - } - 319 - { - title = "Chaos Emerald 7 (Gray)"; - sprite = "CEMGG0"; - } - 320 - { - title = "Emerald Hunt Location"; - sprite = "SHRDA0"; - } - 321 - { - title = "Match Chaos Emerald Spawn"; - sprite = "CEMGA0"; - } - 322 - { - title = "Emblem"; - sprite = "EMBMA0"; - width = 16; - height = 30; - } -} -boxes -{ - color = 7; // Gray - blocking = 2; - title = "Monitors"; - width = 18; - height = 40; + 310 + { + title = "CTF Red Flag"; + sprite = "RFLGA0"; + width = 24; + height = 64; + } + 311 + { + title = "CTF Blue Flag"; + sprite = "BFLGA0"; + width = 24; + height = 64; + } + 312 + { + title = "Emerald Token"; + sprite = "TOKEA0"; + width = 16; + height = 32; + } + 313 + { + title = "Chaos Emerald 1 (Green)"; + sprite = "CEMGA0"; + } + 314 + { + title = "Chaos Emerald 2 (Purple)"; + sprite = "CEMGB0"; + } + 315 + { + title = "Chaos Emerald 3 (Blue)"; + sprite = "CEMGC0"; + } + 316 + { + title = "Chaos Emerald 4 (Cyan)"; + sprite = "CEMGD0"; + } + 317 + { + title = "Chaos Emerald 5 (Orange)"; + sprite = "CEMGE0"; + } + 318 + { + title = "Chaos Emerald 6 (Red)"; + sprite = "CEMGF0"; + } + 319 + { + title = "Chaos Emerald 7 (Gray)"; + sprite = "CEMGG0"; + } + 320 + { + title = "Emerald Hunt Location"; + sprite = "SHRDA0"; + } + 321 + { + title = "Match Chaos Emerald Spawn"; + sprite = "CEMGA0"; + } + 322 + { + title = "Emblem"; + sprite = "EMBMA0"; + width = 16; + height = 30; + } + } - 400 + boxes { - title = "Super Ring (10 Rings)"; - sprite = "TVRIA0"; - } - 401 - { - title = "Pity Shield"; - sprite = "TVPIA0"; - } - 402 - { - title = "Attraction Shield"; - sprite = "TVATA0"; - } - 403 - { - title = "Force Shield"; - sprite = "TVFOA0"; - } - 404 - { - title = "Armageddon Shield"; - sprite = "TVARA0"; - } - 405 - { - title = "Whirlwind Shield"; - sprite = "TVWWA0"; - } - 406 - { - title = "Elemental Shield"; - sprite = "TVELA0"; - } - 407 - { - title = "Super Sneakers"; - sprite = "TVSSA0"; - } - 408 - { - title = "Invincibility"; - sprite = "TVIVA0"; - } - 409 - { - title = "Extra Life"; - sprite = "TV1UA0"; - } - 410 - { - title = "Eggman"; - sprite = "TVEGA0"; - } - 411 - { - title = "Teleporter"; - sprite = "TVMXA0"; - } - 413 - { - title = "Gravity Boots"; - sprite = "TVGVA0"; - } - 414 - { - title = "CTF Team Ring Monitor (Red)"; - sprite = "TRRIA0"; - } - 415 - { - title = "CTF Team Ring Monitor (Blue)"; - sprite = "TBRIA0"; - } - 416 - { - title = "Recycler"; - sprite = "TVRCA0"; - } - 418 - { - title = "Score (1,000 Points)"; - sprite = "TV1KA0"; - } - 419 - { - title = "Score (10,000 Points)"; - sprite = "TVTKA0"; - } - 420 - { - title = "Flame Shield"; - sprite = "TVFLA0"; - } - 421 - { - title = "Water Shield"; - sprite = "TVBBA0"; - } - 422 - { - title = "Lightning Shield"; - sprite = "TVZPA0"; - } -} + color = 7; // Gray + blocking = 2; + title = "Monitors"; + width = 18; + height = 40; -boxes2 -{ - color = 18; // Gold - blocking = 2; - title = "Monitors (Respawning)"; - width = 20; - height = 44; + 400 + { + title = "Super Ring (10 Rings)"; + sprite = "TVRIA0"; + } + 401 + { + title = "Pity Shield"; + sprite = "TVPIA0"; + } + 402 + { + title = "Attraction Shield"; + sprite = "TVATA0"; + } + 403 + { + title = "Force Shield"; + sprite = "TVFOA0"; + } + 404 + { + title = "Armageddon Shield"; + sprite = "TVARA0"; + } + 405 + { + title = "Whirlwind Shield"; + sprite = "TVWWA0"; + } + 406 + { + title = "Elemental Shield"; + sprite = "TVELA0"; + } + 407 + { + title = "Super Sneakers"; + sprite = "TVSSA0"; + } + 408 + { + title = "Invincibility"; + sprite = "TVIVA0"; + } + 409 + { + title = "Extra Life"; + sprite = "TV1UA0"; + } + 410 + { + title = "Eggman"; + sprite = "TVEGA0"; + } + 411 + { + title = "Teleporter"; + sprite = "TVMXA0"; + } + 413 + { + title = "Gravity Boots"; + sprite = "TVGVA0"; + } + 414 + { + title = "CTF Team Ring Monitor (Red)"; + sprite = "TRRIA0"; + } + 415 + { + title = "CTF Team Ring Monitor (Blue)"; + sprite = "TBRIA0"; + } + 416 + { + title = "Recycler"; + sprite = "TVRCA0"; + } + 418 + { + title = "Score (1,000 Points)"; + sprite = "TV1KA0"; + } + 419 + { + title = "Score (10,000 Points)"; + sprite = "TVTKA0"; + } + 420 + { + title = "Flame Shield"; + sprite = "TVFLA0"; + } + 421 + { + title = "Water Shield"; + sprite = "TVBBA0"; + } + 422 + { + title = "Lightning Shield"; + sprite = "TVZPA0"; + } + } - 431 + boxes2 { - title = "Pity Shield (Respawn)"; - sprite = "TVPIB0"; - } - 432 - { - title = "Attraction Shield (Respawn)"; - sprite = "TVATB0"; - } - 433 - { - title = "Force Shield (Respawn)"; - sprite = "TVFOB0"; - } - 434 - { - title = "Armageddon Shield (Respawn)"; - sprite = "TVARB0"; - } - 435 - { - title = "Whirlwind Shield (Respawn)"; - sprite = "TVWWB0"; - } - 436 - { - title = "Elemental Shield (Respawn)"; - sprite = "TVELB0"; - } - 437 - { - title = "Super Sneakers (Respawn)"; - sprite = "TVSSB0"; - } - 438 - { - title = "Invincibility (Respawn)"; - sprite = "TVIVB0"; - } - 440 - { - title = "Eggman (Respawn)"; - sprite = "TVEGB0"; - } - 443 - { - title = "Gravity Boots (Respawn)"; - sprite = "TVGVB0"; - } - 450 - { - title = "Flame Shield (Respawn)"; - sprite = "TVFLB0"; - } - 451 - { - title = "Water Shield (Respawn)"; - sprite = "TVBBB0"; - } - 452 - { - title = "Lightning Shield (Respawn)"; - sprite = "TVZPB0"; - } -} + color = 18; // Gold + blocking = 2; + title = "Monitors (Respawning)"; + width = 20; + height = 44; -generic -{ - color = 11; // Light_Cyan - title = "Generic Items & Hazards"; + 431 + { + title = "Pity Shield (Respawn)"; + sprite = "TVPIB0"; + } + 432 + { + title = "Attraction Shield (Respawn)"; + sprite = "TVATB0"; + } + 433 + { + title = "Force Shield (Respawn)"; + sprite = "TVFOB0"; + } + 434 + { + title = "Armageddon Shield (Respawn)"; + sprite = "TVARB0"; + } + 435 + { + title = "Whirlwind Shield (Respawn)"; + sprite = "TVWWB0"; + } + 436 + { + title = "Elemental Shield (Respawn)"; + sprite = "TVELB0"; + } + 437 + { + title = "Super Sneakers (Respawn)"; + sprite = "TVSSB0"; + } + 438 + { + title = "Invincibility (Respawn)"; + sprite = "TVIVB0"; + } + 440 + { + title = "Eggman (Respawn)"; + sprite = "TVEGB0"; + } + 443 + { + title = "Gravity Boots (Respawn)"; + sprite = "TVGVB0"; + } + 450 + { + title = "Flame Shield (Respawn)"; + sprite = "TVFLB0"; + } + 451 + { + title = "Water Shield (Respawn)"; + sprite = "TVBBB0"; + } + 452 + { + title = "Lightning Shield (Respawn)"; + sprite = "TVZPB0"; + } + } - 500 + generic { - title = "Air Bubble Patch"; - sprite = "BUBLE0"; - width = 8; + color = 11; // Light_Cyan + title = "Generic Items & Hazards"; + + 500 + { + title = "Air Bubble Patch"; + sprite = "BUBLE0"; + width = 8; + height = 16; + } + 501 + { + title = "Signpost"; + sprite = "SIGND0"; + width = 8; + height = 32; + } + 502 + { + arrow = 1; + title = "Star Post"; + sprite = "STPTA0M0"; + width = 64; + height = 128; + } + 520 + { + title = "Bomb Sphere"; + sprite = "SPHRD0"; + width = 16; + height = 24; + } + 521 + { + title = "Spikeball"; + sprite = "SPIKA0"; + width = 12; + height = 8; + } + 522 + { + title = "Wall Spike"; + sprite = "WSPKALAR"; + width = 16; + height = 14; + arrow = 1; + } + 523 + { + title = "Spike"; + sprite = "USPKA0"; + width = 8; + height = 32; + } + 1130 + { + title = "Small Mace"; + sprite = "SMCEA0"; + width = 17; + height = 34; + } + 1131 + { + title = "Big Mace"; + sprite = "BMCEA0"; + width = 34; + height = 68; + } + 1136 + { + title = "Small Fireball"; + sprite = "SFBRA0"; + width = 17; + height = 34; + } + 1137 + { + title = "Large Fireball"; + sprite = "BFBRA0"; + width = 34; + height = 68; + } + } + + springs + { + color = 12; // Light_Red + title = "Springs and Fans"; + width = 20; height = 16; - } - 501 - { - title = "Signpost"; - sprite = "SIGND0"; - width = 8; - height = 32; - } - 502 - { - arrow = 1; - title = "Star Post"; - sprite = "STPTA0M0"; - width = 64; - height = 128; - } - 520 - { - title = "Bomb Sphere"; - sprite = "SPHRD0"; - width = 16; - height = 24; - } - 521 - { - title = "Spikeball"; - sprite = "SPIKA0"; - width = 12; - height = 8; - } - 522 - { - title = "Wall Spike"; - sprite = "WSPKALAR"; - width = 16; - height = 14; - arrow = 1; - } - 523 - { - title = "Spike"; - sprite = "USPKA0"; - width = 8; - height = 32; - } - 1130 - { - title = "Small Mace"; - sprite = "SMCEA0"; - width = 17; - height = 34; - } - 1131 - { - title = "Big Mace"; - sprite = "BMCEA0"; - width = 34; - height = 68; - } - 1136 - { - title = "Small Fireball"; - sprite = "SFBRA0"; - width = 17; - height = 34; - } - 1137 - { - title = "Large Fireball"; - sprite = "BFBRA0"; - width = 34; - height = 68; - } -} - -springs -{ - color = 12; // Light_Red - title = "Springs and Fans"; - width = 20; - height = 16; - sprite = "RSPRD2"; - - 540 - { - title = "Fan"; - sprite = "FANSA0D0"; - width = 16; - height = 8; - } - 541 - { - title = "Gas Jet"; - sprite = "STEMD0"; - width = 32; - } - 542 - { - title = "Bumper"; - sprite = "BUMPA0"; - width = 32; - height = 64; - } - 543 - { - title = "Balloon"; - sprite = "BLONA0"; - width = 32; - height = 64; - } - 550 - { - title = "Yellow Spring"; - sprite = "SPRYA0"; - } - 551 - { - title = "Red Spring"; - sprite = "SPRRA0"; - } - 552 - { - title = "Blue Spring"; - sprite = "SPRBA0"; - } - 555 - { - arrow = 1; - title = "Diagonal Yellow Spring"; - sprite = "YSPRD2"; - width = 16; - } - 556 - { - arrow = 1; - title = "Diagonal Red Spring"; sprite = "RSPRD2"; - width = 16; - } - 557 - { - arrow = 1; - title = "Diagonal Blue Spring"; - sprite = "BSPRD2"; - width = 16; - } - 558 - { - arrow = 1; - title = "Horizontal Yellow Spring"; - sprite = "SSWYD2D8"; - width = 16; - height = 32; - } - 559 - { - arrow = 1; - title = "Horizontal Red Spring"; - sprite = "SSWRD2D8"; - width = 16; - height = 32; - } - 560 - { - arrow = 1; - title = "Horizontal Blue Spring"; - sprite = "SSWBD2D8"; - width = 16; - height = 32; - } - 1134 - { - title = "Yellow Spring Ball"; - sprite = "YSPBA0"; - width = 17; - height = 34; - } - 1135 - { - title = "Red Spring Ball"; - sprite = "RSPBA0"; - width = 17; - height = 34; - } - 544 - { - arrow = 1; - title = "Yellow Boost Panel"; - sprite = "BSTYA0"; - width = 28; - height = 2; - } - 545 - { - arrow = 1; - title = "Red Boost Panel"; - sprite = "BSTRA0"; - width = 28; - height = 2; - } -} -patterns -{ - color = 5; // Magenta - arrow = 1; - title = "Special Placement Patterns"; - width = 16; - height = 384; - sprite = "RINGA0"; + 540 + { + title = "Fan"; + sprite = "FANSA0D0"; + width = 16; + height = 8; + } + 541 + { + title = "Gas Jet"; + sprite = "STEMD0"; + width = 32; + } + 542 + { + title = "Bumper"; + sprite = "BUMPA0"; + width = 32; + height = 64; + } + 543 + { + title = "Balloon"; + sprite = "BLONA0"; + width = 32; + height = 64; + } + 550 + { + title = "Yellow Spring"; + sprite = "SPRYA0"; + } + 551 + { + title = "Red Spring"; + sprite = "SPRRA0"; + } + 552 + { + title = "Blue Spring"; + sprite = "SPRBA0"; + } + 555 + { + arrow = 1; + title = "Diagonal Yellow Spring"; + sprite = "YSPRD2"; + width = 16; + } + 556 + { + arrow = 1; + title = "Diagonal Red Spring"; + sprite = "RSPRD2"; + width = 16; + } + 557 + { + arrow = 1; + title = "Diagonal Blue Spring"; + sprite = "BSPRD2"; + width = 16; + } + 558 + { + arrow = 1; + title = "Horizontal Yellow Spring"; + sprite = "SSWYD2D8"; + width = 16; + height = 32; + } + 559 + { + arrow = 1; + title = "Horizontal Red Spring"; + sprite = "SSWRD2D8"; + width = 16; + height = 32; + } + 560 + { + arrow = 1; + title = "Horizontal Blue Spring"; + sprite = "SSWBD2D8"; + width = 16; + height = 32; + } + 1134 + { + title = "Yellow Spring Ball"; + sprite = "YSPBA0"; + width = 17; + height = 34; + } + 1135 + { + title = "Red Spring Ball"; + sprite = "RSPBA0"; + width = 17; + height = 34; + } + 544 + { + arrow = 1; + title = "Yellow Boost Panel"; + sprite = "BSTYA0"; + width = 28; + height = 2; + } + 545 + { + arrow = 1; + title = "Red Boost Panel"; + sprite = "BSTRA0"; + width = 28; + height = 2; + } + } - 600 + patterns { - arrow = 0; - title = "5 Vertical Rings (Yellow Spring)"; + color = 5; // Magenta + arrow = 1; + title = "Special Placement Patterns"; + width = 16; + height = 384; sprite = "RINGA0"; - } - 601 - { - arrow = 0; - title = "5 Vertical Rings (Red Spring)"; - sprite = "RINGA0"; - height = 1024; - } - 602 - { - title = "5 Diagonal Rings (Yellow Spring)"; - sprite = "RINGA0"; - height = 32; - } - 603 - { - title = "10 Diagonal Rings (Red Spring)"; - sprite = "RINGA0"; - height = 32; - } - 604 - { - title = "Circle of Rings"; - sprite = "RINGA0"; - width = 96; - height = 192; - } - 605 - { - title = "Circle of Rings (Big)"; - sprite = "RINGA0"; - width = 192; - } - 606 - { - title = "Circle of Blue Spheres"; - sprite = "SPHRA0"; - width = 96; - height = 192; - } - 607 - { - title = "Circle of Blue Spheres (Big)"; - sprite = "SPHRA0"; - width = 192; - } - 608 - { - title = "Circle of Rings and Spheres"; - sprite = "SPHRA0"; - width = 96; - height = 192; - 609 - { - title = "Circle of Rings and Spheres (Big)"; - sprite = "SPHRA0"; - width = 192; - } -} -invisible -{ - color = 15; // White - title = "Misc. Invisible"; - width = 0; - height = 0; - sprite = "UNKNA0"; - sort = 1; - fixedsize = true; - blocking = 0; - - 700 - { - title = "Water Ambience A (Large)"; - sprite = "internal:ambiance"; + 600 + { + arrow = 0; + title = "5 Vertical Rings (Yellow Spring)"; + sprite = "RINGA0"; + } + 601 + { + arrow = 0; + title = "5 Vertical Rings (Red Spring)"; + sprite = "RINGA0"; + height = 1024; + } + 602 + { + title = "5 Diagonal Rings (Yellow Spring)"; + sprite = "RINGA0"; + height = 32; + } + 603 + { + title = "10 Diagonal Rings (Red Spring)"; + sprite = "RINGA0"; + height = 32; + } + 604 + { + title = "Circle of Rings"; + sprite = "RINGA0"; + width = 96; + height = 192; + } + 605 + { + title = "Circle of Rings (Big)"; + sprite = "RINGA0"; + width = 192; + } + 606 + { + title = "Circle of Blue Spheres"; + sprite = "SPHRA0"; + width = 96; + height = 192; + } + 607 + { + title = "Circle of Blue Spheres (Big)"; + sprite = "SPHRA0"; + width = 192; + } + 608 + { + title = "Circle of Rings and Spheres"; + sprite = "SPHRA0"; + width = 96; + height = 192; + } + 609 + { + title = "Circle of Rings and Spheres (Big)"; + sprite = "SPHRA0"; + width = 192; + } } - 701 + invisible { - title = "Water Ambience B (Large)"; - sprite = "internal:ambiance"; + color = 15; // White + title = "Misc. Invisible"; + width = 0; + height = 0; + sprite = "UNKNA0"; + sort = 1; + fixedsize = true; + blocking = 0; + + 700 + { + title = "Water Ambience A (Large)"; + sprite = "internal:ambiance"; + } + + 701 + { + title = "Water Ambience B (Large)"; + sprite = "internal:ambiance"; + } + + 702 + { + title = "Water Ambience C (Medium)"; + sprite = "internal:ambiance"; + } + + 703 + { + title = "Water Ambience D (Medium)"; + sprite = "internal:ambiance"; + } + + 704 + { + title = "Water Ambience E (Small)"; + sprite = "internal:ambiance"; + } + + 705 + { + title = "Water Ambience F (Small)"; + sprite = "internal:ambiance"; + } + + 706 + { + title = "Water Ambience G (Extra Large)"; + sprite = "internal:ambiance"; + } + + 707 + { + title = "Water Ambience H (Extra Large)"; + sprite = "internal:ambiance"; + } + + 708 + { + title = "Disco Ambience"; + sprite = "internal:ambiance"; + } + + 709 + { + title = "Volcano Ambience"; + sprite = "internal:ambiance"; + } + + 710 + { + title = "Machine Ambience"; + sprite = "internal:ambiance"; + } + + 750 + { + title = "Slope Vertex"; + sprite = "internal:vertexslope"; + } + + 751 + { + arrow = 1; + title = "Teleport Destination"; + sprite = "internal:tele"; + } + + 752 + { + arrow = 1; + title = "Alternate View Point"; + sprite = "internal:view"; + } + + 753 + { + title = "Zoom Tube Waypoint"; + sprite = "internal:zoom"; + } + + 754 + { + title = "Push Point"; + sprite = "GWLGA0"; + } + 755 + { + title = "Pull Point"; + sprite = "GWLRA0"; + } + 756 + { + title = "Blast Linedef Executor"; + sprite = "TOADA0"; + width = 32; + height = 16; + } + 757 + { + title = "Fan Particle Generator"; + sprite = "PRTLA0"; + width = 8; + height = 16; + } + 758 + { + title = "Object Angle Anchor"; + sprite = "internal:view"; + } + 760 + { + title = "PolyObject Anchor"; + sprite = "internal:polyanchor"; + } + 761 + { + title = "PolyObject Spawn Point"; + sprite = "internal:polycenter"; + } + 762 + { + title = "PolyObject Spawn Point (Crush)"; + sprite = "internal:polycentercrush"; + } + 780 + { + title = "Skybox View Point"; + sprite = "internal:skyb"; + } } - 702 + greenflower { - title = "Water Ambience C (Medium)"; - sprite = "internal:ambiance"; + color = 10; // Green + title = "Greenflower"; + + 800 + { + title = "GFZ Flower"; + sprite = "FWR1A0"; + width = 16; + height = 40; + } + 801 + { + title = "Sunflower"; + sprite = "FWR2A0"; + width = 16; + height = 96; + } + 802 + { + title = "Budding Flower"; + sprite = "FWR3A0"; + width = 8; + height = 32; + } + 803 + { + title = "Blueberry Bush"; + sprite = "BUS3A0"; + width = 16; + height = 32; + } + 804 + { + title = "Berry Bush"; + sprite = "BUS1A0"; + width = 16; + height = 32; + } + 805 + { + title = "Bush"; + sprite = "BUS2A0"; + width = 16; + height = 32; + } + 806 + { + title = "GFZ Tree"; + sprite = "TRE1A0"; + width = 20; + height = 128; + } + 807 + { + title = "GFZ Berry Tree"; + sprite = "TRE1B0"; + width = 20; + height = 128; + } + 808 + { + title = "GFZ Cherry Tree"; + sprite = "TRE1C0"; + width = 20; + height = 128; + } + 809 + { + title = "Checkered Tree"; + sprite = "TRE2A0"; + width = 20; + height = 200; + } + 810 + { + title = "Checkered Tree (Sunset)"; + sprite = "TRE2B0"; + width = 20; + height = 200; + } + 811 + { + title = "Polygon Tree"; + sprite = "TRE4A0"; + width = 20; + height = 200; + } + 812 + { + title = "Bush Tree"; + sprite = "TRE5A0"; + width = 20; + height = 200; + } + 813 + { + title = "Red Bush Tree"; + sprite = "TRE5B0"; + width = 20; + height = 200; + } } - 703 + technohill { - title = "Water Ambience D (Medium)"; - sprite = "internal:ambiance"; + color = 10; // Green + title = "Techno Hill"; + + 900 + { + title = "THZ Steam Flower"; + sprite = "THZPA0"; + width = 8; + height = 32; + } + 901 + { + title = "Alarm"; + sprite = "ALRMA0"; + width = 8; + height = 16; + hangs = 1; + } + 902 + { + title = "THZ Spin Flower (Red)"; + sprite = "FWR5A0"; + width = 16; + height = 64; + } + 903 + { + title = "THZ Spin Flower (Yellow)"; + sprite = "FWR6A0"; + width = 16; + height = 64; + } + 904 + { + arrow = 1; + title = "Whistlebush"; + sprite = "THZTA0"; + width = 16; + height = 64; + } } - 704 + deepsea { - title = "Water Ambience E (Small)"; - sprite = "internal:ambiance"; + color = 10; // Green + title = "Deep Sea"; + + 1000 + { + arrow = 1; + blocking = 2; + title = "Gargoyle"; + sprite = "GARGA1"; + width = 16; + height = 40; + } + 1009 + { + arrow = 1; + blocking = 2; + title = "Gargoyle (Big)"; + sprite = "GARGB1"; + width = 32; + height = 80; + } + 1001 + { + title = "Seaweed"; + sprite = "SEWEA0"; + width = 24; + height = 56; + } + 1002 + { + title = "Dripping Water"; + sprite = "DRIPD0"; + width = 8; + height = 16; + hangs = 1; + } + 1003 + { + title = "Coral (Green)"; + sprite = "CORLA0"; + width = 29; + height = 40; + } + 1004 + { + title = "Coral (Red)"; + sprite = "CORLB0"; + width = 30; + height = 53; + } + 1005 + { + title = "Coral (Orange)"; + sprite = "CORLC0"; + width = 28; + height = 41; + } + 1006 + { + title = "Blue Crystal"; + sprite = "BCRYA1"; + width = 8; + height = 16; + } + 1007 + { + title = "Kelp"; + sprite = "KELPA0"; + width = 16; + height = 292; + } + 1008 + { + title = "Stalagmite (DSZ1)"; + sprite = "DSTGA0"; + width = 8; + height = 116; + } + 1010 + { + arrow = 1; + title = "Light Beam"; + sprite = "LIBEARAL"; + width = 16; + height = 16; + } + 1011 + { + title = "Stalagmite (DSZ2)"; + sprite = "DSTGA0"; + width = 8; + height = 116; + } + 1012 + { + arrow = 1; + title = "Big Floating Mine"; + width = 28; + height = 56; + sprite = "BMNEA1"; + } + 1013 + { + title = "Animated Kelp"; + sprite = "ALGAA0"; + width = 48; + height = 120; + } + 1014 + { + title = "Large Coral (Brown)"; + sprite = "CORLD0"; + width = 56; + height = 112; + } + 1015 + { + title = "Large Coral (Beige)"; + sprite = "CORLE0"; + width = 56; + height = 112; + } } - 705 + castleeggman { - title = "Water Ambience F (Small)"; - sprite = "internal:ambiance"; + color = 10; // Green + title = "Castle Eggman"; + + 1100 + { + title = "Chain (Decorative)"; + sprite = "CHANA0"; + width = 4; + height = 128; + hangs = 1; + } + 1101 + { + title = "Torch"; + sprite = "FLAMA0E0"; + width = 8; + height = 32; + } + 1102 + { + arrow = 1; + blocking = 2; + title = "Eggman Statue"; + sprite = "ESTAA1"; + width = 32; + height = 240; + } + 1103 + { + title = "CEZ Flower"; + sprite = "FWR4A0"; + width = 16; + height = 40; + } + 1104 + { + title = "Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + } + 1105 + { + title = "Chain with Maces Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + } + 1106 + { + title = "Chained Spring Spawnpoint"; + sprite = "YSPBA0"; + width = 17; + height = 34; + } + 1107 + { + title = "Chain Spawnpoint"; + sprite = "BMCHA0"; + width = 17; + height = 34; + } + 1108 + { + arrow = 1; + title = "Hidden Chain Spawnpoint"; + sprite = "internal:chain3"; + width = 17; + height = 34; + } + 1109 + { + title = "Firebar Spawnpoint"; + sprite = "BFBRA0"; + width = 17; + height = 34; + } + 1110 + { + title = "Custom Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + } + 1111 + { + arrow = 1; + blocking = 2; + title = "Crawla Statue"; + sprite = "CSTAA1"; + width = 16; + height = 40; + } + 1112 + { + arrow = 1; + blocking = 2; + title = "Lance-a-Bot Statue"; + sprite = "CBBSA1"; + width = 32; + height = 72; + } + 1114 + { + title = "Pine Tree"; + sprite = "PINEA0"; + width = 16; + height = 628; + } + 1115 + { + title = "CEZ Shrub (Small)"; + sprite = "CEZBA0"; + width = 16; + height = 24; + } + 1116 + { + title = "CEZ Shrub (Large)"; + sprite = "CEZBB0"; + width = 32; + height = 48; + } + 1117 + { + arrow = 1; + title = "Pole Banner (Red)"; + sprite = "BANRA0"; + width = 40; + height = 224; + } + 1118 + { + arrow = 1; + title = "Pole Banner (Blue)"; + sprite = "BANRA0"; + width = 40; + height = 224; + } + 1119 + { + title = "Candle"; + sprite = "CNDLA0"; + width = 8; + height = 48; + } + 1120 + { + title = "Candle Pricket"; + sprite = "CNDLB0"; + width = 8; + height = 176; + } + 1121 + { + title = "Flame Holder"; + sprite = "FLMHA0"; + width = 24; + height = 80; + } + 1122 + { + title = "Fire Torch"; + sprite = "CTRCA0"; + width = 16; + height = 80; + } + 1123 + { + title = "Cannonball Launcher"; + sprite = "internal:cannonball"; + width = 8; + height = 16; + } + 1124 + { + blocking = 2; + title = "Cannonball"; + sprite = "CBLLA0"; + width = 20; + height = 40; + } + 1125 + { + title = "Brambles"; + sprite = "CABRALAR"; + width = 48; + height = 32; + } + 1126 + { + title = "Invisible Lockon Object"; + sprite = "LCKNC0"; + width = 16; + height = 32; + } + 1127 + { + title = "Spectator Eggrobo"; + sprite = "EGR1A1"; + width = 20; + height = 72; + } + 1128 + { + arrow = 1; + title = "Waving Flag (Red)"; + sprite = "CFLGA0"; + width = 8; + height = 208; + } + 1129 + { + arrow = 1; + title = "Waving Flag (Blue)"; + sprite = "CFLGA0"; + width = 8; + height = 208; + } } - 706 + aridcanyon { - title = "Water Ambience G (Extra Large)"; - sprite = "internal:ambiance"; + color = 10; // Green + title = "Arid Canyon"; + + 1200 + { + title = "Tumbleweed (Big)"; + sprite = "BTBLA0"; + width = 24; + height = 48; + } + 1201 + { + title = "Tumbleweed (Small)"; + sprite = "STBLA0"; + width = 12; + height = 24; + } + 1202 + { + arrow = 1; + title = "Rock Spawner"; + sprite = "ROIAA0"; + width = 8; + height = 16; + } + 1203 + { + title = "Tiny Red Flower Cactus"; + sprite = "CACTA0"; + width = 13; + height = 24; + } + 1204 + { + title = "Small Red Flower Cactus"; + sprite = "CACTB0"; + width = 15; + height = 52; + } + 1205 + { + title = "Tiny Blue Flower Cactus"; + sprite = "CACTC0"; + width = 13; + height = 24; + } + 1206 + { + title = "Small Blue Flower Cactus"; + sprite = "CACTD0"; + width = 15; + height = 52; + } + 1207 + { + title = "Prickly Pear"; + sprite = "CACTE0"; + width = 32; + height = 96; + } + 1208 + { + title = "Barrel Cactus"; + sprite = "CACTF0"; + width = 20; + height = 128; + } + 1209 + { + title = "Tall Barrel Cactus"; + sprite = "CACTG0"; + width = 24; + height = 224; + } + 1210 + { + title = "Armed Cactus"; + sprite = "CACTH0"; + width = 24; + height = 256; + } + 1211 + { + title = "Ball Cactus"; + sprite = "CACTI0"; + width = 48; + height = 96; + } + 1212 + { + title = "Caution Sign"; + sprite = "WWSGAR"; + width = 22; + height = 64; + } + 1213 + { + title = "Cacti Sign"; + sprite = "WWS2AR"; + width = 22; + height = 64; + } + 1214 + { + title = "Sharp Turn Sign"; + sprite = "WWS3ALAR"; + width = 16; + height = 192; + } + 1215 + { + title = "Mine Oil Lamp"; + sprite = "OILLA0"; + width = 22; + height = 64; + hangs = 1; + } + 1216 + { + title = "TNT Barrel"; + sprite = "BARRA1"; + width = 24; + height = 63; + } + 1217 + { + title = "TNT Proximity Shell"; + sprite = "REMTA0"; + width = 64; + height = 40; + } + 1218 + { + title = "Dust Devil"; + sprite = "TAZDCR"; + width = 80; + height = 416; + } + 1219 + { + title = "Minecart Spawner"; + sprite = "MCRTCLFR"; + width = 22; + height = 32; + } + 1220 + { + title = "Minecart Stopper"; + sprite = "MCRTIR"; + width = 32; + height = 32; + } + 1221 + { + title = "Minecart Saloon Door"; + sprite = "SALDARAL"; + width = 96; + height = 160; + } + 1222 + { + title = "Train Cameo Spawner"; + sprite = "TRAEBRBL"; + width = 28; + height = 32; + } + 1223 + { + title = "Train Dust Spawner"; + sprite = "ADSTA0"; + width = 4; + height = 4; + } + 1224 + { + title = "Train Steam Spawner"; + sprite = "STEAA0"; + width = 4; + height = 4; + } + 1229 + { + title = "Minecart Switch Point"; + sprite = "internal:zoom"; + width = 8; + height = 16; + } + 1230 + { + title = "Tiny Cactus"; + sprite = "CACTJ0"; + width = 13; + height = 28; + } + 1231 + { + title = "Small Cactus"; + sprite = "CACTK0"; + width = 15; + height = 60; + } } - 707 + redvolcano { - title = "Water Ambience H (Extra Large)"; - sprite = "internal:ambiance"; + color = 10; // Green + title = "Red Volcano"; + + 1300 + { + arrow = 1; + title = "Flame Jet (Horizontal)"; + sprite = "internal:flameh"; + width = 16; + height = 40; + } + 1301 + { + title = "Flame Jet (Vertical)"; + sprite = "internal:flamev"; + width = 16; + height = 40; + } + 1302 + { + title = "Spinning Flame Jet (Counter-Clockwise)"; + sprite = "internal:flame2"; + width = 16; + height = 24; + } + 1303 + { + title = "Spinning Flame Jet (Clockwise)"; + sprite = "internal:flame1"; + width = 16; + height = 24; + } + 1304 + { + title = "Lavafall"; + sprite = "LFALF0"; + width = 30; + height = 32; + } + 1305 + { + title = "Rollout Rock"; + sprite = "PUMIA1A5"; + width = 30; + height = 60; + } + 1306 + { + title = "Big Fern"; + sprite = "JPLAB0"; + width = 32; + height = 48; + } + 1307 + { + title = "Jungle Palm"; + sprite = "JPLAC0"; + width = 32; + height = 48; + } + 1308 + { + title = "Torch Flower"; + sprite = "TFLOA0"; + width = 14; + height = 110; + } + 1309 + { + title = "RVZ1 Wall Vine (Long)"; + sprite = "WVINALAR"; + width = 1; + height = 288; + } + 1310 + { + title = "RVZ1 Wall Vine (Short)"; + sprite = "WVINBLBR"; + width = 1; + height = 288; + } } - 708 + botanicserenity { - title = "Disco Ambience"; - sprite = "internal:ambiance"; - } - - 709 - { - title = "Volcano Ambience"; - sprite = "internal:ambiance"; - } - - 710 - { - title = "Machine Ambience"; - sprite = "internal:ambiance"; - } - - 750 - { - title = "Slope Vertex"; - sprite = "internal:vertexslope"; - } - - 751 - { - arrow = 1; - title = "Teleport Destination"; - sprite = "internal:tele"; - } - - 752 - { - arrow = 1; - title = "Alternate View Point"; - sprite = "internal:view"; - } - - 753 - { - title = "Zoom Tube Waypoint"; - sprite = "internal:zoom"; - } - - 754 - { - title = "Push Point"; - sprite = "GWLGA0"; - } - 755 - { - title = "Pull Point"; - sprite = "GWLRA0"; - } - 756 - { - title = "Blast Linedef Executor"; - sprite = "TOADA0"; - width = 32; - height = 16; - } - 757 - { - title = "Fan Particle Generator"; - sprite = "PRTLA0"; - width = 8; - height = 16; - } - 758 - { - title = "Object Angle Anchor"; - sprite = "internal:view"; - } - 760 - { - title = "PolyObject Anchor"; - sprite = "internal:polyanchor"; - } - 761 - { - title = "PolyObject Spawn Point"; - sprite = "internal:polycenter"; - } - 762 - { - title = "PolyObject Spawn Point (Crush)"; - sprite = "internal:polycentercrush"; - } - 780 - { - title = "Skybox View Point"; - sprite = "internal:skyb"; - } -} - -greenflower -{ - color = 10; // Green - title = "Greenflower"; - - 800 - { - title = "GFZ Flower"; - sprite = "FWR1A0"; - width = 16; - height = 40; - } - 801 - { - title = "Sunflower"; - sprite = "FWR2A0"; - width = 16; - height = 96; - } - 802 - { - title = "Budding Flower"; - sprite = "FWR3A0"; - width = 8; - height = 32; - } - 803 - { - title = "Blueberry Bush"; - sprite = "BUS3A0"; + color = 10; // Green + title = "Botanic Serenity"; width = 16; height = 32; - } - 804 - { - title = "Berry Bush"; - sprite = "BUS1A0"; - width = 16; - height = 32; - } - 805 - { - title = "Bush"; - sprite = "BUS2A0"; - width = 16; - height = 32; - } - 806 - { - title = "GFZ Tree"; - sprite = "TRE1A0"; - width = 20; - height = 128; - } - 807 - { - title = "GFZ Berry Tree"; - sprite = "TRE1B0"; - width = 20; - height = 128; - } - 808 - { - title = "GFZ Cherry Tree"; - sprite = "TRE1C0"; - width = 20; - height = 128; - } - 809 - { - title = "Checkered Tree"; - sprite = "TRE2A0"; - width = 20; - height = 200; - } - 810 - { - title = "Checkered Tree (Sunset)"; - sprite = "TRE2B0"; - width = 20; - height = 200; - } - 811 - { - title = "Polygon Tree"; - sprite = "TRE4A0"; - width = 20; - height = 200; - } - 812 - { - title = "Bush Tree"; - sprite = "TRE5A0"; - width = 20; - height = 200; - } - 813 - { - title = "Red Bush Tree"; - sprite = "TRE5B0"; - width = 20; - height = 200; - } -} - -technohill -{ - color = 10; // Green - title = "Techno Hill"; - - 900 - { - title = "THZ Steam Flower"; - sprite = "THZPA0"; - width = 8; - height = 32; - } - 901 - { - title = "Alarm"; - sprite = "ALRMA0"; - width = 8; - height = 16; - hangs = 1; - } - 902 - { - title = "THZ Spin Flower (Red)"; - sprite = "FWR5A0"; - width = 16; - height = 64; - } - 903 - { - title = "THZ Spin Flower (Yellow)"; - sprite = "FWR6A0"; - width = 16; - height = 64; - } - 904 - { - arrow = 1; - title = "Whistlebush"; - sprite = "THZTA0"; - width = 16; - height = 64; - } -} - -deepsea -{ - color = 10; // Green - title = "Deep Sea"; - - 1000 - { - arrow = 1; - blocking = 2; - title = "Gargoyle"; - sprite = "GARGA1"; - width = 16; - height = 40; - } - 1009 - { - arrow = 1; - blocking = 2; - title = "Gargoyle (Big)"; - sprite = "GARGB1"; - width = 32; - height = 80; - } - 1001 - { - title = "Seaweed"; - sprite = "SEWEA0"; - width = 24; - height = 56; - } - 1002 - { - title = "Dripping Water"; - sprite = "DRIPD0"; - width = 8; - height = 16; - hangs = 1; - } - 1003 - { - title = "Coral (Green)"; - sprite = "CORLA0"; - width = 29; - height = 40; - } - 1004 - { - title = "Coral (Red)"; - sprite = "CORLB0"; - width = 30; - height = 53; - } - 1005 - { - title = "Coral (Orange)"; - sprite = "CORLC0"; - width = 28; - height = 41; - } - 1006 - { - title = "Blue Crystal"; - sprite = "BCRYA1"; - width = 8; - height = 16; - } - 1007 - { - title = "Kelp"; - sprite = "KELPA0"; - width = 16; - height = 292; - } - 1008 - { - title = "Stalagmite (DSZ1)"; - sprite = "DSTGA0"; - width = 8; - height = 116; - } - 1010 - { - arrow = 1; - title = "Light Beam"; - sprite = "LIBEARAL"; - width = 16; - height = 16; - } - 1011 - { - title = "Stalagmite (DSZ2)"; - sprite = "DSTGA0"; - width = 8; - height = 116; - } - 1012 - { - arrow = 1; - title = "Big Floating Mine"; - width = 28; - height = 56; - sprite = "BMNEA1"; - } - 1013 - { - title = "Animated Kelp"; - sprite = "ALGAA0"; - width = 48; - height = 120; - } - 1014 - { - title = "Large Coral (Brown)"; - sprite = "CORLD0"; - width = 56; - height = 112; - } - 1015 - { - title = "Large Coral (Beige)"; - sprite = "CORLE0"; - width = 56; - height = 112; - } -} - -castleeggman -{ - color = 10; // Green - title = "Castle Eggman"; - - 1100 - { - title = "Chain (Decorative)"; - sprite = "CHANA0"; - width = 4; - height = 128; - hangs = 1; - } - 1101 - { - title = "Torch"; - sprite = "FLAMA0E0"; - width = 8; - height = 32; - } - 1102 - { - arrow = 1; - blocking = 2; - title = "Eggman Statue"; - sprite = "ESTAA1"; - width = 32; - height = 240; - } - 1103 - { - title = "CEZ Flower"; - sprite = "FWR4A0"; - width = 16; - height = 40; - } - 1104 - { - title = "Mace Spawnpoint"; - sprite = "SMCEA0"; - width = 17; - height = 34; - } - 1105 - { - title = "Chain with Maces Spawnpoint"; - sprite = "SMCEA0"; - width = 17; - height = 34; - } - 1106 - { - title = "Chained Spring Spawnpoint"; - sprite = "YSPBA0"; - width = 17; - height = 34; - } - 1107 - { - title = "Chain Spawnpoint"; - sprite = "BMCHA0"; - width = 17; - height = 34; - } - 1108 - { - arrow = 1; - title = "Hidden Chain Spawnpoint"; - sprite = "internal:chain3"; - width = 17; - height = 34; - } - 1109 - { - title = "Firebar Spawnpoint"; - sprite = "BFBRA0"; - width = 17; - height = 34; - } - 1110 - { - title = "Custom Mace Spawnpoint"; - sprite = "SMCEA0"; - width = 17; - height = 34; - } - 1111 - { - arrow = 1; - blocking = 2; - title = "Crawla Statue"; - sprite = "CSTAA1"; - width = 16; - height = 40; - } - 1112 - { - arrow = 1; - blocking = 2; - title = "Lance-a-Bot Statue"; - sprite = "CBBSA1"; - width = 32; - height = 72; - } - 1114 - { - title = "Pine Tree"; - sprite = "PINEA0"; - width = 16; - height = 628; - } - 1115 - { - title = "CEZ Shrub (Small)"; - sprite = "CEZBA0"; - width = 16; - height = 24; - } - 1116 - { - title = "CEZ Shrub (Large)"; - sprite = "CEZBB0"; - width = 32; - height = 48; - } - 1117 - { - arrow = 1; - title = "Pole Banner (Red)"; - sprite = "BANRA0"; - width = 40; - height = 224; - } - 1118 - { - arrow = 1; - title = "Pole Banner (Blue)"; - sprite = "BANRA0"; - width = 40; - height = 224; - } - 1119 - { - title = "Candle"; - sprite = "CNDLA0"; - width = 8; - height = 48; - } - 1120 - { - title = "Candle Pricket"; - sprite = "CNDLB0"; - width = 8; - height = 176; - } - 1121 - { - title = "Flame Holder"; - sprite = "FLMHA0"; - width = 24; - height = 80; - } - 1122 - { - title = "Fire Torch"; - sprite = "CTRCA0"; - width = 16; - height = 80; - } - 1123 - { - title = "Cannonball Launcher"; - sprite = "internal:cannonball"; - width = 8; - height = 16; - } - 1124 - { - blocking = 2; - title = "Cannonball"; - sprite = "CBLLA0"; - width = 20; - height = 40; - } - 1125 - { - title = "Brambles"; - sprite = "CABRALAR"; - width = 48; - height = 32; - } - 1126 - { - title = "Invisible Lockon Object"; - sprite = "LCKNC0"; - width = 16; - height = 32; - } - 1127 - { - title = "Spectator Eggrobo"; - sprite = "EGR1A1"; - width = 20; - height = 72; - } - 1128 - { - arrow = 1; - title = "Waving Flag (Red)"; - sprite = "CFLGA0"; - width = 8; - height = 208; - } - 1129 - { - arrow = 1; - title = "Waving Flag (Blue)"; - sprite = "CFLGA0"; - width = 8; - height = 208; - } -} - -aridcanyon -{ - color = 10; // Green - title = "Arid Canyon"; - - 1200 - { - title = "Tumbleweed (Big)"; - sprite = "BTBLA0"; - width = 24; - height = 48; - } - 1201 - { - title = "Tumbleweed (Small)"; - sprite = "STBLA0"; - width = 12; - height = 24; - } - 1202 - { - arrow = 1; - title = "Rock Spawner"; - sprite = "ROIAA0"; - width = 8; - height = 16; - } - 1203 - { - title = "Tiny Red Flower Cactus"; - sprite = "CACTA0"; - width = 13; - height = 24; - } - 1204 - { - title = "Small Red Flower Cactus"; - sprite = "CACTB0"; - width = 15; - height = 52; - } - 1205 - { - title = "Tiny Blue Flower Cactus"; - sprite = "CACTC0"; - width = 13; - height = 24; - } - 1206 - { - title = "Small Blue Flower Cactus"; - sprite = "CACTD0"; - width = 15; - height = 52; - } - 1207 - { - title = "Prickly Pear"; - sprite = "CACTE0"; - width = 32; - height = 96; - } - 1208 - { - title = "Barrel Cactus"; - sprite = "CACTF0"; - width = 20; - height = 128; - } - 1209 - { - title = "Tall Barrel Cactus"; - sprite = "CACTG0"; - width = 24; - height = 224; - } - 1210 - { - title = "Armed Cactus"; - sprite = "CACTH0"; - width = 24; - height = 256; - } - 1211 - { - title = "Ball Cactus"; - sprite = "CACTI0"; - width = 48; - height = 96; - } - 1212 - { - title = "Caution Sign"; - sprite = "WWSGAR"; - width = 22; - height = 64; - } - 1213 - { - title = "Cacti Sign"; - sprite = "WWS2AR"; - width = 22; - height = 64; - } - 1214 - { - title = "Sharp Turn Sign"; - sprite = "WWS3ALAR"; - width = 16; - height = 192; - } - 1215 - { - title = "Mine Oil Lamp"; - sprite = "OILLA0"; - width = 22; - height = 64; - hangs = 1; - } - 1216 - { - title = "TNT Barrel"; - sprite = "BARRA1"; - width = 24; - height = 63; - } - 1217 - { - title = "TNT Proximity Shell"; - sprite = "REMTA0"; - width = 64; - height = 40; - } - 1218 - { - title = "Dust Devil"; - sprite = "TAZDCR"; - width = 80; - height = 416; - } - 1219 - { - title = "Minecart Spawner"; - sprite = "MCRTCLFR"; - width = 22; - height = 32; - } - 1220 - { - title = "Minecart Stopper"; - sprite = "MCRTIR"; - width = 32; - height = 32; - } - 1221 - { - title = "Minecart Saloon Door"; - sprite = "SALDARAL"; - width = 96; - height = 160; - } - 1222 - { - title = "Train Cameo Spawner"; - sprite = "TRAEBRBL"; - width = 28; - height = 32; - } - 1223 - { - title = "Train Dust Spawner"; - sprite = "ADSTA0"; - width = 4; - height = 4; - } - 1224 - { - title = "Train Steam Spawner"; - sprite = "STEAA0"; - width = 4; - height = 4; - } - 1229 - { - title = "Minecart Switch Point"; - sprite = "internal:zoom"; - width = 8; - height = 16; - } - 1230 - { - title = "Tiny Cactus"; - sprite = "CACTJ0"; - width = 13; - height = 28; - } - 1231 - { - title = "Small Cactus"; - sprite = "CACTK0"; - width = 15; - height = 60; - } -} - -redvolcano -{ - color = 10; // Green - title = "Red Volcano"; - - 1300 - { - arrow = 1; - title = "Flame Jet (Horizontal)"; - sprite = "internal:flameh"; - width = 16; - height = 40; - } - 1301 - { - title = "Flame Jet (Vertical)"; - sprite = "internal:flamev"; - width = 16; - height = 40; - } - 1302 - { - title = "Spinning Flame Jet (Counter-Clockwise)"; - sprite = "internal:flame2"; - width = 16; - height = 24; - } - 1303 - { - title = "Spinning Flame Jet (Clockwise)"; - sprite = "internal:flame1"; - width = 16; - height = 24; - } - 1304 - { - title = "Lavafall"; - sprite = "LFALF0"; - width = 30; - height = 32; - } - 1305 - { - title = "Rollout Rock"; - sprite = "PUMIA1A5"; - width = 30; - height = 60; - } - 1306 - { - title = "Big Fern"; - sprite = "JPLAB0"; - width = 32; - height = 48; - } - 1307 - { - title = "Jungle Palm"; - sprite = "JPLAC0"; - width = 32; - height = 48; - } - 1308 - { - title = "Torch Flower"; - sprite = "TFLOA0"; - width = 14; - height = 110; - } - 1309 - { - title = "RVZ1 Wall Vine (Long)"; - sprite = "WVINALAR"; - width = 1; - height = 288; - } - 1310 - { - title = "RVZ1 Wall Vine (Short)"; - sprite = "WVINBLBR"; - width = 1; - height = 288; - } -} - -botanicserenity -{ - color = 10; // Green - title = "Botanic Serenity"; - width = 16; - height = 32; - sprite = "BSZ1A0"; - 1400 - { - title = "Tall Flower (Red)"; sprite = "BSZ1A0"; + 1400 + { + title = "Tall Flower (Red)"; + sprite = "BSZ1A0"; + } + 1401 + { + title = "Tall Flower (Purple)"; + sprite = "BSZ1B0"; + } + 1402 + { + title = "Tall Flower (Blue)"; + sprite = "BSZ1C0"; + } + 1403 + { + title = "Tall Flower (Cyan)"; + sprite = "BSZ1D0"; + } + 1404 + { + title = "Tall Flower (Yellow)"; + sprite = "BSZ1E0"; + } + 1405 + { + title = "Tall Flower (Orange)"; + sprite = "BSZ1F0"; + } + 1410 + { + title = "Medium Flower (Red)"; + sprite = "BSZ2A0"; + } + 1411 + { + title = "Medium Flower (Purple)"; + sprite = "BSZ2B0"; + } + 1412 + { + title = "Medium Flower (Blue)"; + sprite = "BSZ2C0"; + } + 1413 + { + title = "Medium Flower (Cyan)"; + sprite = "BSZ2D0"; + } + 1414 + { + title = "Medium Flower (Yellow)"; + sprite = "BSZ2E0"; + } + 1415 + { + title = "Medium Flower (Orange)"; + sprite = "BSZ2F0"; + } + 1420 + { + title = "Short Flower (Red)"; + sprite = "BSZ3A0"; + } + 1421 + { + title = "Short Flower (Purple)"; + sprite = "BSZ3B0"; + } + 1422 + { + title = "Short Flower (Blue)"; + sprite = "BSZ3C0"; + } + 1423 + { + title = "Short Flower (Cyan)"; + sprite = "BSZ3D0"; + } + 1424 + { + title = "Short Flower (Yellow)"; + sprite = "BSZ3E0"; + } + 1425 + { + title = "Short Flower (Orange)"; + sprite = "BSZ3F0"; + } + 1430 + { + title = "Tulip (Red)"; + sprite = "BST1A0"; + } + 1431 + { + title = "Tulip (Purple)"; + sprite = "BST2A0"; + } + 1432 + { + title = "Tulip (Blue)"; + sprite = "BST3A0"; + } + 1433 + { + title = "Tulip (Cyan)"; + sprite = "BST4A0"; + } + 1434 + { + title = "Tulip (Yellow)"; + sprite = "BST5A0"; + } + 1435 + { + title = "Tulip (Orange)"; + sprite = "BST6A0"; + } + 1440 + { + title = "Cluster (Red)"; + sprite = "BSZ5A0"; + } + 1441 + { + title = "Cluster (Purple)"; + sprite = "BSZ5B0"; + } + 1442 + { + title = "Cluster (Blue)"; + sprite = "BSZ5C0"; + } + 1443 + { + title = "Cluster (Cyan)"; + sprite = "BSZ5D0"; + } + 1444 + { + title = "Cluster (Yellow)"; + sprite = "BSZ5E0"; + } + 1445 + { + title = "Cluster (Orange)"; + sprite = "BSZ5F0"; + } + 1450 + { + title = "Bush (Red)"; + sprite = "BSZ6A0"; + } + 1451 + { + title = "Bush (Purple)"; + sprite = "BSZ6B0"; + } + 1452 + { + title = "Bush (Blue)"; + sprite = "BSZ6C0"; + } + 1453 + { + title = "Bush (Cyan)"; + sprite = "BSZ6D0"; + } + 1454 + { + title = "Bush (Yellow)"; + sprite = "BSZ6E0"; + } + 1455 + { + title = "Bush (Orange)"; + sprite = "BSZ6F0"; + } + 1460 + { + title = "Vine (Red)"; + sprite = "BSZ7A0"; + } + 1461 + { + title = "Vine (Purple)"; + sprite = "BSZ7B0"; + } + 1462 + { + title = "Vine (Blue)"; + sprite = "BSZ7C0"; + } + 1463 + { + title = "Vine (Cyan)"; + sprite = "BSZ7D0"; + } + 1464 + { + title = "Vine (Yellow)"; + sprite = "BSZ7E0"; + } + 1465 + { + title = "Vine (Orange)"; + sprite = "BSZ7F0"; + } + 1470 + { + title = "BSZ Shrub"; + sprite = "BSZ8A0"; + } + 1471 + { + title = "BSZ Clover"; + sprite = "BSZ8B0"; + } + 1473 + { + title = "Palm Tree (Big)"; + width = 16; + height = 160; + sprite = "BSZ8D0"; + } + 1475 + { + title = "Palm Tree (Small)"; + width = 16; + height = 80; + sprite = "BSZ8F0"; + } } - 1401 - { - title = "Tall Flower (Purple)"; - sprite = "BSZ1B0"; - } - 1402 - { - title = "Tall Flower (Blue)"; - sprite = "BSZ1C0"; - } - 1403 - { - title = "Tall Flower (Cyan)"; - sprite = "BSZ1D0"; - } - 1404 - { - title = "Tall Flower (Yellow)"; - sprite = "BSZ1E0"; - } - 1405 - { - title = "Tall Flower (Orange)"; - sprite = "BSZ1F0"; - } - 1410 - { - title = "Medium Flower (Red)"; - sprite = "BSZ2A0"; - } - 1411 - { - title = "Medium Flower (Purple)"; - sprite = "BSZ2B0"; - } - 1412 - { - title = "Medium Flower (Blue)"; - sprite = "BSZ2C0"; - } - 1413 - { - title = "Medium Flower (Cyan)"; - sprite = "BSZ2D0"; - } - 1414 - { - title = "Medium Flower (Yellow)"; - sprite = "BSZ2E0"; - } - 1415 - { - title = "Medium Flower (Orange)"; - sprite = "BSZ2F0"; - } - 1420 - { - title = "Short Flower (Red)"; - sprite = "BSZ3A0"; - } - 1421 - { - title = "Short Flower (Purple)"; - sprite = "BSZ3B0"; - } - 1422 - { - title = "Short Flower (Blue)"; - sprite = "BSZ3C0"; - } - 1423 - { - title = "Short Flower (Cyan)"; - sprite = "BSZ3D0"; - } - 1424 - { - title = "Short Flower (Yellow)"; - sprite = "BSZ3E0"; - } - 1425 - { - title = "Short Flower (Orange)"; - sprite = "BSZ3F0"; - } - 1430 - { - title = "Tulip (Red)"; - sprite = "BST1A0"; - } - 1431 - { - title = "Tulip (Purple)"; - sprite = "BST2A0"; - } - 1432 - { - title = "Tulip (Blue)"; - sprite = "BST3A0"; - } - 1433 - { - title = "Tulip (Cyan)"; - sprite = "BST4A0"; - } - 1434 - { - title = "Tulip (Yellow)"; - sprite = "BST5A0"; - } - 1435 - { - title = "Tulip (Orange)"; - sprite = "BST6A0"; - } - 1440 - { - title = "Cluster (Red)"; - sprite = "BSZ5A0"; - } - 1441 - { - title = "Cluster (Purple)"; - sprite = "BSZ5B0"; - } - 1442 - { - title = "Cluster (Blue)"; - sprite = "BSZ5C0"; - } - 1443 - { - title = "Cluster (Cyan)"; - sprite = "BSZ5D0"; - } - 1444 - { - title = "Cluster (Yellow)"; - sprite = "BSZ5E0"; - } - 1445 - { - title = "Cluster (Orange)"; - sprite = "BSZ5F0"; - } - 1450 - { - title = "Bush (Red)"; - sprite = "BSZ6A0"; - } - 1451 - { - title = "Bush (Purple)"; - sprite = "BSZ6B0"; - } - 1452 - { - title = "Bush (Blue)"; - sprite = "BSZ6C0"; - } - 1453 - { - title = "Bush (Cyan)"; - sprite = "BSZ6D0"; - } - 1454 - { - title = "Bush (Yellow)"; - sprite = "BSZ6E0"; - } - 1455 - { - title = "Bush (Orange)"; - sprite = "BSZ6F0"; - } - 1460 - { - title = "Vine (Red)"; - sprite = "BSZ7A0"; - } - 1461 - { - title = "Vine (Purple)"; - sprite = "BSZ7B0"; - } - 1462 - { - title = "Vine (Blue)"; - sprite = "BSZ7C0"; - } - 1463 - { - title = "Vine (Cyan)"; - sprite = "BSZ7D0"; - } - 1464 - { - title = "Vine (Yellow)"; - sprite = "BSZ7E0"; - } - 1465 - { - title = "Vine (Orange)"; - sprite = "BSZ7F0"; - } - 1470 - { - title = "BSZ Shrub"; - sprite = "BSZ8A0"; - } - 1471 - { - title = "BSZ Clover"; - sprite = "BSZ8B0"; - } - 1473 - { - title = "Palm Tree (Big)"; - width = 16; - height = 160; - sprite = "BSZ8D0"; - } - 1475 - { - title = "Palm Tree (Small)"; - width = 16; - height = 80; - sprite = "BSZ8F0"; - } -} -azuretemple -{ - color = 10; // Green - title = "Azure Temple"; + azuretemple + { + color = 10; // Green + title = "Azure Temple"; - 1500 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle"; - sprite = "BGARA1"; - width = 16; - height = 40; + 1500 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle"; + sprite = "BGARA1"; + width = 16; + height = 40; + } + 1501 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle (Up)"; + sprite = "BGARA1"; + width = 16; + height = 40; + } + 1502 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle (Down)"; + sprite = "BGARA1"; + width = 16; + height = 40; + } + 1503 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle (Long)"; + sprite = "BGARA1"; + width = 16; + height = 40; + } + 1504 + { + title = "ATZ Target"; + sprite = "RCRYB0"; + width = 24; + height = 32; + } + 1505 + { + title = "Green Flame"; + sprite = "CFLMA0E0"; + width = 8; + height = 32; + } + 1506 + { + arrow = 1; + blocking = 2; + title = "Blue Gargoyle"; + sprite = "BGARD1"; + width = 16; + height = 40; + } } - 1501 + + dreamhill { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Up)"; - sprite = "BGARA1"; - width = 16; - height = 40; + color = 10; // Green + title = "Dream Hill"; + + 1600 + { + title = "Spring Tree"; + sprite = "TRE6A0"; + width = 16; + height = 32; + } + 1601 + { + title = "Shleep"; + sprite = "SHLPA0"; + width = 24; + height = 32; + } + 1602 + { + title = "Nightopian"; + sprite = "NTPNA1"; + width = 16; + height = 40; + } } - 1502 + + nightstrk { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Down)"; - sprite = "BGARA1"; - width = 16; - height = 40; - } - 1503 - { - arrow = 1; - blocking = 2; - title = "Glaregoyle (Long)"; - sprite = "BGARA1"; - width = 16; - height = 40; - } - 1504 - { - title = "ATZ Target"; - sprite = "RCRYB0"; - width = 24; - height = 32; - } - 1505 - { - title = "Green Flame"; - sprite = "CFLMA0E0"; + color = 13; // Pink + title = "NiGHTS Track"; width = 8; - height = 32; + height = 4096; + sprite = "UNKNA0"; + + 1700 + { + title = "Axis"; + sprite = "internal:axis1"; + circle = 1; + } + 1701 + { + title = "Axis Transfer"; + sprite = "internal:axis2"; + } + 1702 + { + title = "Axis Transfer Line"; + sprite = "internal:axis3"; + } + 1710 + { + title = "Ideya Capture"; + sprite = "CAPSA0"; + width = 72; + height = 144; + } } - 1506 + + nights { - arrow = 1; - blocking = 2; - title = "Blue Gargoyle"; - sprite = "BGARD1"; + color = 13; // Pink + title = "NiGHTS Items"; + width = 16; + height = 32; + + 1703 + { + title = "Ideya Drone"; + sprite = "NDRNA1"; + width = 16; + height = 56; + } + 1704 + { + arrow = 1; + title = "NiGHTS Bumper"; + sprite = "NBMPG3G7"; + width = 32; + height = 64; + } + 1705 + { + arrow = 1; + title = "Hoop (Generic)"; + sprite = "HOOPA0"; + width = 80; + height = 160; + } + 1706 + { + title = "Blue Sphere"; + sprite = "SPHRA0"; + width = 16; + height = 24; + } + 1707 + { + title = "Super Paraloop"; + sprite = "NPRUA0"; + } + 1708 + { + title = "Drill Refill"; + sprite = "NPRUB0"; + } + 1709 + { + title = "Nightopian Helper"; + sprite = "NPRUC0"; + } + 1711 + { + title = "Extra Time"; + sprite = "NPRUD0"; + } + 1712 + { + title = "Link Freeze"; + sprite = "NPRUE0"; + } + 1713 + { + arrow = 1; + title = "Hoop (Customizable)"; + sprite = "HOOPA0"; + width = 80; + height = 160; + } + 1714 + { + title = "Ideya Anchor Point"; + sprite = "internal:axis1"; + width = 8; + height = 16; + } + } + + mario + { + color = 6; // Brown + title = "Mario"; + + 1800 + { + title = "Coin"; + sprite = "COINA0"; + width = 16; + height = 24; + } + 1801 + { + arrow = 1; + title = "Goomba"; + sprite = "GOOMA0"; + width = 24; + height = 32; + } + 1802 + { + arrow = 1; + title = "Goomba (Blue)"; + sprite = "BGOMA0"; + width = 24; + height = 32; + } + 1803 + { + title = "Fire Flower"; + sprite = "FFWRB0"; + width = 16; + height = 32; + } + 1804 + { + title = "Koopa Shell"; + sprite = "SHLLA1"; + width = 16; + height = 20; + } + 1805 + { + title = "Puma (Jumping Fireball)"; + sprite = "PUMAA0"; + width = 8; + height = 16; + } + 1806 + { + title = "King Bowser"; + sprite = "KOOPA0"; + width = 16; + height = 48; + } + 1807 + { + title = "Axe"; + sprite = "MAXEA0"; + width = 8; + height = 16; + } + 1808 + { + title = "Bush (Short)"; + sprite = "MUS1A0"; + width = 16; + height = 32; + } + 1809 + { + title = "Bush (Tall)"; + sprite = "MUS2A0"; + width = 16; + height = 32; + } + 1810 + { + title = "Toad"; + sprite = "TOADA0"; + width = 8; + height = 32; + } + } + + christmasdisco + { + color = 10; // Green + title = "Christmas & Disco"; + + 1850 + { + title = "Christmas Pole"; + sprite = "XMS1A0"; + width = 16; + height = 40; + } + 1851 + { + title = "Candy Cane"; + sprite = "XMS2A0"; + width = 8; + height = 32; + } + 1852 + { + blocking = 2; + title = "Snowman"; + sprite = "XMS3A0"; + width = 16; + height = 64; + } + 1853 + { + blocking = 2; + title = "Snowman (With Hat)"; + sprite = "XMS3B0"; + width = 16; + height = 80; + } + 1854 + { + title = "Lamp Post"; + sprite = "XMS4A0"; + width = 8; + height = 120; + } + 1855 + { + title = "Lamp Post (Snow)"; + sprite = "XMS4B0"; + width = 8; + height = 120; + } + 1856 + { + title = "Hanging Star"; + sprite = "XMS5A0"; + width = 4; + height = 80; + hangs = 1; + } + 1857 + { + title = "Berry Bush (Snow)"; + sprite = "BUS1B0"; + width = 16; + height = 32; + } + 1858 + { + title = "Bush (Snow)"; + sprite = "BUS2B0"; + width = 16; + height = 32; + } + 1859 + { + title = "Blueberry Bush (Snow)"; + sprite = "BUS3B0"; + width = 16; + height = 32; + } + 1875 + { + title = "Disco Ball"; + sprite = "DBALA0"; + width = 16; + height = 54; + hangs = 1; + } + 1876 + { + arrow = 1; + blocking = 2; + title = "Eggman Disco Statue"; + sprite = "ESTAB1"; + width = 20; + height = 96; + } + } + + stalagmites + { + color = 10; // Green + title = "Stalagmites"; width = 16; height = 40; - } -} -dreamhill -{ - color = 10; // Green - title = "Dream Hill"; + 1900 + { + title = "Brown Stalagmite (Tall)"; + sprite = "STLGA0"; + width = 16; + height = 40; + } + 1901 + { + title = "Brown Stalagmite"; + sprite = "STLGB0"; + width = 16; + height = 40; + } + 1902 + { + title = "Orange Stalagmite (Tall)"; + sprite = "STLGC0"; + width = 16; + height = 40; + } + 1903 + { + title = "Orange Stalagmite"; + sprite = "STLGD0"; + width = 16; + height = 40; + } + 1904 + { + title = "Red Stalagmite (Tall)"; + sprite = "STLGE0"; + width = 16; + height = 40; + } + 1905 + { + title = "Red Stalagmite"; + sprite = "STLGF0"; + width = 16; + height = 40; + } + 1906 + { + title = "Gray Stalagmite (Tall)"; + sprite = "STLGG0"; + width = 24; + height = 96; + } + 1907 + { + title = "Gray Stalagmite"; + sprite = "STLGH0"; + width = 16; + height = 40; + } + 1908 + { + title = "Blue Stalagmite (Tall)"; + sprite = "STLGI0"; + width = 16; + height = 40; + } + 1909 + { + title = "Blue Stalagmite"; + sprite = "STLGJ0"; + width = 16; + height = 40; + } + } - 1600 + hauntedheights { - title = "Spring Tree"; - sprite = "TRE6A0"; - width = 16; - height = 32; - } - 1601 - { - title = "Shleep"; - sprite = "SHLPA0"; - width = 24; - height = 32; - } - 1602 - { - title = "Pian"; - sprite = "NTPNALAR"; - width = 16; - height = 32; - } -} + color = 10; // Green + title = "Haunted Heights"; -nightstrk -{ - color = 13; // Pink - title = "NiGHTS Track"; - width = 8; - height = 4096; - sprite = "UNKNA0"; + 2000 + { + title = "Smashing Spikeball"; + sprite = "FMCEA0"; + width = 18; + height = 28; + } + 2001 + { + title = "HHZ Grass"; + sprite = "HHZMA0"; + width = 16; + height = 40; + } + 2002 + { + title = "HHZ Tentacle 1"; + sprite = "HHZMB0"; + width = 16; + height = 40; + } + 2003 + { + title = "HHZ Tentacle 2"; + sprite = "HHZMC0"; + width = 16; + height = 40; + } + 2004 + { + title = "HHZ Stalagmite (Tall)"; + sprite = "HHZME0"; + width = 16; + height = 40; + } + 2005 + { + title = "HHZ Stalagmite (Short)"; + sprite = "HHZMF0"; + width = 16; + height = 40; + } + 2006 + { + title = "Jack-o'-lantern 1"; + sprite = "PUMKA0"; + width = 16; + height = 40; + } + 2007 + { + title = "Jack-o'-lantern 2"; + sprite = "PUMKB0"; + width = 16; + height = 40; + } + 2008 + { + title = "Jack-o'-lantern 3"; + sprite = "PUMKC0"; + width = 16; + height = 40; + } + 2009 + { + title = "Purple Mushroom"; + sprite = "SHRMD0"; + width = 16; + height = 48; + } + 2010 + { + title = "HHZ Tree"; + sprite = "HHPLC0"; + width = 12; + height = 40; + } + } - 1700 + frozenhillside { - title = "Axis"; - sprite = "internal:axis1"; - circle = 1; - } - 1701 - { - title = "Axis Transfer"; - sprite = "internal:axis2"; - } - 1702 - { - title = "Axis Transfer Line"; - sprite = "internal:axis3"; - } - 1710 - { - title = "Ideya Capture"; - sprite = "CAPSA0"; - width = 72; - height = 144; - } -} + color = 10; // Green + title = "Frozen Hillside"; -nights -{ - color = 13; // Pink - title = "NiGHTS Items"; - width = 16; - height = 32; + 2100 + { + title = "Ice Shard (Small)"; + sprite = "FHZIA0"; + width = 8; + height = 32; + } + 2101 + { + title = "Ice Shard (Large)"; + sprite = "FHZIB0"; + width = 8; + height = 32; + } + 2102 + { + title = "Crystal Tree (Aqua)"; + sprite = "TRE3A0"; + width = 20; + height = 200; + } + 2103 + { + title = "Crystal Tree (Pink)"; + sprite = "TRE3B0"; + width = 20; + height = 200; + } + 2104 + { + title = "Amy Cameo"; + sprite = "ROSYA1"; + width = 16; + height = 48; + } + 2105 + { + title = "Mistletoe"; + sprite = "XMS6A0"; + width = 52; + height = 106; + } + } - 1703 + tutorial { - title = "Ideya Drone"; - sprite = "NDRNA1"; - width = 16; - height = 56; + color = 10; // Green + title = "Tutorial"; + + 799 + { + title = "Tutorial Plant"; + sprite = "TUPFH0"; + width = 40; + height = 144; + } } - 1704 + + flickies { - arrow = 1; - title = "NiGHTS Bumper"; - sprite = "NBMPG3G7"; - width = 32; - height = 64; - } - 1705 - { - arrow = 1; - title = "Hoop (Generic)"; - sprite = "HOOPA0"; - width = 80; - height = 160; - } - 1706 - { - title = "Blue Sphere"; - sprite = "SPHRA0"; - width = 16; - height = 24; - } - 1707 - { - title = "Super Paraloop"; - sprite = "NPRUA0"; - } - 1708 - { - title = "Drill Refill"; - sprite = "NPRUB0"; - } - 1709 - { - title = "Nightopian Helper"; - sprite = "NPRUC0"; - } - 1711 - { - title = "Extra Time"; - sprite = "NPRUD0"; - } - 1712 - { - title = "Link Freeze"; - sprite = "NPRUE0"; - } - 1713 - { - arrow = 1; - title = "Hoop (Customizable)"; - sprite = "HOOPA0"; - width = 80; - height = 160; - } - 1714 - { - title = "Ideya Anchor Point"; - sprite = "internal:axis1"; + color = 10; // Green + title = "Flickies"; width = 8; - height = 16; - } -} - -mario -{ - color = 6; // Brown - title = "Mario"; - - 1800 - { - title = "Coin"; - sprite = "COINA0"; - width = 16; - height = 24; - } - 1801 - { - arrow = 1; - title = "Goomba"; - sprite = "GOOMA0"; - width = 24; - height = 32; - } - 1802 - { - arrow = 1; - title = "Goomba (Blue)"; - sprite = "BGOMA0"; - width = 24; - height = 32; - } - 1803 - { - title = "Fire Flower"; - sprite = "FFWRB0"; - width = 16; - height = 32; - } - 1804 - { - title = "Koopa Shell"; - sprite = "SHLLA1"; - width = 16; height = 20; - } - 1805 - { - title = "Puma (Jumping Fireball)"; - sprite = "PUMAA0"; - width = 8; - height = 16; - } - 1806 - { - title = "King Bowser"; - sprite = "KOOPA0"; - width = 16; - height = 48; - } - 1807 - { - title = "Axe"; - sprite = "MAXEA0"; - width = 8; - height = 16; - } - 1808 - { - title = "Bush (Short)"; - sprite = "MUS1A0"; - width = 16; - height = 32; - } - 1809 - { - title = "Bush (Tall)"; - sprite = "MUS2A0"; - width = 16; - height = 32; - } - 1810 - { - title = "Toad"; - sprite = "TOADA0"; - width = 8; - height = 32; + + 2200 + { + title = "Bluebird"; + sprite = "FL01A1"; + } + 2201 + { + title = "Rabbit"; + sprite = "FL02A1"; + } + 2202 + { + title = "Chicken"; + sprite = "FL03A1"; + } + 2203 + { + title = "Seal"; + sprite = "FL04A1"; + } + 2204 + { + title = "Pig"; + sprite = "FL05A1"; + } + 2205 + { + title = "Chipmunk"; + sprite = "FL06A1"; + } + 2206 + { + title = "Penguin"; + sprite = "FL07A1"; + } + 2207 + { + title = "Fish"; + sprite = "FL08A1"; + } + 2208 + { + title = "Ram"; + sprite = "FL09A1"; + } + 2209 + { + title = "Puffin"; + sprite = "FL10A1"; + } + 2210 + { + title = "Cow"; + sprite = "FL11A1"; + } + 2211 + { + title = "Rat"; + sprite = "FL12A1"; + } + 2212 + { + title = "Bear"; + sprite = "FL13A1"; + } + 2213 + { + title = "Dove"; + sprite = "FL14A1"; + } + 2214 + { + title = "Cat"; + sprite = "FL15A1"; + } + 2215 + { + title = "Canary"; + sprite = "FL16A1"; + } + 2216 + { + title = "Spider"; + sprite = "FS01A1"; + } + 2217 + { + title = "Bat"; + sprite = "FS02A0"; + } } } -christmasdisco +udmf { - color = 10; // Green - title = "Christmas & Disco"; - - 1850 - { - title = "Christmas Pole"; - sprite = "XMS1A0"; - width = 16; - height = 40; - } - 1851 - { - title = "Candy Cane"; - sprite = "XMS2A0"; - width = 8; - height = 32; - } - 1852 - { - blocking = 2; - title = "Snowman"; - sprite = "XMS3A0"; - width = 16; - height = 64; - } - 1853 - { - blocking = 2; - title = "Snowman (With Hat)"; - sprite = "XMS3B0"; - width = 16; - height = 80; - } - 1854 - { - title = "Lamp Post"; - sprite = "XMS4A0"; - width = 8; - height = 120; - } - 1855 - { - title = "Lamp Post (Snow)"; - sprite = "XMS4B0"; - width = 8; - height = 120; - } - 1856 - { - title = "Hanging Star"; - sprite = "XMS5A0"; - width = 4; - height = 80; - hangs = 1; - } - 1857 - { - title = "Berry Bush (Snow)"; - sprite = "BUS1B0"; - width = 16; - height = 32; - } - 1858 - { - title = "Bush (Snow)"; - sprite = "BUS2B0"; - width = 16; - height = 32; - } - 1859 - { - title = "Blueberry Bush (Snow)"; - sprite = "BUS3B0"; - width = 16; - height = 32; - } - 1875 - { - title = "Disco Ball"; - sprite = "DBALA0"; - width = 16; - height = 54; - hangs = 1; - } - 1876 + editor { + color = 15; // White arrow = 1; - blocking = 2; - title = "Eggman Disco Statue"; - sprite = "ESTAB1"; - width = 20; - height = 96; - } -} + title = ""; + error = -1; + width = 8; + height = 16; + sort = 1; -stalagmites -{ - color = 10; // Green - title = "Stalagmites"; - width = 16; - height = 40; + 3328 = "3D Mode Start"; + } - 1900 + starts { - title = "Brown Stalagmite (Tall)"; - sprite = "STLGA0"; + color = 1; // Blue + arrow = 1; + title = "Player Starts"; width = 16; - height = 40; + height = 48; + sprite = "PLAYA0"; + + 1 + { + title = "Player 01 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 2 + { + title = "Player 02 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 3 + { + title = "Player 03 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 4 + { + title = "Player 04 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 5 + { + title = "Player 05 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 6 + { + title = "Player 06 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 7 + { + title = "Player 07 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 8 + { + title = "Player 08 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 9 + { + title = "Player 09 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 10 + { + title = "Player 10 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 11 + { + title = "Player 11 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 12 + { + title = "Player 12 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 13 + { + title = "Player 13 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 14 + { + title = "Player 14 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 15 + { + title = "Player 15 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 16 + { + title = "Player 16 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 17 + { + title = "Player 17 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 18 + { + title = "Player 18 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 19 + { + title = "Player 19 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 20 + { + title = "Player 20 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 21 + { + title = "Player 21 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 22 + { + title = "Player 22 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 23 + { + title = "Player 23 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 24 + { + title = "Player 24 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 25 + { + title = "Player 25 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 26 + { + title = "Player 26 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 27 + { + title = "Player 27 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 28 + { + title = "Player 28 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 29 + { + title = "Player 29 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 30 + { + title = "Player 30 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 31 + { + title = "Player 31 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 32 + { + title = "Player 32 Start"; + sprite = "PLAYA0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 33 + { + title = "Match Start"; + sprite = "NDRNA2A8"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 34 + { + title = "CTF Red Team Start"; + sprite = "SIGNG0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } + 35 + { + title = "CTF Blue Team Start"; + sprite = "SIGNE0"; + arg0 + { + title = "Spawn on ceiling?"; + type = 11; + enum = "noyes"; + } + } } - 1901 + + enemies { - title = "Brown Stalagmite"; - sprite = "STLGB0"; - width = 16; - height = 40; + color = 9; // Light_Blue + arrow = 1; + title = "Enemies"; + + 100 + { + title = "Crawla (Blue)"; + sprite = "POSSA1"; + width = 24; + height = 32; + } + 101 + { + title = "Crawla (Red)"; + sprite = "SPOSA1"; + width = 24; + height = 32; + } + 102 + { + title = "Stupid Dumb Unnamed RoboFish"; + sprite = "FISHA0"; + width = 8; + height = 28; + arg0 + { + title = "Jump strength"; + } + } + 103 + { + title = "Buzz (Gold)"; + sprite = "BUZZA1"; + width = 28; + height = 40; + arg0 + { + title = "Can move?"; + type = 11; + enum = "yesno"; + } + } + 104 + { + title = "Buzz (Red)"; + sprite = "RBUZA1"; + width = 28; + height = 40; + arg0 + { + title = "Can move?"; + type = 11; + enum = "yesno"; + } + } + 108 + { + title = "Deton"; + sprite = "DETNA1"; + width = 20; + height = 32; + } + 110 + { + title = "Turret"; + sprite = "TRETA1"; + width = 16; + height = 32; + arg0 + { + title = "Death trigger tag"; + type = 15; + } + } + 111 + { + title = "Pop-up Turret"; + sprite = "TURRI1"; + width = 12; + height = 64; + arg0 + { + title = "Firing delay"; + } + } + 122 + { + title = "Spring Shell (Green)"; + sprite = "SSHLA1"; + width = 24; + height = 40; + } + 125 + { + title = "Spring Shell (Yellow)"; + sprite = "SSHLI1"; + width = 24; + height = 40; + } + 109 + { + title = "Skim"; + sprite = "SKIMA1"; + width = 16; + height = 24; + } + 113 + { + title = "Jet Jaw"; + sprite = "JJAWA3A7"; + width = 12; + height = 20; + } + 126 + { + title = "Crushstacean"; + sprite = "CRABA0"; + width = 24; + height = 32; + arg0 + { + title = "Spawn direction"; + type = 11; + enum + { + 0 = "Right"; + 1 = "Left"; + } + } + } + 138 + { + title = "Banpyura"; + sprite = "CR2BA0"; + width = 24; + height = 32; + arg0 + { + title = "Spawn direction"; + type = 11; + enum + { + 0 = "Right"; + 1 = "Left"; + } + } + } + 117 + { + title = "Robo-Hood"; + sprite = "ARCHA1"; + width = 24; + height = 32; + arg0 + { + title = "Can jump?"; + type = 11; + enum = "yesno"; + } + } + 118 + { + title = "Lance-a-Bot"; + sprite = "CBFSA1"; + width = 32; + height = 72; + } + 1113 + { + title = "Suspicious Lance-a-Bot Statue"; + sprite = "CBBSA1"; + width = 32; + height = 72; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 119 + { + title = "Egg Guard"; + sprite = "ESHIA1"; + width = 16; + height = 48; + arg0 + { + title = "Turn direction"; + type = 11; + enum + { + 0 = "Back"; + 1 = "Right"; + 2 = "Left"; + } + } + arg1 + { + title = "Double speed?"; + type = 11; + enum = "noyes"; + } + } + 115 + { + title = "Bird Aircraft Strike Hazard"; + sprite = "VLTRF1"; + width = 12; + height = 24; + } + 120 + { + title = "Green Snapper"; + sprite = "GSNPA1"; + width = 24; + height = 24; + } + 121 + { + title = "Minus"; + sprite = "MNUSA0"; + width = 24; + height = 32; + } + 134 + { + title = "Canarivore"; + sprite = "CANAA0"; + width = 12; + height = 80; + hangs = 1; + } + 123 + { + title = "Unidus"; + sprite = "UNIDA1"; + width = 18; + height = 36; + } + 135 + { + title = "Pterabyte Spawner"; + sprite = "PTERA2A8"; + width = 16; + height = 16; + arg0 + { + title = "Number of Pterabytes"; + default = 1; + } + } + 136 + { + title = "Pyre Fly"; + sprite = "PYREA0"; + width = 24; + height = 34; + arg0 + { + title = "Start on fire?"; + type = 11; + enum = "noyes"; + } + } + 137 + { + title = "Dragonbomber"; + sprite = "DRABA1"; + width = 28; + height = 48; + } + 105 + { + title = "Jetty-Syn Bomber"; + sprite = "JETBB1"; + width = 20; + height = 50; + arg0 + { + title = "Can move?"; + type = 11; + enum = "yesno"; + } + } + 106 + { + title = "Jetty-Syn Gunner"; + sprite = "JETGB1"; + width = 20; + height = 48; + arg0 + { + title = "Can move?"; + type = 11; + enum = "yesno"; + } + } + 112 + { + title = "Spincushion"; + sprite = "SHRPA1"; + width = 16; + height = 24; + } + 114 + { + title = "Snailer"; + sprite = "SNLRA3A7"; + width = 24; + height = 48; + } + 129 + { + title = "Penguinator"; + sprite = "PENGA1"; + width = 24; + height = 32; + } + 130 + { + title = "Pophat"; + sprite = "POPHA1"; + width = 24; + height = 32; + } + 107 + { + title = "Crawla Commander"; + sprite = "CCOMA1"; + width = 16; + height = 32; + } + 131 + { + title = "Spinbobert"; + sprite = "SBOBB0"; + width = 32; + height = 32; + } + 132 + { + title = "Cacolantern"; + sprite = "CACOA0"; + width = 32; + height = 32; + arg0 + { + title = "Can move?"; + type = 11; + enum = "yesno"; + } + } + 133 + { + title = "Hangster"; + sprite = "HBATC1"; + width = 24; + height = 24; + hangs = 1; + } + 127 + { + title = "Hive Elemental"; + sprite = "HIVEA0"; + width = 32; + height = 80; + arg0 + { + title = "Number of bees"; + } + } + 128 + { + title = "Bumblebore"; + sprite = "BUMBA1"; + width = 16; + height = 32; + arg0 + { + title = "Can move?"; + type = 11; + enum = "yesno"; + } + } + 124 + { + title = "Buggle"; + sprite = "BBUZA1"; + width = 20; + height = 24; + } + 116 + { + title = "Pointy"; + sprite = "PNTYA1"; + width = 8; + height = 16; + } } - 1902 + + bosses { - title = "Orange Stalagmite (Tall)"; - sprite = "STLGC0"; - width = 16; - height = 40; + color = 8; // Dark_Gray + arrow = 1; + title = "Bosses"; + + 200 + { + title = "Egg Mobile"; + sprite = "EGGMA1"; + width = 24; + height = 76; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + } + 201 + { + title = "Egg Slimer"; + sprite = "EGGNA1"; + width = 24; + height = 76; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + arg5 + { + title = "Speed up when hit?"; + type = 11; + enum = "yesno"; + } + } + 202 + { + title = "Sea Egg"; + sprite = "EGGOA1"; + width = 32; + height = 116; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + } + 203 + { + title = "Egg Colosseum"; + sprite = "EGGPA1"; + width = 24; + height = 76; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + arg5 + { + title = "Cage drop trigger tag"; + type = 15; + } + } + 204 + { + title = "Fang"; + sprite = "FANGA1"; + width = 24; + height = 60; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + arg5 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Grayscale"; + 2 = "Skip intro"; + } + } + } + 206 + { + title = "Brak Eggman (Old)"; + sprite = "BRAKB1"; + width = 48; + height = 160; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + arg5 + { + title = "Platform trigger tag"; + type = 15; + } + } + 207 + { + title = "Metal Sonic (Race)"; + sprite = "METLI1"; + width = 16; + height = 48; + arg0 + { + title = "Grayscale?"; + type = 11; + enum = "noyes"; + } + } + 208 + { + title = "Metal Sonic (Battle)"; + sprite = "METLC1"; + width = 16; + height = 48; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + arg5 + { + title = "Grayscale?"; + type = 11; + enum = "noyes"; + } + } + 209 + { + title = "Brak Eggman"; + sprite = "BRAK01"; + width = 48; + height = 160; + arg0 + { + title = "Boss ID"; + } + arg1 + { + title = "End level on death?"; + type = 11; + enum = "noyes"; + } + arg2 + { + title = "Death trigger tag"; + type = 15; + } + arg3 + { + title = "Victory trigger tag"; + type = 15; + } + arg4 + { + title = "Pinch trigger tag"; + type = 15; + } + arg5 + { + title = "Attack trigger tag"; + type = 15; + } + arg6 + { + title = "Flags"; + type = 12; + enum + { + 1 = "No origin-fling death"; + 2 = "Electric barrier"; + } + } + } + 290 + { + arrow = 0; + title = "Boss Escape Point"; + width = 8; + height = 16; + sprite = "internal:eggmanend"; + } + 291 + { + arrow = 0; + title = "Egg Capsule Center"; + width = 8; + height = 16; + sprite = "internal:capsule"; + } + 292 + { + arrow = 0; + title = "Boss Waypoint"; + width = 8; + height = 16; + sprite = "internal:eggmanway"; + arg0 + { + title = "Sea Egg sequence"; + } + arg1 + { + title = "Brak Eggman sequence"; + } + } + 293 + { + title = "Metal Sonic Gather Point"; + sprite = "internal:metal"; + width = 8; + height = 16; + } + 294 + { + title = "Fang Waypoint"; + sprite = "internal:eggmanway"; + width = 8; + height = 16; + arg0 + { + title = "Center waypoint?"; + type = 11; + enum = "noyes"; + } + } } - 1903 + + rings { - title = "Orange Stalagmite"; - sprite = "STLGD0"; - width = 16; - height = 40; - } - 1904 - { - title = "Red Stalagmite (Tall)"; - sprite = "STLGE0"; - width = 16; - height = 40; - } - 1905 - { - title = "Red Stalagmite"; - sprite = "STLGF0"; - width = 16; - height = 40; - } - 1906 - { - title = "Gray Stalagmite (Tall)"; - sprite = "STLGG0"; + color = 14; // Yellow + title = "Rings and Weapon Panels"; width = 24; - height = 96; - } - 1907 - { - title = "Gray Stalagmite"; - sprite = "STLGH0"; - width = 16; - height = 40; - } - 1908 - { - title = "Blue Stalagmite (Tall)"; - sprite = "STLGI0"; - width = 16; - height = 40; - } - 1909 - { - title = "Blue Stalagmite"; - sprite = "STLGJ0"; - width = 16; - height = 40; - } -} + height = 24; + sprite = "RINGA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } -hauntedheights -{ - color = 10; // Green - title = "Haunted Heights"; + 300 + { + title = "Ring"; + sprite = "RINGA0"; + width = 16; + } + 301 + { + title = "Bounce Ring"; + sprite = "internal:RNGBA0"; + } + 302 + { + title = "Rail Ring"; + sprite = "internal:RNGRA0"; + } + 303 + { + title = "Infinity Ring"; + sprite = "internal:RNGIA0"; + } + 304 + { + title = "Automatic Ring"; + sprite = "internal:RNGAA0"; + } + 305 + { + title = "Explosion Ring"; + sprite = "internal:RNGEA0"; + } + 306 + { + title = "Scatter Ring"; + sprite = "internal:RNGSA0"; + } + 307 + { + title = "Grenade Ring"; + sprite = "internal:RNGGA0"; + } + 308 + { + title = "CTF Team Ring (Red)"; + sprite = "internal:RRNGA0"; + width = 16; + } + 309 + { + title = "CTF Team Ring (Blue)"; + sprite = "internal:BRNGA0"; + width = 16; + } + 330 + { + title = "Bounce Ring Panel"; + sprite = "internal:PIKBA0"; + } + 331 + { + title = "Rail Ring Panel"; + sprite = "internal:PIKRA0"; + } + 332 + { + title = "Automatic Ring Panel"; + sprite = "internal:PIKAA0"; + } + 333 + { + title = "Explosion Ring Panel"; + sprite = "internal:PIKEA0"; + } + 334 + { + title = "Scatter Ring Panel"; + sprite = "internal:PIKSA0"; + } + 335 + { + title = "Grenade Ring Panel"; + sprite = "internal:PIKGA0"; + } + } - 2000 + collectibles { - title = "Smashing Spikeball"; - sprite = "FMCEA0"; + color = 10; // Light_Green + title = "Other Collectibles"; + width = 16; + height = 32; + sort = 1; + sprite = "CEMGA0"; + + 310 + { + title = "CTF Red Flag"; + sprite = "RFLGA0"; + width = 24; + height = 64; + } + 311 + { + title = "CTF Blue Flag"; + sprite = "BFLGA0"; + width = 24; + height = 64; + } + 312 + { + title = "Emerald Token"; + sprite = "TOKEA0"; + width = 16; + height = 32; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 313 + { + title = "Chaos Emerald 1 (Green)"; + sprite = "CEMGA0"; + } + 314 + { + title = "Chaos Emerald 2 (Purple)"; + sprite = "CEMGB0"; + } + 315 + { + title = "Chaos Emerald 3 (Blue)"; + sprite = "CEMGC0"; + } + 316 + { + title = "Chaos Emerald 4 (Cyan)"; + sprite = "CEMGD0"; + } + 317 + { + title = "Chaos Emerald 5 (Orange)"; + sprite = "CEMGE0"; + } + 318 + { + title = "Chaos Emerald 6 (Red)"; + sprite = "CEMGF0"; + } + 319 + { + title = "Chaos Emerald 7 (Gray)"; + sprite = "CEMGG0"; + } + 320 + { + title = "Emerald Hunt Location"; + sprite = "SHRDA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 321 + { + title = "Match Chaos Emerald Spawn"; + sprite = "CEMGA0"; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 322 + { + title = "Emblem"; + sprite = "EMBMA0"; + width = 16; + height = 30; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + } + + boxes + { + color = 7; // Gray + blocking = 2; + title = "Monitors"; width = 18; - height = 28; + height = 40; + arg0 + { + title = "Death trigger tag"; + type = 15; + } + + 400 + { + title = "Super Ring (10 Rings)"; + sprite = "TVRIA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 401 + { + title = "Pity Shield"; + sprite = "TVPIA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 402 + { + title = "Attraction Shield"; + sprite = "TVATA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 403 + { + title = "Force Shield"; + sprite = "TVFOA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 404 + { + title = "Armageddon Shield"; + sprite = "TVARA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 405 + { + title = "Whirlwind Shield"; + sprite = "TVWWA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 406 + { + title = "Elemental Shield"; + sprite = "TVELA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 407 + { + title = "Super Sneakers"; + sprite = "TVSSA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 408 + { + title = "Invincibility"; + sprite = "TVIVA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 409 + { + title = "Extra Life"; + sprite = "TV1UA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + arg2 + { + title = "Points"; + type = 11; + enum + { + 0 = "1,000"; + 1 = "10,000"; + } + } + } + 410 + { + title = "Eggman"; + sprite = "TVEGA0"; + } + 411 + { + title = "Teleporter"; + sprite = "TVMXA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 413 + { + title = "Gravity Boots"; + sprite = "TVGVA0"; + } + 414 + { + title = "CTF Team Ring Monitor (Red)"; + sprite = "TRRIA0"; + } + 415 + { + title = "CTF Team Ring Monitor (Blue)"; + sprite = "TBRIA0"; + } + 416 + { + title = "Recycler"; + sprite = "TVRCA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 418 + { + title = "Score (1,000 Points)"; + sprite = "TV1KA0"; + } + 419 + { + title = "Score (10,000 Points)"; + sprite = "TVTKA0"; + } + 420 + { + title = "Flame Shield"; + sprite = "TVFLA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 421 + { + title = "Water Shield"; + sprite = "TVBBA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } + 422 + { + title = "Lightning Shield"; + sprite = "TVZPA0"; + arg1 + { + title = "Respawn behavior"; + type = 11; + enum = "monitorrespawn"; + } + } } - 2001 + + boxes2 { - title = "HHZ Grass"; - sprite = "HHZMA0"; + color = 18; // Gold + blocking = 2; + title = "Monitors (Respawning)"; + width = 20; + height = 44; + arg0 + { + title = "Death trigger tag"; + type = 15; + } + + 431 + { + title = "Pity Shield (Respawn)"; + sprite = "TVPIB0"; + } + 432 + { + title = "Attraction Shield (Respawn)"; + sprite = "TVATB0"; + } + 433 + { + title = "Force Shield (Respawn)"; + sprite = "TVFOB0"; + } + 434 + { + title = "Armageddon Shield (Respawn)"; + sprite = "TVARB0"; + } + 435 + { + title = "Whirlwind Shield (Respawn)"; + sprite = "TVWWB0"; + } + 436 + { + title = "Elemental Shield (Respawn)"; + sprite = "TVELB0"; + } + 437 + { + title = "Super Sneakers (Respawn)"; + sprite = "TVSSB0"; + } + 438 + { + title = "Invincibility (Respawn)"; + sprite = "TVIVB0"; + } + 440 + { + title = "Eggman (Respawn)"; + sprite = "TVEGB0"; + } + 443 + { + title = "Gravity Boots (Respawn)"; + sprite = "TVGVB0"; + } + 450 + { + title = "Flame Shield (Respawn)"; + sprite = "TVFLB0"; + } + 451 + { + title = "Water Shield (Respawn)"; + sprite = "TVBBB0"; + } + 452 + { + title = "Lightning Shield (Respawn)"; + sprite = "TVZPB0"; + } + } + + generic + { + color = 11; // Light_Cyan + title = "Generic Items & Hazards"; + + 500 + { + title = "Air Bubble Patch"; + sprite = "BUBLE0"; + width = 8; + height = 16; + arg0 + { + title = "Distance check?"; + type = 11; + enum = "yesno"; + } + } + 501 + { + title = "Signpost"; + sprite = "SIGND0"; + width = 8; + height = 32; + } + 502 + { + arrow = 1; + title = "Star Post"; + sprite = "STPTA0M0"; + width = 64; + height = 128; + arg0 + { + title = "Order"; + } + arg1 + { + title = "Respawn at center?"; + type = 11; + enum = "noyes"; + } + } + 520 + { + title = "Bomb Sphere"; + sprite = "SPHRD0"; + width = 16; + height = 24; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 521 + { + title = "Spikeball"; + sprite = "SPIKA0"; + width = 12; + height = 8; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 522 + { + title = "Wall Spike"; + sprite = "WSPKALAR"; + width = 16; + height = 14; + arrow = 1; + arg0 + { + title = "Retraction interval"; + } + arg1 + { + title = "Start interval"; + } + arg2 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Start retracted"; + 2 = "Intangible"; + } + } + } + 523 + { + title = "Spike"; + sprite = "USPKA0"; + width = 8; + height = 32; + arg0 + { + title = "Retraction interval"; + } + arg1 + { + title = "Start interval"; + } + arg2 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Start retracted"; + 2 = "Intangible"; + } + } + } + 1130 + { + title = "Small Mace"; + sprite = "SMCEA0"; + width = 17; + height = 34; + } + 1131 + { + title = "Big Mace"; + sprite = "BMCEA0"; + width = 34; + height = 68; + } + 1136 + { + title = "Small Fireball"; + sprite = "SFBRA0"; + width = 17; + height = 34; + } + 1137 + { + title = "Large Fireball"; + sprite = "BFBRA0"; + width = 34; + height = 68; + } + } + + springs + { + color = 12; // Light_Red + title = "Springs and Fans"; + width = 20; + height = 16; + sprite = "RSPRD2"; + + 540 + { + title = "Fan"; + sprite = "FANSA0D0"; + width = 16; + height = 8; + arg0 + { + title = "Lift height"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Invisible"; + 2 = "No distance check"; + } + } + } + 541 + { + title = "Gas Jet"; + sprite = "STEMD0"; + width = 32; + arg0 + { + title = "Play sound?"; + type = 11; + enum = "yesno"; + } + } + 542 + { + title = "Bumper"; + sprite = "BUMPA0"; + width = 32; + height = 64; + } + 543 + { + title = "Balloon"; + sprite = "BLONA0"; + width = 32; + height = 64; + arg0 + { + title = "Respawn?"; + type = 11; + enum = "noyes"; + } + stringarg0 + { + title = "Color"; + } + } + 550 + { + title = "Yellow Spring"; + sprite = "SPRYA0"; + } + 551 + { + title = "Red Spring"; + sprite = "SPRRA0"; + } + 552 + { + title = "Blue Spring"; + sprite = "SPRBA0"; + } + 555 + { + arrow = 1; + title = "Diagonal Yellow Spring"; + sprite = "YSPRD2"; + width = 16; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Ignore gravity"; + 2 = "Rotate 22.5° CCW"; + } + } + } + 556 + { + arrow = 1; + title = "Diagonal Red Spring"; + sprite = "RSPRD2"; + width = 16; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Ignore gravity"; + 2 = "Rotate 22.5° CCW"; + } + } + } + 557 + { + arrow = 1; + title = "Diagonal Blue Spring"; + sprite = "BSPRD2"; + width = 16; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Ignore gravity"; + 2 = "Rotate 22.5° CCW"; + } + } + } + 558 + { + arrow = 1; + title = "Horizontal Yellow Spring"; + sprite = "SSWYD2D8"; + width = 16; + height = 32; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 559 + { + arrow = 1; + title = "Horizontal Red Spring"; + sprite = "SSWRD2D8"; + width = 16; + height = 32; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 560 + { + arrow = 1; + title = "Horizontal Blue Spring"; + sprite = "SSWBD2D8"; + width = 16; + height = 32; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 1134 + { + title = "Yellow Spring Ball"; + sprite = "YSPBA0"; + width = 17; + height = 34; + } + 1135 + { + title = "Red Spring Ball"; + sprite = "RSPBA0"; + width = 17; + height = 34; + } + 544 + { + arrow = 1; + title = "Yellow Boost Panel"; + sprite = "BSTYA0"; + width = 28; + height = 2; + arg0 + { + title = "Force spin?"; + type = 11; + enum = "noyes"; + } + } + 545 + { + arrow = 1; + title = "Red Boost Panel"; + sprite = "BSTRA0"; + width = 28; + height = 2; + arg0 + { + title = "Force spin?"; + type = 11; + enum = "noyes"; + } + } + } + + patterns + { + color = 5; // Magenta + arrow = 1; + title = "Special Placement Patterns"; + width = 16; + height = 384; + sprite = "RINGA0"; + + 600 + { + arrow = 0; + title = "5 Vertical Rings (Yellow Spring)"; + sprite = "RINGA0"; + } + 601 + { + arrow = 0; + title = "5 Vertical Rings (Red Spring)"; + sprite = "RINGA0"; + height = 1024; + } + 602 + { + title = "5 Diagonal Rings (Yellow Spring)"; + sprite = "RINGA0"; + height = 32; + } + 603 + { + title = "10 Diagonal Rings (Red Spring)"; + sprite = "RINGA0"; + height = 32; + } + 604 + { + title = "Circle of Rings"; + sprite = "RINGA0"; + width = 96; + height = 192; + } + 605 + { + title = "Circle of Rings (Big)"; + sprite = "RINGA0"; + width = 192; + } + 606 + { + title = "Circle of Blue Spheres"; + sprite = "SPHRA0"; + width = 96; + height = 192; + } + 607 + { + title = "Circle of Blue Spheres (Big)"; + sprite = "SPHRA0"; + width = 192; + } + 608 + { + title = "Circle of Rings and Spheres"; + sprite = "SPHRA0"; + width = 96; + height = 192; + } + 609 + { + title = "Circle of Rings and Spheres (Big)"; + sprite = "SPHRA0"; + width = 192; + } + 610 + { + title = "Row of Items"; + sprite = "RINGA0"; + arg0 + { + title = "Number of items"; + } + arg1 + { + title = "Horizontal spacing"; + } + arg2 + { + title = "Vertical spacing"; + } + stringarg0 + { + title = "Object types"; + } + } + 611 + { + title = "Circle of Items"; + sprite = "RINGA0"; + width = 96; + height = 192; + arg0 + { + title = "Number of items"; + } + arg1 + { + title = "Radius"; + } + stringarg0 + { + title = "Object types"; + } + } + } + + invisible + { + color = 15; // White + title = "Misc. Invisible"; + width = 0; + height = 0; + sprite = "UNKNA0"; + sort = 1; + fixedsize = true; + blocking = 0; + + 700 + { + title = "Ambient Sound Effect"; + sprite = "internal:ambiance"; + arg0 + { + title = "Repeat speed"; + } + stringarg0 + { + title = "Sound"; + } + } + + 750 + { + title = "Slope Vertex"; + sprite = "internal:vertexslope"; + arg0 + { + title = "Absolute height?"; + type = 11; + enum = "noyes"; + } + } + + 751 + { + arrow = 1; + title = "Teleport Destination"; + sprite = "internal:tele"; + } + + 752 + { + arrow = 1; + title = "Alternate View Point"; + sprite = "internal:view"; + } + + 753 + { + title = "Zoom Tube Waypoint"; + sprite = "internal:zoom"; + arg0 + { + title = "Sequence"; + } + arg1 + { + title = "Order"; + } + } + + 754 + { + title = "Push/Pull Point"; + sprite = "GWLGA0"; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Strength"; + } + arg2 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Fade using XY"; + 2 = "Push using XYZ"; + 4 = "Non-exclusive"; + } + } + } + 756 + { + title = "Blast Linedef Executor"; + sprite = "TOADA0"; + width = 32; + height = 16; + arg0 + { + title = "Linedef tag"; + type = 15; + } + } + 757 + { + title = "Fan Particle Generator"; + sprite = "PRTLA0"; + width = 8; + height = 16; + arg0 + { + title = "Particles"; + } + arg1 + { + title = "Radius"; + } + arg2 + { + title = "Rising speed"; + } + arg3 + { + title = "Rotation speed"; + type = 8; + } + arg4 + { + title = "Spawn interval"; + } + arg5 + { + title = "Rising distance"; + } + arg6 + { + title = "Heights control linedef"; + type = 15; + } + } + 758 + { + title = "Object Angle Anchor"; + sprite = "internal:view"; + } + 760 + { + title = "PolyObject Anchor"; + sprite = "internal:polyanchor"; + } + 761 + { + title = "PolyObject Spawn Point"; + sprite = "internal:polycenter"; + } + 762 + { + title = "PolyObject Spawn Point (Crush)"; + sprite = "internal:polycentercrush"; + } + 780 + { + title = "Skybox View Point"; + sprite = "internal:skyb"; + arg0 + { + title = "Type"; + type = 11; + enum + { + 0 = "Viewpoint"; + 1 = "Centerpoint"; + } + } + } + } + + greenflower + { + color = 10; // Green + title = "Greenflower"; + + 800 + { + title = "GFZ Flower"; + sprite = "FWR1A0"; + width = 16; + height = 40; + } + 801 + { + title = "Sunflower"; + sprite = "FWR2A0"; + width = 16; + height = 96; + } + 802 + { + title = "Budding Flower"; + sprite = "FWR3A0"; + width = 8; + height = 32; + } + 803 + { + title = "Blueberry Bush"; + sprite = "BUS3A0"; + width = 16; + height = 32; + } + 804 + { + title = "Berry Bush"; + sprite = "BUS1A0"; + width = 16; + height = 32; + } + 805 + { + title = "Bush"; + sprite = "BUS2A0"; + width = 16; + height = 32; + } + 806 + { + title = "GFZ Tree"; + sprite = "TRE1A0"; + width = 20; + height = 128; + } + 807 + { + title = "GFZ Berry Tree"; + sprite = "TRE1B0"; + width = 20; + height = 128; + } + 808 + { + title = "GFZ Cherry Tree"; + sprite = "TRE1C0"; + width = 20; + height = 128; + } + 809 + { + title = "Checkered Tree"; + sprite = "TRE2A0"; + width = 20; + height = 200; + } + 810 + { + title = "Checkered Tree (Sunset)"; + sprite = "TRE2B0"; + width = 20; + height = 200; + } + 811 + { + title = "Polygon Tree"; + sprite = "TRE4A0"; + width = 20; + height = 200; + } + 812 + { + title = "Bush Tree"; + sprite = "TRE5A0"; + width = 20; + height = 200; + } + 813 + { + title = "Red Bush Tree"; + sprite = "TRE5B0"; + width = 20; + height = 200; + } + } + + technohill + { + color = 10; // Green + title = "Techno Hill"; + + 900 + { + title = "THZ Steam Flower"; + sprite = "THZPA0"; + width = 8; + height = 32; + } + 901 + { + title = "Alarm"; + sprite = "ALRMA0"; + width = 8; + height = 16; + hangs = 1; + } + 902 + { + title = "THZ Spin Flower (Red)"; + sprite = "FWR5A0"; + width = 16; + height = 64; + } + 903 + { + title = "THZ Spin Flower (Yellow)"; + sprite = "FWR6A0"; + width = 16; + height = 64; + } + 904 + { + arrow = 1; + title = "Whistlebush"; + sprite = "THZTA0"; + width = 16; + height = 64; + } + } + + deepsea + { + color = 10; // Green + title = "Deep Sea"; + + 1000 + { + arrow = 1; + blocking = 2; + title = "Gargoyle"; + sprite = "GARGA1"; + width = 16; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1009 + { + arrow = 1; + blocking = 2; + title = "Gargoyle (Big)"; + sprite = "GARGB1"; + width = 32; + height = 80; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1001 + { + title = "Seaweed"; + sprite = "SEWEA0"; + width = 24; + height = 56; + } + 1002 + { + title = "Dripping Water"; + sprite = "DRIPD0"; + width = 8; + height = 16; + hangs = 1; + arg0 + { + title = "Dripping delay"; + } + } + 1003 + { + title = "Coral (Green)"; + sprite = "CORLA0"; + width = 29; + height = 40; + } + 1004 + { + title = "Coral (Red)"; + sprite = "CORLB0"; + width = 30; + height = 53; + } + 1005 + { + title = "Coral (Orange)"; + sprite = "CORLC0"; + width = 28; + height = 41; + } + 1006 + { + title = "Blue Crystal"; + sprite = "BCRYA1"; + width = 8; + height = 16; + } + 1007 + { + title = "Kelp"; + sprite = "KELPA0"; + width = 16; + height = 292; + arg0 + { + title = "Double size?"; + type = 11; + enum = "noyes"; + } + } + 1008 + { + title = "Stalagmite (DSZ1)"; + sprite = "DSTGA0"; + width = 8; + height = 116; + arg0 + { + title = "Double size?"; + type = 11; + enum = "noyes"; + } + } + 1010 + { + arrow = 1; + title = "Light Beam"; + sprite = "LIBEARAL"; + width = 16; + height = 16; + } + 1011 + { + title = "Stalagmite (DSZ2)"; + sprite = "DSTGA0"; + width = 8; + height = 116; + arg0 + { + title = "Double size?"; + type = 11; + enum = "noyes"; + } + } + 1012 + { + arrow = 1; + title = "Big Floating Mine"; + width = 28; + height = 56; + sprite = "BMNEA1"; + } + 1013 + { + title = "Animated Kelp"; + sprite = "ALGAA0"; + width = 48; + height = 120; + } + 1014 + { + title = "Large Coral (Brown)"; + sprite = "CORLD0"; + width = 56; + height = 112; + } + 1015 + { + title = "Large Coral (Beige)"; + sprite = "CORLE0"; + width = 56; + height = 112; + } + } + + castleeggman + { + color = 10; // Green + title = "Castle Eggman"; + + 1100 + { + title = "Chain (Decorative)"; + sprite = "CHANA0"; + width = 4; + height = 128; + hangs = 1; + } + 1101 + { + title = "Torch"; + sprite = "FLAMA0E0"; + width = 8; + height = 32; + arg0 + { + title = "Corona?"; + type = 11; + enum = "noyes"; + } + } + 1102 + { + arrow = 1; + blocking = 2; + title = "Eggman Statue"; + sprite = "ESTAA1"; + width = 32; + height = 240; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + arg1 + { + title = "Solid gold?"; + type = 11; + enum = "noyes"; + } + } + 1103 + { + title = "CEZ Flower"; + sprite = "FWR4A0"; + width = 16; + height = 40; + } + 1104 + { + title = "Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + arg0 + { + title = "Number of links"; + } + arg1 + { + title = "Number of spokes"; + } + arg2 + { + title = "Width"; + } + arg3 + { + title = "Speed"; + } + arg4 + { + title = "Phase"; + type = 8; + } + arg5 + { + title = "Pinch"; + type = 8; + } + arg6 + { + title = "Omitted spokes"; + } + arg7 + { + title = "Omitted links"; + } + arg8 + { + title = "Flags"; + type = 12; + enum = "maceflags"; + } + } + 1105 + { + title = "Chain with Maces Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + arg0 + { + title = "Number of links"; + } + arg1 + { + title = "Number of spokes"; + } + arg2 + { + title = "Width"; + } + arg3 + { + title = "Speed"; + } + arg4 + { + title = "Phase"; + type = 8; + } + arg5 + { + title = "Pinch"; + type = 8; + } + arg6 + { + title = "Omitted spokes"; + } + arg7 + { + title = "Omitted links"; + } + arg8 + { + title = "Flags"; + type = 12; + enum = "maceflags"; + } + } + 1106 + { + title = "Chained Spring Spawnpoint"; + sprite = "YSPBA0"; + width = 17; + height = 34; + arg0 + { + title = "Number of links"; + } + arg1 + { + title = "Number of spokes"; + } + arg2 + { + title = "Width"; + } + arg3 + { + title = "Speed"; + } + arg4 + { + title = "Phase"; + type = 8; + } + arg5 + { + title = "Pinch"; + type = 8; + } + arg6 + { + title = "Omitted spokes"; + } + arg7 + { + title = "Omitted links"; + } + arg8 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Red spring"; + 2 = "No sounds"; + 4 = "Player-turnable chain"; + 8 = "Swing instead of spin"; + 16 = "Make chain from end item"; + 32 = "Spawn link at origin"; + 64 = "Clip inside ground"; + 128 = "No distance check"; + } + } + } + 1107 + { + title = "Chain Spawnpoint"; + sprite = "BMCHA0"; + width = 17; + height = 34; + arg0 + { + title = "Number of links"; + } + arg1 + { + title = "Number of spokes"; + } + arg2 + { + title = "Width"; + } + arg3 + { + title = "Speed"; + } + arg4 + { + title = "Phase"; + type = 8; + } + arg5 + { + title = "Pinch"; + type = 8; + } + arg6 + { + title = "Omitted spokes"; + } + arg7 + { + title = "Omitted links"; + } + arg8 + { + title = "Flags"; + type = 12; + enum = "maceflags"; + + } + } + 1108 + { + arrow = 1; + title = "Hidden Chain Spawnpoint"; + sprite = "internal:chain3"; + width = 17; + height = 34; + } + 1109 + { + title = "Firebar Spawnpoint"; + sprite = "BFBRA0"; + width = 17; + height = 34; + arg0 + { + title = "Number of links"; + } + arg1 + { + title = "Number of spokes"; + } + arg2 + { + title = "Width"; + } + arg3 + { + title = "Speed"; + } + arg4 + { + title = "Phase"; + type = 8; + } + arg5 + { + title = "Pinch"; + type = 8; + } + arg6 + { + title = "Omitted spokes"; + } + arg7 + { + title = "Omitted links"; + } + arg8 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Double size"; + 2 = "No sounds"; + 4 = "Player-turnable chain"; + 8 = "Swing instead of spin"; + 16 = "Omit chain links"; + 32 = "Spawn link at origin"; + 64 = "Clip inside ground"; + 128 = "No distance check"; + } + } + } + 1110 + { + title = "Custom Mace Spawnpoint"; + sprite = "SMCEA0"; + width = 17; + height = 34; + arg0 + { + title = "Number of links"; + } + arg1 + { + title = "Number of spokes"; + } + arg2 + { + title = "Width"; + } + arg3 + { + title = "Speed"; + } + arg4 + { + title = "Phase"; + type = 8; + } + arg5 + { + title = "Pinch"; + type = 8; + } + arg6 + { + title = "Omitted spokes"; + } + arg7 + { + title = "Omitted links"; + } + arg8 + { + title = "Flags"; + type = 12; + enum = "maceflags"; + } + stringarg0 + { + title = "Mace object type"; + type = 2; + } + stringarg1 + { + title = "Link object type"; + type = 2; + } + } + 1111 + { + arrow = 1; + blocking = 2; + title = "Crawla Statue"; + sprite = "CSTAA1"; + width = 16; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1112 + { + arrow = 1; + blocking = 2; + title = "Lance-a-Bot Statue"; + sprite = "CBBSA1"; + width = 32; + height = 72; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1114 + { + title = "Pine Tree"; + sprite = "PINEA0"; + width = 16; + height = 628; + } + 1115 + { + title = "CEZ Shrub (Small)"; + sprite = "CEZBA0"; + width = 16; + height = 24; + } + 1116 + { + title = "CEZ Shrub (Large)"; + sprite = "CEZBB0"; + width = 32; + height = 48; + } + 1117 + { + arrow = 1; + title = "Pole Banner (Red)"; + sprite = "BANRA0"; + width = 40; + height = 224; + } + 1118 + { + arrow = 1; + title = "Pole Banner (Blue)"; + sprite = "BANRA0"; + width = 40; + height = 224; + } + 1119 + { + title = "Candle"; + sprite = "CNDLA0"; + width = 8; + height = 48; + arg0 + { + title = "Corona?"; + type = 11; + enum = "noyes"; + } + } + 1120 + { + title = "Candle Pricket"; + sprite = "CNDLB0"; + width = 8; + height = 176; + arg0 + { + title = "Corona?"; + type = 11; + enum = "noyes"; + } + } + 1121 + { + title = "Flame Holder"; + sprite = "FLMHA0"; + width = 24; + height = 80; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "No flame"; + 2 = "Add corona"; + } + } + } + 1122 + { + title = "Fire Torch"; + sprite = "CTRCA0"; + width = 16; + height = 80; + } + 1123 + { + title = "Cannonball Launcher"; + sprite = "internal:cannonball"; + width = 8; + height = 16; + } + 1124 + { + blocking = 2; + title = "Cannonball"; + sprite = "CBLLA0"; + width = 20; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1125 + { + title = "Brambles"; + sprite = "CABRALAR"; + width = 48; + height = 32; + } + 1126 + { + title = "Invisible Lockon Object"; + sprite = "LCKNC0"; + width = 16; + height = 32; + } + 1127 + { + title = "Spectator Eggrobo"; + sprite = "EGR1A1"; + width = 20; + height = 72; + arg0 + { + title = "Movement"; + type = 11; + enum + { + 0 = "None"; + 1 = "Right"; + 2 = "Left"; + } + } + } + 1128 + { + arrow = 1; + title = "Waving Flag (Red)"; + sprite = "CFLGA0"; + width = 8; + height = 208; + } + 1129 + { + arrow = 1; + title = "Waving Flag (Blue)"; + sprite = "CFLGA0"; + width = 8; + height = 208; + } + } + + aridcanyon + { + color = 10; // Green + title = "Arid Canyon"; + + 1200 + { + title = "Tumbleweed (Big)"; + sprite = "BTBLA0"; + width = 24; + height = 48; + arg0 + { + title = "Move perpetually?"; + type = 11; + enum = "noyes"; + } + } + 1201 + { + title = "Tumbleweed (Small)"; + sprite = "STBLA0"; + width = 12; + height = 24; + arg0 + { + title = "Move perpetually?"; + type = 11; + enum = "noyes"; + } + } + 1202 + { + arrow = 1; + title = "Rock Spawner"; + sprite = "ROIAA0"; + width = 8; + height = 16; + arg0 + { + title = "Speed"; + } + arg1 + { + title = "Spawn interval"; + } + arg2 + { + title = "Randomize speed?"; + type = 11; + enum = "noyes"; + } + stringarg0 + { + title = "Object type"; + type = 2; + } + } + 1203 + { + title = "Tiny Red Flower Cactus"; + sprite = "CACTA0"; + width = 13; + height = 24; + } + 1204 + { + title = "Small Red Flower Cactus"; + sprite = "CACTB0"; + width = 15; + height = 52; + } + 1205 + { + title = "Tiny Blue Flower Cactus"; + sprite = "CACTC0"; + width = 13; + height = 24; + } + 1206 + { + title = "Small Blue Flower Cactus"; + sprite = "CACTD0"; + width = 15; + height = 52; + } + 1207 + { + title = "Prickly Pear"; + sprite = "CACTE0"; + width = 32; + height = 96; + } + 1208 + { + title = "Barrel Cactus"; + sprite = "CACTF0"; + width = 20; + height = 128; + } + 1209 + { + title = "Tall Barrel Cactus"; + sprite = "CACTG0"; + width = 24; + height = 224; + } + 1210 + { + title = "Armed Cactus"; + sprite = "CACTH0"; + width = 24; + height = 256; + } + 1211 + { + title = "Ball Cactus"; + sprite = "CACTI0"; + width = 48; + height = 96; + } + 1212 + { + title = "Caution Sign"; + sprite = "WWSGAR"; + width = 22; + height = 64; + } + 1213 + { + title = "Cacti Sign"; + sprite = "WWS2AR"; + width = 22; + height = 64; + } + 1214 + { + title = "Sharp Turn Sign"; + sprite = "WWS3ALAR"; + width = 16; + height = 192; + } + 1215 + { + title = "Mine Oil Lamp"; + sprite = "OILLA0"; + width = 22; + height = 64; + hangs = 1; + } + 1216 + { + title = "TNT Barrel"; + sprite = "BARRA1"; + width = 24; + height = 63; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1217 + { + title = "TNT Proximity Shell"; + sprite = "REMTA0"; + width = 64; + height = 40; + } + 1218 + { + title = "Dust Devil"; + sprite = "TAZDCR"; + width = 80; + height = 416; + } + 1219 + { + title = "Minecart Spawner"; + sprite = "MCRTCLFR"; + width = 22; + height = 32; + } + 1220 + { + title = "Minecart Stopper"; + sprite = "MCRTIR"; + width = 32; + height = 32; + } + 1221 + { + title = "Minecart Saloon Door"; + sprite = "SALDARAL"; + width = 96; + height = 160; + arg0 + { + title = "Allow non-minecart players?"; + type = 11; + enum = "noyes"; + } + } + 1222 + { + title = "Train Cameo Spawner"; + sprite = "TRAEBRBL"; + width = 28; + height = 32; + } + 1223 + { + title = "Train Dust Spawner"; + sprite = "ADSTA0"; + width = 4; + height = 4; + } + 1224 + { + title = "Train Steam Spawner"; + sprite = "STEAA0"; + width = 4; + height = 4; + } + 1229 + { + title = "Minecart Switch Point"; + sprite = "internal:zoom"; + width = 8; + height = 16; + arg0 + { + title = "Type"; + type = 11; + enum + { + 0 = "Disable"; + 1 = "Enable"; + } + } + } + 1230 + { + title = "Tiny Cactus"; + sprite = "CACTJ0"; + width = 13; + height = 28; + } + 1231 + { + title = "Small Cactus"; + sprite = "CACTK0"; + width = 15; + height = 60; + } + } + + redvolcano + { + color = 10; // Green + title = "Red Volcano"; + + 1300 + { + arrow = 1; + title = "Flame Jet (Horizontal)"; + sprite = "internal:flameh"; + width = 16; + height = 40; + arg0 + { + title = "On time"; + } + arg1 + { + title = "Off time"; + } + arg2 + { + title = "Strength"; + } + arg3 + { + title = "Waving direction"; + type = 11; + enum + { + 0 = "Horizontal"; + 1 = "Vertical"; + } + } + } + 1301 + { + title = "Flame Jet (Vertical)"; + sprite = "internal:flamev"; + width = 16; + height = 40; + arg0 + { + title = "On time"; + } + arg1 + { + title = "Off time"; + } + arg2 + { + title = "Strength"; + } + arg3 + { + title = "Shooting direction"; + type = 11; + enum + { + 0 = "Upwards"; + 1 = "Downwards"; + } + } + } + 1302 + { + title = "Spinning Flame Jet (Counter-Clockwise)"; + sprite = "internal:flame2"; + width = 16; + height = 24; + } + 1303 + { + title = "Spinning Flame Jet (Clockwise)"; + sprite = "internal:flame1"; + width = 16; + height = 24; + } + 1304 + { + title = "Lavafall"; + sprite = "LFALF0"; + width = 30; + height = 32; + arg0 + { + title = "Initial delay"; + } + arg1 + { + title = "Double size?"; + type = 11; + enum = "noyes"; + } + } + 1305 + { + title = "Rollout Rock"; + sprite = "PUMIA1A5"; + width = 30; + height = 60; + arg0 + { + title = "Buoyant?"; + type = 11; + enum = "yesno"; + } + } + 1306 + { + title = "Big Fern"; + sprite = "JPLAB0"; + width = 32; + height = 48; + } + 1307 + { + title = "Jungle Palm"; + sprite = "JPLAC0"; + width = 32; + height = 48; + } + 1308 + { + title = "Torch Flower"; + sprite = "TFLOA0"; + width = 14; + height = 110; + } + 1309 + { + title = "RVZ1 Wall Vine (Long)"; + sprite = "WVINALAR"; + width = 1; + height = 288; + } + 1310 + { + title = "RVZ1 Wall Vine (Short)"; + sprite = "WVINBLBR"; + width = 1; + height = 288; + } + } + + botanicserenity + { + color = 10; // Green + title = "Botanic Serenity"; + width = 16; + height = 32; + sprite = "BSZ1A0"; + 1400 + { + title = "Tall Flower (Red)"; + sprite = "BSZ1A0"; + } + 1401 + { + title = "Tall Flower (Purple)"; + sprite = "BSZ1B0"; + } + 1402 + { + title = "Tall Flower (Blue)"; + sprite = "BSZ1C0"; + } + 1403 + { + title = "Tall Flower (Cyan)"; + sprite = "BSZ1D0"; + } + 1404 + { + title = "Tall Flower (Yellow)"; + sprite = "BSZ1E0"; + } + 1405 + { + title = "Tall Flower (Orange)"; + sprite = "BSZ1F0"; + } + 1410 + { + title = "Medium Flower (Red)"; + sprite = "BSZ2A0"; + } + 1411 + { + title = "Medium Flower (Purple)"; + sprite = "BSZ2B0"; + } + 1412 + { + title = "Medium Flower (Blue)"; + sprite = "BSZ2C0"; + } + 1413 + { + title = "Medium Flower (Cyan)"; + sprite = "BSZ2D0"; + } + 1414 + { + title = "Medium Flower (Yellow)"; + sprite = "BSZ2E0"; + } + 1415 + { + title = "Medium Flower (Orange)"; + sprite = "BSZ2F0"; + } + 1420 + { + title = "Short Flower (Red)"; + sprite = "BSZ3A0"; + } + 1421 + { + title = "Short Flower (Purple)"; + sprite = "BSZ3B0"; + } + 1422 + { + title = "Short Flower (Blue)"; + sprite = "BSZ3C0"; + } + 1423 + { + title = "Short Flower (Cyan)"; + sprite = "BSZ3D0"; + } + 1424 + { + title = "Short Flower (Yellow)"; + sprite = "BSZ3E0"; + } + 1425 + { + title = "Short Flower (Orange)"; + sprite = "BSZ3F0"; + } + 1430 + { + title = "Tulip (Red)"; + sprite = "BST1A0"; + } + 1431 + { + title = "Tulip (Purple)"; + sprite = "BST2A0"; + } + 1432 + { + title = "Tulip (Blue)"; + sprite = "BST3A0"; + } + 1433 + { + title = "Tulip (Cyan)"; + sprite = "BST4A0"; + } + 1434 + { + title = "Tulip (Yellow)"; + sprite = "BST5A0"; + } + 1435 + { + title = "Tulip (Orange)"; + sprite = "BST6A0"; + } + 1440 + { + title = "Cluster (Red)"; + sprite = "BSZ5A0"; + } + 1441 + { + title = "Cluster (Purple)"; + sprite = "BSZ5B0"; + } + 1442 + { + title = "Cluster (Blue)"; + sprite = "BSZ5C0"; + } + 1443 + { + title = "Cluster (Cyan)"; + sprite = "BSZ5D0"; + } + 1444 + { + title = "Cluster (Yellow)"; + sprite = "BSZ5E0"; + } + 1445 + { + title = "Cluster (Orange)"; + sprite = "BSZ5F0"; + } + 1450 + { + title = "Bush (Red)"; + sprite = "BSZ6A0"; + } + 1451 + { + title = "Bush (Purple)"; + sprite = "BSZ6B0"; + } + 1452 + { + title = "Bush (Blue)"; + sprite = "BSZ6C0"; + } + 1453 + { + title = "Bush (Cyan)"; + sprite = "BSZ6D0"; + } + 1454 + { + title = "Bush (Yellow)"; + sprite = "BSZ6E0"; + } + 1455 + { + title = "Bush (Orange)"; + sprite = "BSZ6F0"; + } + 1460 + { + title = "Vine (Red)"; + sprite = "BSZ7A0"; + } + 1461 + { + title = "Vine (Purple)"; + sprite = "BSZ7B0"; + } + 1462 + { + title = "Vine (Blue)"; + sprite = "BSZ7C0"; + } + 1463 + { + title = "Vine (Cyan)"; + sprite = "BSZ7D0"; + } + 1464 + { + title = "Vine (Yellow)"; + sprite = "BSZ7E0"; + } + 1465 + { + title = "Vine (Orange)"; + sprite = "BSZ7F0"; + } + 1470 + { + title = "BSZ Shrub"; + sprite = "BSZ8A0"; + } + 1471 + { + title = "BSZ Clover"; + sprite = "BSZ8B0"; + } + 1473 + { + title = "Palm Tree (Big)"; + width = 16; + height = 160; + sprite = "BSZ8D0"; + } + 1475 + { + title = "Palm Tree (Small)"; + width = 16; + height = 80; + sprite = "BSZ8F0"; + } + } + + azuretemple + { + color = 10; // Green + title = "Azure Temple"; + + 1500 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle"; + sprite = "BGARA1"; + width = 16; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + arg1 + { + title = "Starting delay"; + } + } + 1501 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle (Up)"; + sprite = "BGARA1"; + width = 16; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + arg1 + { + title = "Starting delay"; + } + } + 1502 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle (Down)"; + sprite = "BGARA1"; + width = 16; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + arg1 + { + title = "Starting delay"; + } + } + 1503 + { + arrow = 1; + blocking = 2; + title = "Glaregoyle (Long)"; + sprite = "BGARA1"; + width = 16; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + arg1 + { + title = "Starting delay"; + } + } + 1504 + { + title = "ATZ Target"; + sprite = "RCRYB0"; + width = 24; + height = 32; + } + 1505 + { + title = "Green Flame"; + sprite = "CFLMA0E0"; + width = 8; + height = 32; + } + 1506 + { + arrow = 1; + blocking = 2; + title = "Blue Gargoyle"; + sprite = "BGARD1"; + width = 16; + height = 40; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + } + + dreamhill + { + color = 10; // Green + title = "Dream Hill"; + + 1600 + { + title = "Spring Tree"; + sprite = "TRE6A0"; + width = 16; + height = 32; + } + 1601 + { + title = "Shleep"; + sprite = "SHLPA0"; + width = 24; + height = 32; + } + 1602 + { + title = "Nightopian"; + sprite = "NTPNA1"; + width = 16; + height = 40; + arg0 + { + title = "Can move?"; + type = 11; + enum = "yesno"; + } + } + } + + nightstrk + { + color = 13; // Pink + title = "NiGHTS Track"; + width = 8; + height = 4096; + sprite = "UNKNA0"; + + 1700 + { + title = "Axis"; + sprite = "internal:axis1"; + circle = 1; + arg0 + { + title = "Mare"; + } + arg1 + { + title = "Order"; + } + arg2 + { + title = "Radius"; + } + arg3 + { + title = "Direction"; + type = 11; + enum + { + 0 = "Clockwise"; + 1 = "Counterclockwise"; + } + } + } + 1701 + { + title = "Axis Transfer"; + sprite = "internal:axis2"; + arg0 + { + title = "Mare"; + } + arg1 + { + title = "Order"; + } + } + 1702 + { + title = "Axis Transfer Line"; + sprite = "internal:axis3"; + arg0 + { + title = "Mare"; + } + arg1 + { + title = "Order"; + } + } + 1710 + { + title = "Ideya Capture"; + sprite = "CAPSA0"; + width = 72; + height = 144; + arg0 + { + title = "Mare"; + } + arg1 + { + title = "Required spheres"; + } + } + } + + nights + { + color = 13; // Pink + title = "NiGHTS Items"; + width = 16; + height = 32; + + 1703 + { + title = "Ideya Drone"; + sprite = "NDRNA1"; + width = 16; + height = 56; + arg0 + { + title = "Time limit"; + } + arg1 + { + title = "Height"; + } + arg2 + { + title = "Radius"; + } + arg3 + { + title = "Alignment"; + type = 11; + enum + { + 0 = "Bottom with offset"; + 1 = "Bottom"; + 2 = "Middle"; + 3 = "Top"; + } + } + arg4 + { + title = "Die upon time up?"; + type = 11; + enum = "noyes"; + } + } + 1704 + { + arrow = 1; + title = "NiGHTS Bumper"; + sprite = "NBMPG3G7"; + width = 32; + height = 64; + } + 1706 + { + title = "Blue Sphere"; + sprite = "SPHRA0"; + width = 16; + height = 24; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 1707 + { + title = "Super Paraloop"; + sprite = "NPRUA0"; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Bonus time only"; + 2 = "Spawn immediately"; + } + } + } + 1708 + { + title = "Drill Refill"; + sprite = "NPRUB0"; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Bonus time only"; + 2 = "Spawn immediately"; + } + } + } + 1709 + { + title = "Nightopian Helper"; + sprite = "NPRUC0"; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Bonus time only"; + 2 = "Spawn immediately"; + } + } + } + 1711 + { + title = "Extra Time"; + sprite = "NPRUD0"; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Bonus time only"; + 2 = "Spawn immediately"; + } + } + } + 1712 + { + title = "Link Freeze"; + sprite = "NPRUE0"; + arg0 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Bonus time only"; + 2 = "Spawn immediately"; + } + } + } + 1713 + { + arrow = 1; + title = "Hoop"; + sprite = "HOOPA0"; + width = 80; + height = 160; + arg0 + { + title = "Radius"; + } + } + 1714 + { + title = "Ideya Anchor Point"; + sprite = "internal:axis1"; + width = 8; + height = 16; + arg0 + { + title = "Mare"; + } + } + } + + mario + { + color = 6; // Brown + title = "Mario"; + + 1800 + { + title = "Coin"; + sprite = "COINA0"; + width = 16; + height = 24; + arg0 + { + title = "Float?"; + type = 11; + enum = "yesno"; + } + } + 1801 + { + arrow = 1; + title = "Goomba"; + sprite = "GOOMA0"; + width = 24; + height = 32; + } + 1802 + { + arrow = 1; + title = "Goomba (Blue)"; + sprite = "BGOMA0"; + width = 24; + height = 32; + } + 1803 + { + title = "Fire Flower"; + sprite = "FFWRB0"; + width = 16; + height = 32; + } + 1804 + { + title = "Koopa Shell"; + sprite = "SHLLA1"; + width = 16; + height = 20; + } + 1805 + { + title = "Puma (Jumping Fireball)"; + sprite = "PUMAA0"; + width = 8; + height = 16; + arg0 + { + title = "Jump strength"; + } + } + 1806 + { + title = "King Bowser"; + sprite = "KOOPA0"; + width = 16; + height = 48; + arg0 + { + title = "Death trigger tag"; + type = 15; + } + } + 1807 + { + title = "Axe"; + sprite = "MAXEA0"; + width = 8; + height = 16; + arg0 + { + title = "Death trigger tag"; + type = 15; + } + } + 1808 + { + title = "Bush (Short)"; + sprite = "MUS1A0"; + width = 16; + height = 32; + } + 1809 + { + title = "Bush (Tall)"; + sprite = "MUS2A0"; + width = 16; + height = 32; + } + 1810 + { + title = "Toad"; + sprite = "TOADA0"; + width = 8; + height = 32; + } + } + + christmasdisco + { + color = 10; // Green + title = "Christmas & Disco"; + + 1850 + { + title = "Christmas Pole"; + sprite = "XMS1A0"; + width = 16; + height = 40; + } + 1851 + { + title = "Candy Cane"; + sprite = "XMS2A0"; + width = 8; + height = 32; + } + 1852 + { + blocking = 2; + title = "Snowman"; + sprite = "XMS3A0"; + width = 16; + height = 64; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1853 + { + blocking = 2; + title = "Snowman (With Hat)"; + sprite = "XMS3B0"; + width = 16; + height = 80; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + 1854 + { + title = "Lamp Post"; + sprite = "XMS4A0"; + width = 8; + height = 120; + } + 1855 + { + title = "Lamp Post (Snow)"; + sprite = "XMS4B0"; + width = 8; + height = 120; + } + 1856 + { + title = "Hanging Star"; + sprite = "XMS5A0"; + width = 4; + height = 80; + hangs = 1; + } + 1857 + { + title = "Berry Bush (Snow)"; + sprite = "BUS1B0"; + width = 16; + height = 32; + } + 1858 + { + title = "Bush (Snow)"; + sprite = "BUS2B0"; + width = 16; + height = 32; + } + 1859 + { + title = "Blueberry Bush (Snow)"; + sprite = "BUS3B0"; + width = 16; + height = 32; + } + 1875 + { + title = "Disco Ball"; + sprite = "DBALA0"; + width = 16; + height = 54; + hangs = 1; + } + 1876 + { + arrow = 1; + blocking = 2; + title = "Eggman Disco Statue"; + sprite = "ESTAB1"; + width = 20; + height = 96; + arg0 + { + title = "Push behavior"; + type = 11; + enum = "pushablebehavior"; + } + } + } + + stalagmites + { + color = 10; // Green + title = "Stalagmites"; width = 16; height = 40; + + 1900 + { + title = "Brown Stalagmite (Tall)"; + sprite = "STLGA0"; + width = 16; + height = 40; + } + 1901 + { + title = "Brown Stalagmite"; + sprite = "STLGB0"; + width = 16; + height = 40; + } + 1902 + { + title = "Orange Stalagmite (Tall)"; + sprite = "STLGC0"; + width = 16; + height = 40; + } + 1903 + { + title = "Orange Stalagmite"; + sprite = "STLGD0"; + width = 16; + height = 40; + } + 1904 + { + title = "Red Stalagmite (Tall)"; + sprite = "STLGE0"; + width = 16; + height = 40; + } + 1905 + { + title = "Red Stalagmite"; + sprite = "STLGF0"; + width = 16; + height = 40; + } + 1906 + { + title = "Gray Stalagmite (Tall)"; + sprite = "STLGG0"; + width = 24; + height = 96; + } + 1907 + { + title = "Gray Stalagmite"; + sprite = "STLGH0"; + width = 16; + height = 40; + } + 1908 + { + title = "Blue Stalagmite (Tall)"; + sprite = "STLGI0"; + width = 16; + height = 40; + } + 1909 + { + title = "Blue Stalagmite"; + sprite = "STLGJ0"; + width = 16; + height = 40; + } } - 2002 + + hauntedheights { - title = "HHZ Tentacle 1"; - sprite = "HHZMB0"; - width = 16; - height = 40; + color = 10; // Green + title = "Haunted Heights"; + + 2000 + { + title = "Smashing Spikeball"; + sprite = "FMCEA0"; + width = 18; + height = 28; + arg0 + { + title = "Initial delay"; + } + } + 2001 + { + title = "HHZ Grass"; + sprite = "HHZMA0"; + width = 16; + height = 40; + } + 2002 + { + title = "HHZ Tentacle 1"; + sprite = "HHZMB0"; + width = 16; + height = 40; + } + 2003 + { + title = "HHZ Tentacle 2"; + sprite = "HHZMC0"; + width = 16; + height = 40; + } + 2004 + { + title = "HHZ Stalagmite (Tall)"; + sprite = "HHZME0"; + width = 16; + height = 40; + } + 2005 + { + title = "HHZ Stalagmite (Short)"; + sprite = "HHZMF0"; + width = 16; + height = 40; + } + 2006 + { + title = "Jack-o'-lantern 1"; + sprite = "PUMKA0"; + width = 16; + height = 40; + arg0 + { + title = "Flicker"; + type = 11; + enum = "yesno"; + } + } + 2007 + { + title = "Jack-o'-lantern 2"; + sprite = "PUMKB0"; + width = 16; + height = 40; + arg0 + { + title = "Flicker"; + type = 11; + enum = "yesno"; + } + } + 2008 + { + title = "Jack-o'-lantern 3"; + sprite = "PUMKC0"; + width = 16; + height = 40; + arg0 + { + title = "Flicker"; + type = 11; + enum = "yesno"; + } + } + 2009 + { + title = "Purple Mushroom"; + sprite = "SHRMD0"; + width = 16; + height = 48; + } + 2010 + { + title = "HHZ Tree"; + sprite = "HHPLC0"; + width = 12; + height = 40; + } } - 2003 + + frozenhillside { - title = "HHZ Tentacle 2"; - sprite = "HHZMC0"; - width = 16; - height = 40; + color = 10; // Green + title = "Frozen Hillside"; + + 2100 + { + title = "Ice Shard (Small)"; + sprite = "FHZIA0"; + width = 8; + height = 32; + } + 2101 + { + title = "Ice Shard (Large)"; + sprite = "FHZIB0"; + width = 8; + height = 32; + } + 2102 + { + title = "Crystal Tree (Aqua)"; + sprite = "TRE3A0"; + width = 20; + height = 200; + } + 2103 + { + title = "Crystal Tree (Pink)"; + sprite = "TRE3B0"; + width = 20; + height = 200; + } + 2104 + { + title = "Amy Cameo"; + sprite = "ROSYA1"; + width = 16; + height = 48; + arg0 + { + title = "Grayscale?"; + type = 11; + enum = "noyes"; + } + } + 2105 + { + title = "Mistletoe"; + sprite = "XMS6A0"; + width = 52; + height = 106; + } } - 2004 + + tutorial { - title = "HHZ Stalagmite (Tall)"; - sprite = "HHZME0"; - width = 16; - height = 40; + color = 10; // Green + title = "Tutorial"; + + 799 + { + title = "Tutorial Plant"; + sprite = "TUPFH0"; + width = 40; + height = 144; + arg0 + { + title = "Start frame"; + } + } } - 2005 + + flickies { - title = "HHZ Stalagmite (Short)"; - sprite = "HHZMF0"; - width = 16; - height = 40; - } - 2006 - { - title = "Jack-o'-lantern 1"; - sprite = "PUMKA0"; - width = 16; - height = 40; - } - 2007 - { - title = "Jack-o'-lantern 2"; - sprite = "PUMKB0"; - width = 16; - height = 40; - } - 2008 - { - title = "Jack-o'-lantern 3"; - sprite = "PUMKC0"; - width = 16; - height = 40; - } - 2009 - { - title = "Purple Mushroom"; - sprite = "SHRMD0"; - width = 16; - height = 48; - } - 2010 - { - title = "HHZ Tree"; - sprite = "HHPLC0"; - width = 12; - height = 40; + color = 10; // Green + title = "Flickies"; + width = 8; + height = 20; + arg0 + { + title = "Radius"; + } + arg1 + { + title = "Flags"; + type = 12; + enum + { + 1 = "Move aimlessly"; + 2 = "No movement"; + 4 = "Hop"; + } + } + + 2200 + { + title = "Bluebird"; + sprite = "FL01A1"; + } + 2201 + { + title = "Rabbit"; + sprite = "FL02A1"; + } + 2202 + { + title = "Chicken"; + sprite = "FL03A1"; + } + 2203 + { + title = "Seal"; + sprite = "FL04A1"; + } + 2204 + { + title = "Pig"; + sprite = "FL05A1"; + } + 2205 + { + title = "Chipmunk"; + sprite = "FL06A1"; + } + 2206 + { + title = "Penguin"; + sprite = "FL07A1"; + } + 2207 + { + title = "Fish"; + sprite = "FL08A1"; + arg2 + { + title = "Color"; + type = 11; + enum + { + 0 = "Random"; + 1 = "Red"; + 2 = "Cyan"; + 3 = "Blue"; + 4 = "Vapor"; + 5 = "Purple"; + 6 = "Bubblegum"; + 7 = "Neon"; + 8 = "Black"; + 9 = "Beige"; + 10 = "Lavender"; + 11 = "Ruby"; + 12 = "Salmon"; + 13 = "Sunset"; + 14 = "Orange"; + 15 = "Yellow"; + } + } + } + 2208 + { + title = "Ram"; + sprite = "FL09A1"; + } + 2209 + { + title = "Puffin"; + sprite = "FL10A1"; + } + 2210 + { + title = "Cow"; + sprite = "FL11A1"; + } + 2211 + { + title = "Rat"; + sprite = "FL12A1"; + } + 2212 + { + title = "Bear"; + sprite = "FL13A1"; + } + 2213 + { + title = "Dove"; + sprite = "FL14A1"; + } + 2214 + { + title = "Cat"; + sprite = "FL15A1"; + } + 2215 + { + title = "Canary"; + sprite = "FL16A1"; + } + 2216 + { + title = "Spider"; + sprite = "FS01A1"; + } + 2217 + { + title = "Bat"; + sprite = "FS02A0"; + } } } - -frozenhillside -{ - color = 10; // Green - title = "Frozen Hillside"; - - 2100 - { - title = "Ice Shard (Small)"; - sprite = "FHZIA0"; - width = 8; - height = 32; - } - 2101 - { - title = "Ice Shard (Large)"; - sprite = "FHZIB0"; - width = 8; - height = 32; - } - 2102 - { - title = "Crystal Tree (Aqua)"; - sprite = "TRE3A0"; - width = 20; - height = 200; - } - 2103 - { - title = "Crystal Tree (Pink)"; - sprite = "TRE3B0"; - width = 20; - height = 200; - } - 2104 - { - title = "Amy Cameo"; - sprite = "ROSYA1"; - width = 16; - height = 48; - } - 2105 - { - title = "Mistletoe"; - sprite = "XMS6A0"; - width = 52; - height = 106; - } -} - -flickies -{ - color = 10; // Green - title = "Flickies"; - width = 8; - height = 20; - - 2200 - { - title = "Bluebird"; - sprite = "FL01A1"; - } - 2201 - { - title = "Rabbit"; - sprite = "FL02A1"; - } - 2202 - { - title = "Chicken"; - sprite = "FL03A1"; - } - 2203 - { - title = "Seal"; - sprite = "FL04A1"; - } - 2204 - { - title = "Pig"; - sprite = "FL05A1"; - } - 2205 - { - title = "Chipmunk"; - sprite = "FL06A1"; - } - 2206 - { - title = "Penguin"; - sprite = "FL07A1"; - } - 2207 - { - title = "Fish"; - sprite = "FL08A1"; - } - 2208 - { - title = "Ram"; - sprite = "FL09A1"; - } - 2209 - { - title = "Puffin"; - sprite = "FL10A1"; - } - 2210 - { - title = "Cow"; - sprite = "FL11A1"; - } - 2211 - { - title = "Rat"; - sprite = "FL12A1"; - } - 2212 - { - title = "Bear"; - sprite = "FL13A1"; - } - 2213 - { - title = "Dove"; - sprite = "FL14A1"; - } - 2214 - { - title = "Cat"; - sprite = "FL15A1"; - } - 2215 - { - title = "Canary"; - sprite = "FL16A1"; - } - 2216 - { - title = "Spider"; - sprite = "FS01A1"; - } - 2217 - { - title = "Bat"; - sprite = "FS02A0"; - } -} \ No newline at end of file diff --git a/extras/conf/udb/SRB2_22Doom.cfg b/extras/conf/udb/SRB2_22Doom.cfg index 891b9d507..9e733aa39 100644 --- a/extras/conf/udb/SRB2_22Doom.cfg +++ b/extras/conf/udb/SRB2_22Doom.cfg @@ -25,12 +25,6 @@ scriptlumpnames include("Includes\\SRB222_misc.cfg", "scriptlumpnames"); } -// THING TYPES -thingtypes -{ - include("Includes\\SRB222_things.cfg"); -} - //Default things filters thingsfilters { diff --git a/extras/conf/udb/SRB2_22UDMF.cfg b/extras/conf/udb/SRB2_22UDMF.cfg index 749cf499a..b6bd22478 100644 --- a/extras/conf/udb/SRB2_22UDMF.cfg +++ b/extras/conf/udb/SRB2_22UDMF.cfg @@ -25,12 +25,6 @@ scriptlumpnames include("Includes\\SRB222_misc.cfg", "scriptlumpnames"); } -// THING TYPES -thingtypes -{ - include("Includes\\SRB222_things.cfg"); -} - //Default things filters thingsfilters { diff --git a/libs/FMOD.props b/libs/FMOD.props deleted file mode 100644 index 785f11ce1..000000000 --- a/libs/FMOD.props +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - $(SolutionDir)libs\fmodex\inc;$(IncludePath) - $(SolutionDir)libs\fmodex\lib;$(LibraryPath) - - - - - fmodexL64_vc.lib;%(AdditionalDependencies) - - - - - fmodexL_vc.lib;%(AdditionalDependencies) - - - - \ No newline at end of file diff --git a/libs/dll-binaries/i686/Old/fmod.dll b/libs/dll-binaries/i686/Old/fmod.dll deleted file mode 100644 index 6b0e379d3..000000000 Binary files a/libs/dll-binaries/i686/Old/fmod.dll and /dev/null differ diff --git a/libs/dll-binaries/i686/Old/fmodexL.dll b/libs/dll-binaries/i686/Old/fmodexL.dll deleted file mode 100644 index 1ac9e21c9..000000000 Binary files a/libs/dll-binaries/i686/Old/fmodexL.dll and /dev/null differ diff --git a/libs/dll-binaries/i686/fmodex.dll b/libs/dll-binaries/i686/fmodex.dll deleted file mode 100644 index 875f8a267..000000000 Binary files a/libs/dll-binaries/i686/fmodex.dll and /dev/null differ diff --git a/libs/dll-binaries/x86_64/Old/fmod64.dll b/libs/dll-binaries/x86_64/Old/fmod64.dll deleted file mode 100644 index 2a8bab284..000000000 Binary files a/libs/dll-binaries/x86_64/Old/fmod64.dll and /dev/null differ diff --git a/libs/dll-binaries/x86_64/Old/fmodexL64.dll b/libs/dll-binaries/x86_64/Old/fmodexL64.dll deleted file mode 100644 index 463628c6e..000000000 Binary files a/libs/dll-binaries/x86_64/Old/fmodexL64.dll and /dev/null differ diff --git a/libs/dll-binaries/x86_64/fmodex64.dll b/libs/dll-binaries/x86_64/fmodex64.dll deleted file mode 100644 index f08c0033b..000000000 Binary files a/libs/dll-binaries/x86_64/fmodex64.dll and /dev/null differ diff --git a/libs/fmodex/inc/fmod.h b/libs/fmodex/inc/fmod.h deleted file mode 100644 index f3fbd853e..000000000 --- a/libs/fmodex/inc/fmod.h +++ /dev/null @@ -1,2462 +0,0 @@ - -/* ============================================================================================ */ -/* FMOD Ex - Main C/C++ header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ -/* */ -/* This header is the base header for all other FMOD headers. If you are programming in C */ -/* use this exclusively, or if you are programming C++ use this in conjunction with FMOD.HPP */ -/* */ -/* ============================================================================================ */ - -#ifndef _FMOD_H -#define _FMOD_H - -/* - FMOD version number. Check this against FMOD::System::getVersion. - 0xaaaabbcc -> aaaa = major version number. bb = minor version number. cc = development version number. -*/ - -#define FMOD_VERSION 0x00044412 - -/* - Compiler specific settings. -*/ - -#if defined(__CYGWIN32__) - #define F_CDECL __cdecl - #define F_STDCALL __stdcall - #define F_DECLSPEC __declspec - #define F_DLLEXPORT ( dllexport ) -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) - #define F_CDECL _cdecl - #define F_STDCALL _stdcall - #define F_DECLSPEC __declspec - #define F_DLLEXPORT ( dllexport ) -#elif defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) - #define F_CDECL - #define F_STDCALL - #define F_DECLSPEC - #define F_DLLEXPORT __attribute__ ((visibility("default"))) -#else - #define F_CDECL - #define F_STDCALL - #define F_DECLSPEC - #define F_DLLEXPORT -#endif - -#ifdef DLL_EXPORTS - #if defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) - #define F_API __attribute__ ((visibility("default"))) - #else - #define F_API __declspec(dllexport) F_STDCALL - #endif -#else - #define F_API F_STDCALL -#endif - -#define F_CALLBACK F_STDCALL - -/* - FMOD types. -*/ - -typedef int FMOD_BOOL; -typedef struct FMOD_SYSTEM FMOD_SYSTEM; -typedef struct FMOD_SOUND FMOD_SOUND; -typedef struct FMOD_CHANNEL FMOD_CHANNEL; -typedef struct FMOD_CHANNELGROUP FMOD_CHANNELGROUP; -typedef struct FMOD_SOUNDGROUP FMOD_SOUNDGROUP; -typedef struct FMOD_REVERB FMOD_REVERB; -typedef struct FMOD_DSP FMOD_DSP; -typedef struct FMOD_DSPCONNECTION FMOD_DSPCONNECTION; -typedef struct FMOD_POLYGON FMOD_POLYGON; -typedef struct FMOD_GEOMETRY FMOD_GEOMETRY; -typedef struct FMOD_SYNCPOINT FMOD_SYNCPOINT; -typedef unsigned int FMOD_MODE; -typedef unsigned int FMOD_TIMEUNIT; -typedef unsigned int FMOD_INITFLAGS; -typedef unsigned int FMOD_CAPS; -typedef unsigned int FMOD_DEBUGLEVEL; -typedef unsigned int FMOD_MEMORY_TYPE; - -/* -[ENUM] -[ - [DESCRIPTION] - error codes. Returned from every function. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] -] -*/ -typedef enum -{ - FMOD_OK, /* No errors. */ - FMOD_ERR_ALREADYLOCKED, /* Tried to call lock a second time before unlock was called. */ - FMOD_ERR_BADCOMMAND, /* Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). */ - FMOD_ERR_CDDA_DRIVERS, /* Neither NTSCSI nor ASPI could be initialised. */ - FMOD_ERR_CDDA_INIT, /* An error occurred while initialising the CDDA subsystem. */ - FMOD_ERR_CDDA_INVALID_DEVICE, /* Couldn't find the specified device. */ - FMOD_ERR_CDDA_NOAUDIO, /* No audio tracks on the specified disc. */ - FMOD_ERR_CDDA_NODEVICES, /* No CD/DVD devices were found. */ - FMOD_ERR_CDDA_NODISC, /* No disc present in the specified drive. */ - FMOD_ERR_CDDA_READ, /* A CDDA read error occurred. */ - FMOD_ERR_CHANNEL_ALLOC, /* Error trying to allocate a channel. */ - FMOD_ERR_CHANNEL_STOLEN, /* The specified channel has been reused to play another sound. */ - FMOD_ERR_COM, /* A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. */ - FMOD_ERR_DMA, /* DMA Failure. See debug output for more information. */ - FMOD_ERR_DSP_CONNECTION, /* DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). */ - FMOD_ERR_DSP_FORMAT, /* DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. */ - FMOD_ERR_DSP_NOTFOUND, /* DSP connection error. Couldn't find the DSP unit specified. */ - FMOD_ERR_DSP_RUNNING, /* DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. */ - FMOD_ERR_DSP_TOOMANYCONNECTIONS,/* DSP connection error. The unit being connected to or disconnected should only have 1 input or output. */ - FMOD_ERR_FILE_BAD, /* Error loading file. */ - FMOD_ERR_FILE_COULDNOTSEEK, /* Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. */ - FMOD_ERR_FILE_DISKEJECTED, /* Media was ejected while reading. */ - FMOD_ERR_FILE_EOF, /* End of file unexpectedly reached while trying to read essential data (truncated data?). */ - FMOD_ERR_FILE_NOTFOUND, /* File not found. */ - FMOD_ERR_FILE_UNWANTED, /* Unwanted file access occured. */ - FMOD_ERR_FORMAT, /* Unsupported file or audio format. */ - FMOD_ERR_HTTP, /* A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. */ - FMOD_ERR_HTTP_ACCESS, /* The specified resource requires authentication or is forbidden. */ - FMOD_ERR_HTTP_PROXY_AUTH, /* Proxy authentication is required to access the specified resource. */ - FMOD_ERR_HTTP_SERVER_ERROR, /* A HTTP server error occurred. */ - FMOD_ERR_HTTP_TIMEOUT, /* The HTTP request timed out. */ - FMOD_ERR_INITIALIZATION, /* FMOD was not initialized correctly to support this function. */ - FMOD_ERR_INITIALIZED, /* Cannot call this command after System::init. */ - FMOD_ERR_INTERNAL, /* An error occured that wasn't supposed to. Contact support. */ - FMOD_ERR_INVALID_ADDRESS, /* On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) */ - FMOD_ERR_INVALID_FLOAT, /* Value passed in was a NaN, Inf or denormalized float. */ - FMOD_ERR_INVALID_HANDLE, /* An invalid object handle was used. */ - FMOD_ERR_INVALID_PARAM, /* An invalid parameter was passed to this function. */ - FMOD_ERR_INVALID_POSITION, /* An invalid seek position was passed to this function. */ - FMOD_ERR_INVALID_SPEAKER, /* An invalid speaker was passed to this function based on the current speaker mode. */ - FMOD_ERR_INVALID_SYNCPOINT, /* The syncpoint did not come from this sound handle. */ - FMOD_ERR_INVALID_VECTOR, /* The vectors passed in are not unit length, or perpendicular. */ - FMOD_ERR_MAXAUDIBLE, /* Reached maximum audible playback count for this sound's soundgroup. */ - FMOD_ERR_MEMORY, /* Not enough memory or resources. */ - FMOD_ERR_MEMORY_CANTPOINT, /* Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. */ - FMOD_ERR_MEMORY_SRAM, /* Not enough memory or resources on console sound ram. */ - FMOD_ERR_NEEDS2D, /* Tried to call a command on a 3d sound when the command was meant for 2d sound. */ - FMOD_ERR_NEEDS3D, /* Tried to call a command on a 2d sound when the command was meant for 3d sound. */ - FMOD_ERR_NEEDSHARDWARE, /* Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). */ - FMOD_ERR_NEEDSSOFTWARE, /* Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. */ - FMOD_ERR_NET_CONNECT, /* Couldn't connect to the specified host. */ - FMOD_ERR_NET_SOCKET_ERROR, /* A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. */ - FMOD_ERR_NET_URL, /* The specified URL couldn't be resolved. */ - FMOD_ERR_NET_WOULD_BLOCK, /* Operation on a non-blocking socket could not complete immediately. */ - FMOD_ERR_NOTREADY, /* Operation could not be performed because specified sound/DSP connection is not ready. */ - FMOD_ERR_OUTPUT_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ - FMOD_ERR_OUTPUT_CREATEBUFFER, /* Error creating hardware sound buffer. */ - FMOD_ERR_OUTPUT_DRIVERCALL, /* A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. */ - FMOD_ERR_OUTPUT_ENUMERATION, /* Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. */ - FMOD_ERR_OUTPUT_FORMAT, /* Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). */ - FMOD_ERR_OUTPUT_INIT, /* Error initializing output device. */ - FMOD_ERR_OUTPUT_NOHARDWARE, /* FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. */ - FMOD_ERR_OUTPUT_NOSOFTWARE, /* Attempted to create a software sound but no software channels were specified in System::init. */ - FMOD_ERR_PAN, /* Panning only works with mono or stereo sound sources. */ - FMOD_ERR_PLUGIN, /* An unspecified error has been returned from a 3rd party plugin. */ - FMOD_ERR_PLUGIN_INSTANCES, /* The number of allowed instances of a plugin has been exceeded. */ - FMOD_ERR_PLUGIN_MISSING, /* A requested output, dsp unit type or codec was not available. */ - FMOD_ERR_PLUGIN_RESOURCE, /* A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) */ - FMOD_ERR_PRELOADED, /* The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. */ - FMOD_ERR_PROGRAMMERSOUND, /* The specified sound is still in use by the event system, wait for the event which is using it finish with it. */ - FMOD_ERR_RECORD, /* An error occured trying to initialize the recording device. */ - FMOD_ERR_REVERB_INSTANCE, /* Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. */ - FMOD_ERR_SUBSOUND_ALLOCATED, /* This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. */ - FMOD_ERR_SUBSOUND_CANTMOVE, /* Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. */ - FMOD_ERR_SUBSOUND_MODE, /* The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. */ - FMOD_ERR_SUBSOUNDS, /* The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. */ - FMOD_ERR_TAGNOTFOUND, /* The specified tag could not be found or there are no tags. */ - FMOD_ERR_TOOMANYCHANNELS, /* The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. */ - FMOD_ERR_UNIMPLEMENTED, /* Something in FMOD hasn't been implemented when it should be! contact support! */ - FMOD_ERR_UNINITIALIZED, /* This command failed because System::init or System::setDriver was not called. */ - FMOD_ERR_UNSUPPORTED, /* A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. */ - FMOD_ERR_UPDATE, /* An error caused by System::update occured. */ - FMOD_ERR_VERSION, /* The version number of this file format is not supported. */ - - FMOD_ERR_EVENT_FAILED, /* An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. */ - FMOD_ERR_EVENT_INFOONLY, /* Can't execute this command on an EVENT_INFOONLY event. */ - FMOD_ERR_EVENT_INTERNAL, /* An error occured that wasn't supposed to. See debug log for reason. */ - FMOD_ERR_EVENT_MAXSTREAMS, /* Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. */ - FMOD_ERR_EVENT_MISMATCH, /* FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. */ - FMOD_ERR_EVENT_NAMECONFLICT, /* A category with the same name already exists. */ - FMOD_ERR_EVENT_NOTFOUND, /* The requested event, event group, event category or event property could not be found. */ - FMOD_ERR_EVENT_NEEDSSIMPLE, /* Tried to call a function on a complex event that's only supported by simple events. */ - FMOD_ERR_EVENT_GUIDCONFLICT, /* An event with the same GUID already exists. */ - FMOD_ERR_EVENT_ALREADY_LOADED, /* The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. */ - - FMOD_ERR_MUSIC_UNINITIALIZED, /* Music system is not initialized probably because no music data is loaded. */ - FMOD_ERR_MUSIC_NOTFOUND, /* The requested music entity could not be found. */ - FMOD_ERR_MUSIC_NOCALLBACK, /* The music callback is required, but it has not been set. */ - - FMOD_RESULT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_RESULT; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure describing a point in 3D space. - - [REMARKS] - FMOD uses a left handed co-ordinate system by default. - To use a right handed co-ordinate system specify FMOD_INIT_3D_RIGHTHANDED from FMOD_INITFLAGS in System::init. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::set3DListenerAttributes - System::get3DListenerAttributes - Channel::set3DAttributes - Channel::get3DAttributes - Channel::set3DCustomRolloff - Channel::get3DCustomRolloff - Sound::set3DCustomRolloff - Sound::get3DCustomRolloff - Geometry::addPolygon - Geometry::setPolygonVertex - Geometry::getPolygonVertex - Geometry::setRotation - Geometry::getRotation - Geometry::setPosition - Geometry::getPosition - Geometry::setScale - Geometry::getScale - FMOD_INITFLAGS -] -*/ -typedef struct -{ - float x; /* X co-ordinate in 3D space. */ - float y; /* Y co-ordinate in 3D space. */ - float z; /* Z co-ordinate in 3D space. */ -} FMOD_VECTOR; - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure describing a globally unique identifier. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::getDriverInfo -] -*/ -typedef struct -{ - unsigned int Data1; /* Specifies the first 8 hexadecimal digits of the GUID */ - unsigned short Data2; /* Specifies the first group of 4 hexadecimal digits. */ - unsigned short Data3; /* Specifies the second group of 4 hexadecimal digits. */ - unsigned char Data4[8]; /* Array of 8 bytes. The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits. */ -} FMOD_GUID; - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure that is passed into FMOD_FILE_ASYNCREADCALLBACK. Use the information in this structure to perform - - [REMARKS] - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - - Instructions: write to 'buffer', and 'bytesread' BEFORE setting 'result'. - As soon as result is set, FMOD will asynchronously continue internally using the data provided in this structure. - - Set 'result' to the result expected from a normal file read callback. - If the read was successful, set it to FMOD_OK. - If it read some data but hit the end of the file, set it to FMOD_ERR_FILE_EOF. - If a bad error occurred, return FMOD_ERR_FILE_BAD - If a disk was ejected, return FMOD_ERR_FILE_DISKEJECTED. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_FILE_ASYNCREADCALLBACK - FMOD_FILE_ASYNCCANCELCALLBACK -] -*/ -typedef struct -{ - void *handle; /* [r] The file handle that was filled out in the open callback. */ - unsigned int offset; /* [r] Seek position, make sure you read from this file offset. */ - unsigned int sizebytes; /* [r] how many bytes requested for read. */ - int priority; /* [r] 0 = low importance. 100 = extremely important (ie 'must read now or stuttering may occur') */ - - void *buffer; /* [w] Buffer to read file data into. */ - unsigned int bytesread; /* [w] Fill this in before setting result code to tell FMOD how many bytes were read. */ - FMOD_RESULT result; /* [r/w] Result code, FMOD_OK tells the system it is ready to consume the data. Set this last! Default value = FMOD_ERR_NOTREADY. */ - - void *userdata; /* [r] User data pointer. */ -} FMOD_ASYNCREADINFO; - - -/* -[ENUM] -[ - [DESCRIPTION] - These output types are used with System::setOutput / System::getOutput, to choose which output method to use. - - [REMARKS] - To pass information to the driver when initializing fmod use the extradriverdata parameter in System::init for the following reasons. - - FMOD_OUTPUTTYPE_WAVWRITER - extradriverdata is a pointer to a char * filename that the wav writer will output to. - - FMOD_OUTPUTTYPE_WAVWRITER_NRT - extradriverdata is a pointer to a char * filename that the wav writer will output to. - - FMOD_OUTPUTTYPE_DSOUND - extradriverdata is a pointer to a HWND so that FMOD can set the focus on the audio for a particular window. - - FMOD_OUTPUTTYPE_PS3 - extradriverdata is a pointer to a FMOD_PS3_EXTRADRIVERDATA struct. This can be found in fmodps3.h. - - FMOD_OUTPUTTYPE_GC - extradriverdata is a pointer to a FMOD_GC_INFO struct. This can be found in fmodgc.h. - - FMOD_OUTPUTTYPE_WII - extradriverdata is a pointer to a FMOD_WII_INFO struct. This can be found in fmodwii.h. - - FMOD_OUTPUTTYPE_ALSA - extradriverdata is a pointer to a FMOD_LINUX_EXTRADRIVERDATA struct. This can be found in fmodlinux.h. - - Currently these are the only FMOD drivers that take extra information. Other unknown plugins may have different requirements. - - Note! If FMOD_OUTPUTTYPE_WAVWRITER_NRT or FMOD_OUTPUTTYPE_NOSOUND_NRT are used, and if the System::update function is being called - very quickly (ie for a non realtime decode) it may be being called too quickly for the FMOD streamer thread to respond to. - The result will be a skipping/stuttering output in the captured audio. - - To remedy this, disable the FMOD Ex streamer thread, and use FMOD_INIT_STREAM_FROM_UPDATE to avoid skipping in the output stream, - as it will lock the mixer and the streamer together in the same thread. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::setOutput - System::getOutput - System::setSoftwareFormat - System::getSoftwareFormat - System::init - System::update - FMOD_INITFLAGS -] -*/ -typedef enum -{ - FMOD_OUTPUTTYPE_AUTODETECT, /* Picks the best output mode for the platform. This is the default. */ - - FMOD_OUTPUTTYPE_UNKNOWN, /* All - 3rd party plugin, unknown. This is for use with System::getOutput only. */ - FMOD_OUTPUTTYPE_NOSOUND, /* All - All calls in this mode succeed but make no sound. */ - FMOD_OUTPUTTYPE_WAVWRITER, /* All - Writes output to fmodoutput.wav by default. Use the 'extradriverdata' parameter in System::init, by simply passing the filename as a string, to set the wav filename. */ - FMOD_OUTPUTTYPE_NOSOUND_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_NOSOUND. User can drive mixer with System::update at whatever rate they want. */ - FMOD_OUTPUTTYPE_WAVWRITER_NRT, /* All - Non-realtime version of FMOD_OUTPUTTYPE_WAVWRITER. User can drive mixer with System::update at whatever rate they want. */ - - FMOD_OUTPUTTYPE_DSOUND, /* Win32/Win64 - DirectSound output. (Default on Windows XP and below) */ - FMOD_OUTPUTTYPE_WINMM, /* Win32/Win64 - Windows Multimedia output. */ - FMOD_OUTPUTTYPE_WASAPI, /* Win32 - Windows Audio Session API. (Default on Windows Vista and above) */ - FMOD_OUTPUTTYPE_ASIO, /* Win32 - Low latency ASIO 2.0 driver. */ - FMOD_OUTPUTTYPE_OSS, /* Linux/Linux64 - Open Sound System output. (Default on Linux, third preference) */ - FMOD_OUTPUTTYPE_ALSA, /* Linux/Linux64 - Advanced Linux Sound Architecture output. (Default on Linux, second preference if available) */ - FMOD_OUTPUTTYPE_ESD, /* Linux/Linux64 - Enlightment Sound Daemon output. */ - FMOD_OUTPUTTYPE_PULSEAUDIO, /* Linux/Linux64 - PulseAudio output. (Default on Linux, first preference if available) */ - FMOD_OUTPUTTYPE_COREAUDIO, /* Mac - Macintosh CoreAudio output. (Default on Mac) */ - FMOD_OUTPUTTYPE_XBOX360, /* Xbox 360 - Native Xbox360 output. (Default on Xbox 360) */ - FMOD_OUTPUTTYPE_PSP, /* PSP - Native PSP output. (Default on PSP) */ - FMOD_OUTPUTTYPE_PS3, /* PS3 - Native PS3 output. (Default on PS3) */ - FMOD_OUTPUTTYPE_NGP, /* NGP - Native NGP output. (Default on NGP) */ - FMOD_OUTPUTTYPE_WII, /* Wii - Native Wii output. (Default on Wii) */ - FMOD_OUTPUTTYPE_3DS, /* 3DS - Native 3DS output (Default on 3DS) */ - FMOD_OUTPUTTYPE_AUDIOTRACK, /* Android - Java Audio Track output. (Default on Android 2.2 and below) */ - FMOD_OUTPUTTYPE_OPENSL, /* Android - OpenSL ES output. (Default on Android 2.3 and above) */ - FMOD_OUTPUTTYPE_NACL, /* Native Client - Native Client output. (Default on Native Client) */ - FMOD_OUTPUTTYPE_WIIU, /* Wii U - Native Wii U output. (Default on Wii U) */ - FMOD_OUTPUTTYPE_ASOUND, /* BlackBerry - Native BlackBerry asound output. (Default on BlackBerry) */ - - FMOD_OUTPUTTYPE_MAX, /* Maximum number of output types supported. */ - FMOD_OUTPUTTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_OUTPUTTYPE; - - -/* -[DEFINE] -[ - [NAME] - FMOD_CAPS - - [DESCRIPTION] - Bit fields to use with System::getDriverCaps to determine the capabilities of a card / output device. - - [REMARKS] - It is important to check FMOD_CAPS_HARDWARE_EMULATED on windows machines, to then adjust System::setDSPBufferSize to (1024, 10) to compensate for the higher latency. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::getDriverCaps - System::setDSPBufferSize -] -*/ -#define FMOD_CAPS_NONE 0x00000000 /* Device has no special capabilities. */ -#define FMOD_CAPS_HARDWARE 0x00000001 /* Device supports hardware mixing. */ -#define FMOD_CAPS_HARDWARE_EMULATED 0x00000002 /* User has device set to 'Hardware acceleration = off' in control panel, and now extra 200ms latency is incurred. */ -#define FMOD_CAPS_OUTPUT_MULTICHANNEL 0x00000004 /* Device can do multichannel output, ie greater than 2 channels. */ -#define FMOD_CAPS_OUTPUT_FORMAT_PCM8 0x00000008 /* Device can output to 8bit integer PCM. */ -#define FMOD_CAPS_OUTPUT_FORMAT_PCM16 0x00000010 /* Device can output to 16bit integer PCM. */ -#define FMOD_CAPS_OUTPUT_FORMAT_PCM24 0x00000020 /* Device can output to 24bit integer PCM. */ -#define FMOD_CAPS_OUTPUT_FORMAT_PCM32 0x00000040 /* Device can output to 32bit integer PCM. */ -#define FMOD_CAPS_OUTPUT_FORMAT_PCMFLOAT 0x00000080 /* Device can output to 32bit floating point PCM. */ -#define FMOD_CAPS_REVERB_LIMITED 0x00002000 /* Device supports some form of limited hardware reverb, maybe parameterless and only selectable by environment. */ -#define FMOD_CAPS_LOOPBACK 0x00004000 /* Device is a loopback recording device */ -/* [DEFINE_END] */ - -/* -[DEFINE] -[ - [NAME] - FMOD_DEBUGLEVEL - - [DESCRIPTION] - Bit fields to use with FMOD::Debug_SetLevel / FMOD::Debug_GetLevel to control the level of tty debug output with logging versions of FMOD (fmodL). - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Debug_SetLevel - Debug_GetLevel -] -*/ -#define FMOD_DEBUG_LEVEL_NONE 0x00000000 -#define FMOD_DEBUG_LEVEL_LOG 0x00000001 /* Will display generic logging messages. */ -#define FMOD_DEBUG_LEVEL_ERROR 0x00000002 /* Will display errors. */ -#define FMOD_DEBUG_LEVEL_WARNING 0x00000004 /* Will display warnings that are not fatal. */ -#define FMOD_DEBUG_LEVEL_HINT 0x00000008 /* Will hint to you if there is something possibly better you could be doing. */ -#define FMOD_DEBUG_LEVEL_ALL 0x000000FF -#define FMOD_DEBUG_TYPE_MEMORY 0x00000100 /* Show FMOD memory related logging messages. */ -#define FMOD_DEBUG_TYPE_THREAD 0x00000200 /* Show FMOD thread related logging messages. */ -#define FMOD_DEBUG_TYPE_FILE 0x00000400 /* Show FMOD file system related logging messages. */ -#define FMOD_DEBUG_TYPE_NET 0x00000800 /* Show FMOD network related logging messages. */ -#define FMOD_DEBUG_TYPE_EVENT 0x00001000 /* Show FMOD Event related logging messages. */ -#define FMOD_DEBUG_TYPE_ALL 0x0000FFFF -#define FMOD_DEBUG_DISPLAY_TIMESTAMPS 0x01000000 /* Display the timestamp of the log entry in milliseconds. */ -#define FMOD_DEBUG_DISPLAY_LINENUMBERS 0x02000000 /* Display the FMOD Ex source code line numbers, for debugging purposes. */ -#define FMOD_DEBUG_DISPLAY_COMPRESS 0x04000000 /* If a message is repeated more than 5 times it will stop displaying it and instead display the number of times the message was logged. */ -#define FMOD_DEBUG_DISPLAY_THREAD 0x08000000 /* Display the thread ID of the calling function that caused this log entry to appear. */ -#define FMOD_DEBUG_DISPLAY_ALL 0x0F000000 -#define FMOD_DEBUG_ALL 0xFFFFFFFF -/* [DEFINE_END] */ - - -/* -[DEFINE] -[ - [NAME] - FMOD_MEMORY_TYPE - - [DESCRIPTION] - Bit fields for memory allocation type being passed into FMOD memory callbacks. - - [REMARKS] - Remember this is a bitfield. You may get more than 1 bit set (ie physical + persistent) so do not simply switch on the types! You must check each bit individually or clear out the bits that you do not want within the callback. - Bits can be excluded if you want during Memory_Initialize so that you never get them. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_MEMORY_ALLOCCALLBACK - FMOD_MEMORY_REALLOCCALLBACK - FMOD_MEMORY_FREECALLBACK - Memory_Initialize - -] -*/ -#define FMOD_MEMORY_NORMAL 0x00000000 /* Standard memory. */ -#define FMOD_MEMORY_STREAM_FILE 0x00000001 /* Stream file buffer, size controllable with System::setStreamBufferSize. */ -#define FMOD_MEMORY_STREAM_DECODE 0x00000002 /* Stream decode buffer, size controllable with FMOD_CREATESOUNDEXINFO::decodebuffersize. */ -#define FMOD_MEMORY_SAMPLEDATA 0x00000004 /* Sample data buffer. Raw audio data, usually PCM/MPEG/ADPCM/XMA data. */ -#define FMOD_MEMORY_DSP_OUTPUTBUFFER 0x00000008 /* DSP memory block allocated when more than 1 output exists on a DSP node. */ -#define FMOD_MEMORY_XBOX360_PHYSICAL 0x00100000 /* Requires XPhysicalAlloc / XPhysicalFree. */ -#define FMOD_MEMORY_PERSISTENT 0x00200000 /* Persistent memory. Memory will be freed when System::release is called. */ -#define FMOD_MEMORY_SECONDARY 0x00400000 /* Secondary memory. Allocation should be in secondary memory. For example RSX on the PS3. */ -#define FMOD_MEMORY_ALL 0xFFFFFFFF -/* [DEFINE_END] */ - - -/* -[ENUM] -[ - [DESCRIPTION] - These are speaker types defined for use with the System::setSpeakerMode or System::getSpeakerMode command. - - [REMARKS] - These are important notes on speaker modes in regards to sounds created with FMOD_SOFTWARE. - Note below the phrase 'sound channels' is used. These are the subchannels inside a sound, they are not related and - have nothing to do with the FMOD class "Channel". - For example a mono sound has 1 sound channel, a stereo sound has 2 sound channels, and an AC3 or 6 channel wav file have 6 "sound channels". - - FMOD_SPEAKERMODE_RAW - --------------------- - This mode is for output devices that are not specifically mono/stereo/quad/surround/5.1 or 7.1, but are multichannel. - Use System::setSoftwareFormat to specify the number of speakers you want to address, otherwise it will default to 2 (stereo). - Sound channels map to speakers sequentially, so a mono sound maps to output speaker 0, stereo sound maps to output speaker 0 & 1. - The user assumes knowledge of the speaker order. FMOD_SPEAKER enumerations may not apply, so raw channel indices should be used. - Multichannel sounds map input channels to output channels 1:1. - Channel::setPan and Channel::setSpeakerMix do not work. - Speaker levels must be manually set with Channel::setSpeakerLevels. - - FMOD_SPEAKERMODE_MONO - --------------------- - This mode is for a 1 speaker arrangement. - Panning does not work in this speaker mode. - Mono, stereo and multichannel sounds have each sound channel played on the one speaker unity. - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. - Channel::setSpeakerMix does not work. - - FMOD_SPEAKERMODE_STEREO - ----------------------- - This mode is for 2 speaker arrangements that have a left and right speaker. - - Mono sounds default to an even distribution between left and right. They can be panned with Channel::setPan. - - Stereo sounds default to the middle, or full left in the left speaker and full right in the right speaker. - - They can be cross faded with Channel::setPan. - - Multichannel sounds have each sound channel played on each speaker at unity. - - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. - - Channel::setSpeakerMix works but only front left and right parameters are used, the rest are ignored. - - FMOD_SPEAKERMODE_QUAD - ------------------------ - This mode is for 4 speaker arrangements that have a front left, front right, rear left and a rear right speaker. - - Mono sounds default to an even distribution between front left and front right. They can be panned with Channel::setPan. - - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. - - They can be cross faded with Channel::setPan. - - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. - - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. - - Channel::setSpeakerMix works but side left, side right, center and lfe are ignored. - - FMOD_SPEAKERMODE_SURROUND - ------------------------ - This mode is for 5 speaker arrangements that have a left/right/center/rear left/rear right. - - Mono sounds default to the center speaker. They can be panned with Channel::setPan. - - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. - - They can be cross faded with Channel::setPan. - - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. - - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. - - Channel::setSpeakerMix works but side left / side right are ignored. - - FMOD_SPEAKERMODE_5POINT1 - ------------------------ - This mode is for 5.1 speaker arrangements that have a left/right/center/rear left/rear right and a subwoofer speaker. - - Mono sounds default to the center speaker. They can be panned with Channel::setPan. - - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. - - They can be cross faded with Channel::setPan. - - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. - - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. - - Channel::setSpeakerMix works but side left / side right are ignored. - - FMOD_SPEAKERMODE_7POINT1 - ------------------------ - This mode is for 7.1 speaker arrangements that have a left/right/center/rear left/rear right/side left/side right - and a subwoofer speaker. - - Mono sounds default to the center speaker. They can be panned with Channel::setPan. - - Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. - - They can be cross faded with Channel::setPan. - - Multichannel sounds default to all of their sound channels being played on each speaker in order of input. - - Mix behavior for multichannel sounds can be set with Channel::setSpeakerLevels. - - Channel::setSpeakerMix works and every parameter is used to set the balance of a sound in any speaker. - - FMOD_SPEAKERMODE_SRS5_1_MATRIX - ------------------------------------------------------ - This mode is for mono, stereo, 5.1 and 6.1 speaker arrangements, as it is backwards and forwards compatible with - stereo, but to get a surround effect a SRS 5.1, Prologic or Prologic 2 hardware decoder / amplifier is needed or - a compatible SRS equipped device (e.g., laptop, TV, etc.) or accessory (e.g., headphone). - Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1. - - If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten. - - Output rate must be 44100, 48000 or 96000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned. - - FMOD_SPEAKERMODE_DOLBY5_1_MATRIX - ------------------------------------------------------ - This mode is for 5.1 speaker arrangements using a stereo signal, to get a surround effect a Dolby Pro Logic II - hardware decoder / amplifier is needed. - Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1. - - If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten. - - Output rate must be 32000, 44100 or 48000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned. - - FMOD_SPEAKERMODE_MYEARS - ------------------------------------------------------ - This mode is for headphones. This will attempt to load a MyEars profile (see myears.net.au) and use it to generate - surround sound on headphones using a personalized HRTF algorithm, for realistic 3d sound. - Pan behavior is the same as FMOD_SPEAKERMODE_7POINT1. - MyEars speaker mode will automatically be set if the speakermode is FMOD_SPEAKERMODE_STEREO and the MyEars profile exists. - If this mode is set explicitly, FMOD_INIT_DISABLE_MYEARS_AUTODETECT has no effect. - If this mode is set explicitly and the MyEars profile does not exist, FMOD_ERR_OUTPUT_DRIVERCALL will be returned. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::setSpeakerMode - System::getSpeakerMode - System::getDriverCaps - System::setSoftwareFormat - Channel::setSpeakerLevels -] -*/ -typedef enum -{ - FMOD_SPEAKERMODE_RAW, /* There is no specific speakermode. Sound channels are mapped in order of input to output. Use System::setSoftwareFormat to specify speaker count. See remarks for more information. */ - FMOD_SPEAKERMODE_MONO, /* The speakers are monaural. */ - FMOD_SPEAKERMODE_STEREO, /* The speakers are stereo (DEFAULT). */ - FMOD_SPEAKERMODE_QUAD, /* 4 speaker setup. This includes front left, front right, rear left, rear right. */ - FMOD_SPEAKERMODE_SURROUND, /* 5 speaker setup. This includes front left, front right, center, rear left, rear right. */ - FMOD_SPEAKERMODE_5POINT1, /* 5.1 speaker setup. This includes front left, front right, center, rear left, rear right and a subwoofer. */ - FMOD_SPEAKERMODE_7POINT1, /* 7.1 speaker setup. This includes front left, front right, center, rear left, rear right, side left, side right and a subwoofer. */ - - FMOD_SPEAKERMODE_SRS5_1_MATRIX, /* Stereo compatible output, embedded with surround information. SRS 5.1/Prologic/Prologic2 decoders will split the signal into a 5.1 speaker set-up or SRS virtual surround will decode into a 2-speaker/headphone setup. See remarks about limitations.*/ - FMOD_SPEAKERMODE_DOLBY5_1_MATRIX, /* Stereo compatible output, embedded with surround information. Dolby Pro Logic II decoders will split the signal into a 5.1 speaker set-up. */ - FMOD_SPEAKERMODE_MYEARS, /* Stereo output, but data is encoded using personalized HRTF algorithms. See myears.net.au */ - - FMOD_SPEAKERMODE_MAX, /* Maximum number of speaker modes supported. */ - FMOD_SPEAKERMODE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_SPEAKERMODE; - - -/* -[ENUM] -[ - [DESCRIPTION] - These are speaker types defined for use with the Channel::setSpeakerLevels command. - It can also be used for speaker placement in the System::set3DSpeakerPosition command. - - [REMARKS] - If you are using FMOD_SPEAKERMODE_RAW and speaker assignments are meaningless, just cast a raw integer value to this type. - For example (FMOD_SPEAKER)7 would use the 7th speaker (also the same as FMOD_SPEAKER_SIDE_RIGHT). - Values higher than this can be used if an output system has more than 8 speaker types / output channels. 15 is the current maximum. - - NOTE: On Playstation 3 in 7.1, the extra 2 speakers are not side left/side right, they are 'surround back left'/'surround back right' which - locate the speakers behind the listener instead of to the sides like on PC. FMOD_SPEAKER_SBL/FMOD_SPEAKER_SBR are provided to make it - clearer what speaker is being addressed on that platform. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_SPEAKERMODE - Channel::setSpeakerLevels - Channel::getSpeakerLevels - System::set3DSpeakerPosition - System::get3DSpeakerPosition -] -*/ -typedef enum -{ - FMOD_SPEAKER_FRONT_LEFT, - FMOD_SPEAKER_FRONT_RIGHT, - FMOD_SPEAKER_FRONT_CENTER, - FMOD_SPEAKER_LOW_FREQUENCY, - FMOD_SPEAKER_BACK_LEFT, - FMOD_SPEAKER_BACK_RIGHT, - FMOD_SPEAKER_SIDE_LEFT, - FMOD_SPEAKER_SIDE_RIGHT, - - FMOD_SPEAKER_MAX, /* Maximum number of speaker types supported. */ - FMOD_SPEAKER_MONO = FMOD_SPEAKER_FRONT_LEFT, /* For use with FMOD_SPEAKERMODE_MONO and Channel::SetSpeakerLevels. Mapped to same value as FMOD_SPEAKER_FRONT_LEFT. */ - FMOD_SPEAKER_NULL = 65535, /* A non speaker. Use this with ASIO mapping to ignore a speaker. */ - FMOD_SPEAKER_SBL = FMOD_SPEAKER_SIDE_LEFT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ - FMOD_SPEAKER_SBR = FMOD_SPEAKER_SIDE_RIGHT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ - FMOD_SPEAKER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_SPEAKER; - - -/* -[ENUM] -[ - [DESCRIPTION] - These are plugin types defined for use with the System::getNumPlugins, - System::getPluginInfo and System::unloadPlugin functions. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::getNumPlugins - System::getPluginInfo - System::unloadPlugin -] -*/ -typedef enum -{ - FMOD_PLUGINTYPE_OUTPUT, /* The plugin type is an output module. FMOD mixed audio will play through one of these devices */ - FMOD_PLUGINTYPE_CODEC, /* The plugin type is a file format codec. FMOD will use these codecs to load file formats for playback. */ - FMOD_PLUGINTYPE_DSP, /* The plugin type is a DSP unit. FMOD will use these plugins as part of its DSP network to apply effects to output or generate sound in realtime. */ - - FMOD_PLUGINTYPE_MAX, /* Maximum number of plugin types supported. */ - FMOD_PLUGINTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_PLUGINTYPE; - - -/* -[DEFINE] -[ - [NAME] - FMOD_INITFLAGS - - [DESCRIPTION] - Initialization flags. Use them with System::init in the flags parameter to change various behavior. - - [REMARKS] - Use System::setAdvancedSettings to adjust settings for some of the features that are enabled by these flags. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::init - System::update - System::setAdvancedSettings - Channel::set3DOcclusion -] -*/ -#define FMOD_INIT_NORMAL 0x00000000 /* All platforms - Initialize normally */ -#define FMOD_INIT_STREAM_FROM_UPDATE 0x00000001 /* All platforms - No stream thread is created internally. Streams are driven from System::update. Mainly used with non-realtime outputs. */ -#define FMOD_INIT_3D_RIGHTHANDED 0x00000002 /* All platforms - FMOD will treat +X as right, +Y as up and +Z as backwards (towards you). */ -#define FMOD_INIT_SOFTWARE_DISABLE 0x00000004 /* All platforms - Disable software mixer to save memory. Anything created with FMOD_SOFTWARE will fail and DSP will not work. */ -#define FMOD_INIT_OCCLUSION_LOWPASS 0x00000008 /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which is automatically used when Channel::set3DOcclusion is used or the geometry API. */ -#define FMOD_INIT_HRTF_LOWPASS 0x00000010 /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which causes sounds to sound duller when the sound goes behind the listener. Use System::setAdvancedSettings to adjust cutoff frequency. */ -#define FMOD_INIT_DISTANCE_FILTERING 0x00000200 /* All platforms - All FMOD_SOFTWARE with FMOD_3D based voices will add a software lowpass and highpass filter effect into the DSP chain which will act as a distance-automated bandpass filter. Use System::setAdvancedSettings to adjust the center frequency. */ -#define FMOD_INIT_REVERB_PREALLOCBUFFERS 0x00000040 /* All platforms - FMOD Software reverb will preallocate enough buffers for reverb per channel, rather than allocating them and freeing them at runtime. */ -#define FMOD_INIT_ENABLE_PROFILE 0x00000020 /* All platforms - Enable TCP/IP based host which allows FMOD Designer or FMOD Profiler to connect to it, and view memory, CPU and the DSP network graph in real-time. */ -#define FMOD_INIT_VOL0_BECOMES_VIRTUAL 0x00000080 /* All platforms - Any sounds that are 0 volume will go virtual and not be processed except for having their positions updated virtually. Use System::setAdvancedSettings to adjust what volume besides zero to switch to virtual at. */ -#define FMOD_INIT_WASAPI_EXCLUSIVE 0x00000100 /* Win32 Vista only - for WASAPI output - Enable exclusive access to hardware, lower latency at the expense of excluding other applications from accessing the audio hardware. */ -#define FMOD_INIT_PS3_PREFERDTS 0x00800000 /* PS3 only - Prefer DTS over Dolby Digital if both are supported. Note: 8 and 6 channel LPCM is always preferred over both DTS and Dolby Digital. */ -#define FMOD_INIT_PS3_FORCE2CHLPCM 0x01000000 /* PS3 only - Force PS3 system output mode to 2 channel LPCM. */ -#define FMOD_INIT_DISABLEDOLBY 0x00100000 /* Wii / 3DS - Disable Dolby Pro Logic surround. Speakermode will be set to STEREO even if user has selected surround in the system settings. */ -#define FMOD_INIT_SYSTEM_MUSICMUTENOTPAUSE 0x00200000 /* Xbox 360 / PS3 - The "music" channelgroup which by default pauses when custom 360 dashboard / PS3 BGM music is played, can be changed to mute (therefore continues playing) instead of pausing, by using this flag. */ -#define FMOD_INIT_SYNCMIXERWITHUPDATE 0x00400000 /* Win32/Wii/PS3/Xbox/Xbox 360 - FMOD Mixer thread is woken up to do a mix when System::update is called rather than waking periodically on its own timer. */ -#define FMOD_INIT_GEOMETRY_USECLOSEST 0x04000000 /* All platforms - With the geometry engine, only process the closest polygon rather than accumulating all polygons the sound to listener line intersects. */ -#define FMOD_INIT_DISABLE_MYEARS_AUTODETECT 0x08000000 /* Win32 - Disables automatic setting of FMOD_SPEAKERMODE_STEREO to FMOD_SPEAKERMODE_MYEARS if the MyEars profile exists on the PC. MyEars is HRTF 7.1 downmixing through headphones. */ -#define FMOD_INIT_PS3_DISABLEDTS 0x10000000 /* PS3 only - Disable DTS output mode selection */ -#define FMOD_INIT_PS3_DISABLEDOLBYDIGITAL 0x20000000 /* PS3 only - Disable Dolby Digital output mode selection */ -/* [DEFINE_END] */ - - -/* -[ENUM] -[ - [DESCRIPTION] - These definitions describe the type of song being played. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Sound::getFormat -] -*/ -typedef enum -{ - FMOD_SOUND_TYPE_UNKNOWN, /* 3rd party / unknown plugin format. */ - FMOD_SOUND_TYPE_AIFF, /* AIFF. */ - FMOD_SOUND_TYPE_ASF, /* Microsoft Advanced Systems Format (ie WMA/ASF/WMV). */ - FMOD_SOUND_TYPE_AT3, /* Sony ATRAC 3 format */ - FMOD_SOUND_TYPE_CDDA, /* Digital CD audio. */ - FMOD_SOUND_TYPE_DLS, /* Sound font / downloadable sound bank. */ - FMOD_SOUND_TYPE_FLAC, /* FLAC lossless codec. */ - FMOD_SOUND_TYPE_FSB, /* FMOD Sample Bank. */ - FMOD_SOUND_TYPE_GCADPCM, /* Nintendo GameCube/Wii ADPCM */ - FMOD_SOUND_TYPE_IT, /* Impulse Tracker. */ - FMOD_SOUND_TYPE_MIDI, /* MIDI. extracodecdata is a pointer to an FMOD_MIDI_EXTRACODECDATA structure. */ - FMOD_SOUND_TYPE_MOD, /* Protracker / Fasttracker MOD. */ - FMOD_SOUND_TYPE_MPEG, /* MP2/MP3 MPEG. */ - FMOD_SOUND_TYPE_OGGVORBIS, /* Ogg vorbis. */ - FMOD_SOUND_TYPE_PLAYLIST, /* Information only from ASX/PLS/M3U/WAX playlists */ - FMOD_SOUND_TYPE_RAW, /* Raw PCM data. */ - FMOD_SOUND_TYPE_S3M, /* ScreamTracker 3. */ - FMOD_SOUND_TYPE_SF2, /* Sound font 2 format. */ - FMOD_SOUND_TYPE_USER, /* User created sound. */ - FMOD_SOUND_TYPE_WAV, /* Microsoft WAV. */ - FMOD_SOUND_TYPE_XM, /* FastTracker 2 XM. */ - FMOD_SOUND_TYPE_XMA, /* Xbox360 XMA */ - FMOD_SOUND_TYPE_VAG, /* PlayStation Portable ADPCM VAG format. */ - FMOD_SOUND_TYPE_AUDIOQUEUE, /* iPhone hardware decoder, supports AAC, ALAC and MP3. extracodecdata is a pointer to an FMOD_AUDIOQUEUE_EXTRACODECDATA structure. */ - FMOD_SOUND_TYPE_XWMA, /* Xbox360 XWMA */ - FMOD_SOUND_TYPE_BCWAV, /* 3DS BCWAV container format for DSP ADPCM and PCM */ - FMOD_SOUND_TYPE_AT9, /* NGP ATRAC 9 format */ - FMOD_SOUND_TYPE_VORBIS, /* Raw vorbis */ - FMOD_SOUND_TYPE_MEDIA_FOUNDATION,/* Microsoft Media Foundation wrappers, supports ASF/WMA */ - - FMOD_SOUND_TYPE_MAX, /* Maximum number of sound types supported. */ - FMOD_SOUND_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_SOUND_TYPE; - - -/* -[ENUM] -[ - [DESCRIPTION] - These definitions describe the native format of the hardware or software buffer that will be used. - - [REMARKS] - This is the format the native hardware or software buffer will be or is created in. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::createSound - Sound::getFormat -] -*/ -typedef enum -{ - FMOD_SOUND_FORMAT_NONE, /* Unitialized / unknown. */ - FMOD_SOUND_FORMAT_PCM8, /* 8bit integer PCM data. */ - FMOD_SOUND_FORMAT_PCM16, /* 16bit integer PCM data. */ - FMOD_SOUND_FORMAT_PCM24, /* 24bit integer PCM data. */ - FMOD_SOUND_FORMAT_PCM32, /* 32bit integer PCM data. */ - FMOD_SOUND_FORMAT_PCMFLOAT, /* 32bit floating point PCM data. */ - FMOD_SOUND_FORMAT_GCADPCM, /* Compressed Nintendo 3DS/Wii DSP data. */ - FMOD_SOUND_FORMAT_IMAADPCM, /* Compressed IMA ADPCM data. */ - FMOD_SOUND_FORMAT_VAG, /* Compressed PlayStation Portable ADPCM data. */ - FMOD_SOUND_FORMAT_HEVAG, /* Compressed PSVita ADPCM data. */ - FMOD_SOUND_FORMAT_XMA, /* Compressed Xbox360 XMA data. */ - FMOD_SOUND_FORMAT_MPEG, /* Compressed MPEG layer 2 or 3 data. */ - FMOD_SOUND_FORMAT_CELT, /* Compressed CELT data. */ - FMOD_SOUND_FORMAT_AT9, /* Compressed PSVita ATRAC9 data. */ - FMOD_SOUND_FORMAT_XWMA, /* Compressed Xbox360 xWMA data. */ - FMOD_SOUND_FORMAT_VORBIS, /* Compressed Vorbis data. */ - - FMOD_SOUND_FORMAT_MAX, /* Maximum number of sound formats supported. */ - FMOD_SOUND_FORMAT_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_SOUND_FORMAT; - - -/* -[DEFINE] -[ - [NAME] - FMOD_MODE - - [DESCRIPTION] - Sound description bitfields, bitwise OR them together for loading and describing sounds. - - [REMARKS] - By default a sound will open as a static sound that is decompressed fully into memory to PCM. (ie equivalent of FMOD_CREATESAMPLE) - To have a sound stream instead, use FMOD_CREATESTREAM, or use the wrapper function System::createStream. - Some opening modes (ie FMOD_OPENUSER, FMOD_OPENMEMORY, FMOD_OPENMEMORY_POINT, FMOD_OPENRAW) will need extra information. - This can be provided using the FMOD_CREATESOUNDEXINFO structure. - - Specifying FMOD_OPENMEMORY_POINT will POINT to your memory rather allocating its own sound buffers and duplicating it internally. - This means you cannot free the memory while FMOD is using it, until after Sound::release is called. - With FMOD_OPENMEMORY_POINT, for PCM formats, only WAV, FSB, and RAW are supported. For compressed formats, only those formats supported by FMOD_CREATECOMPRESSEDSAMPLE are supported. - With FMOD_OPENMEMORY_POINT and FMOD_OPENRAW or PCM, if using them together, note that you must pad the data on each side by 16 bytes. This is so fmod can modify the ends of the data for looping/interpolation/mixing purposes. If a wav file, you will need to insert silence, and then reset loop points to stop the playback from playing that silence. - With FMOD_OPENMEMORY_POINT, For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used. - - Xbox 360 memory On Xbox 360 Specifying FMOD_OPENMEMORY_POINT to a virtual memory address will cause FMOD_ERR_INVALID_ADDRESS - to be returned. Use physical memory only for this functionality. - - FMOD_LOWMEM is used on a sound if you want to minimize the memory overhead, by having FMOD not allocate memory for certain - features that are not likely to be used in a game environment. These are : - 1. Sound::getName functionality is removed. 256 bytes per sound is saved. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::createSound - System::createStream - Sound::setMode - Sound::getMode - Channel::setMode - Channel::getMode - Sound::set3DCustomRolloff - Channel::set3DCustomRolloff - Sound::getOpenState -] -*/ -#define FMOD_DEFAULT 0x00000000 /* Default for all modes listed below. FMOD_LOOP_OFF, FMOD_2D, FMOD_HARDWARE */ -#define FMOD_LOOP_OFF 0x00000001 /* For non looping sounds. (DEFAULT). Overrides FMOD_LOOP_NORMAL / FMOD_LOOP_BIDI. */ -#define FMOD_LOOP_NORMAL 0x00000002 /* For forward looping sounds. */ -#define FMOD_LOOP_BIDI 0x00000004 /* For bidirectional looping sounds. (only works on software mixed static sounds). */ -#define FMOD_2D 0x00000008 /* Ignores any 3d processing. (DEFAULT). */ -#define FMOD_3D 0x00000010 /* Makes the sound positionable in 3D. Overrides FMOD_2D. */ -#define FMOD_HARDWARE 0x00000020 /* Attempts to make sounds use hardware acceleration. (DEFAULT). Note on platforms that don't support FMOD_HARDWARE (only 3DS, PS Vita, PSP, Wii and Wii U support FMOD_HARDWARE), this will be internally treated as FMOD_SOFTWARE. */ -#define FMOD_SOFTWARE 0x00000040 /* Makes the sound be mixed by the FMOD CPU based software mixer. Overrides FMOD_HARDWARE. Use this for FFT, DSP, compressed sample support, 2D multi-speaker support and other software related features. */ -#define FMOD_CREATESTREAM 0x00000080 /* Decompress at runtime, streaming from the source provided (ie from disk). Overrides FMOD_CREATESAMPLE and FMOD_CREATECOMPRESSEDSAMPLE. Note a stream can only be played once at a time due to a stream only having 1 stream buffer and file handle. Open multiple streams to have them play concurrently. */ -#define FMOD_CREATESAMPLE 0x00000100 /* Decompress at loadtime, decompressing or decoding whole file into memory as the target sample format (ie PCM). Fastest for FMOD_SOFTWARE based playback and most flexible. */ -#define FMOD_CREATECOMPRESSEDSAMPLE 0x00000200 /* Load MP2, MP3, IMAADPCM or XMA into memory and leave it compressed. During playback the FMOD software mixer will decode it in realtime as a 'compressed sample'. Can only be used in combination with FMOD_SOFTWARE. Overrides FMOD_CREATESAMPLE. If the sound data is not ADPCM, MPEG or XMA it will behave as if it was created with FMOD_CREATESAMPLE and decode the sound into PCM. */ -#define FMOD_OPENUSER 0x00000400 /* Opens a user created static sample or stream. Use FMOD_CREATESOUNDEXINFO to specify format and/or read callbacks. If a user created 'sample' is created with no read callback, the sample will be empty. Use Sound::lock and Sound::unlock to place sound data into the sound if this is the case. */ -#define FMOD_OPENMEMORY 0x00000800 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. If used with FMOD_CREATESAMPLE or FMOD_CREATECOMPRESSEDSAMPLE, FMOD duplicates the memory into its own buffers. Your own buffer can be freed after open. If used with FMOD_CREATESTREAM, FMOD will stream out of the buffer whose pointer you passed in. In this case, your own buffer should not be freed until you have finished with and released the stream.*/ -#define FMOD_OPENMEMORY_POINT 0x10000000 /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. This differs to FMOD_OPENMEMORY in that it uses the memory as is, without duplicating the memory into its own buffers. For Wii/PSP FMOD_HARDWARE supports this flag for the GCADPCM/VAG formats. On other platforms FMOD_SOFTWARE must be used, as sound hardware on the other platforms (ie PC) cannot access main ram. Cannot be freed after open, only after Sound::release. Will not work if the data is compressed and FMOD_CREATECOMPRESSEDSAMPLE is not used. */ -#define FMOD_OPENRAW 0x00001000 /* Will ignore file format and treat as raw pcm. Use FMOD_CREATESOUNDEXINFO to specify format. Requires at least defaultfrequency, numchannels and format to be specified before it will open. Must be little endian data. */ -#define FMOD_OPENONLY 0x00002000 /* Just open the file, dont prebuffer or read. Good for fast opens for info, or when sound::readData is to be used. */ -#define FMOD_ACCURATETIME 0x00004000 /* For System::createSound - for accurate Sound::getLength/Channel::setPosition on VBR MP3, and MOD/S3M/XM/IT/MIDI files. Scans file first, so takes longer to open. FMOD_OPENONLY does not affect this. */ -#define FMOD_MPEGSEARCH 0x00008000 /* For corrupted / bad MP3 files. This will search all the way through the file until it hits a valid MPEG header. Normally only searches for 4k. */ -#define FMOD_NONBLOCKING 0x00010000 /* For opening sounds and getting streamed subsounds (seeking) asyncronously. Use Sound::getOpenState to poll the state of the sound as it opens or retrieves the subsound in the background. */ -#define FMOD_UNIQUE 0x00020000 /* Unique sound, can only be played one at a time */ -#define FMOD_3D_HEADRELATIVE 0x00040000 /* Make the sound's position, velocity and orientation relative to the listener. */ -#define FMOD_3D_WORLDRELATIVE 0x00080000 /* Make the sound's position, velocity and orientation absolute (relative to the world). (DEFAULT) */ -#define FMOD_3D_INVERSEROLLOFF 0x00100000 /* This sound will follow the inverse rolloff model where mindistance = full volume, maxdistance = where sound stops attenuating, and rolloff is fixed according to the global rolloff factor. (DEFAULT) */ -#define FMOD_3D_LINEARROLLOFF 0x00200000 /* This sound will follow a linear rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ -#define FMOD_3D_LINEARSQUAREROLLOFF 0x00400000 /* This sound will follow a linear-square rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ -#define FMOD_3D_CUSTOMROLLOFF 0x04000000 /* This sound will follow a rolloff model defined by Sound::set3DCustomRolloff / Channel::set3DCustomRolloff. */ -#define FMOD_3D_IGNOREGEOMETRY 0x40000000 /* Is not affect by geometry occlusion. If not specified in Sound::setMode, or Channel::setMode, the flag is cleared and it is affected by geometry again. */ -#define FMOD_UNICODE 0x01000000 /* Filename is double-byte unicode. */ -#define FMOD_IGNORETAGS 0x02000000 /* Skips id3v2/asf/etc tag checks when opening a sound, to reduce seek/read overhead when opening files (helps with CD performance). */ -#define FMOD_LOWMEM 0x08000000 /* Removes some features from samples to give a lower memory overhead, like Sound::getName. See remarks. */ -#define FMOD_LOADSECONDARYRAM 0x20000000 /* Load sound into the secondary RAM of supported platform. On PS3, sounds will be loaded into RSX/VRAM. */ -#define FMOD_VIRTUAL_PLAYFROMSTART 0x80000000 /* For sounds that start virtual (due to being quiet or low importance), instead of swapping back to audible, and playing at the correct offset according to time, this flag makes the sound play from the start. */ - -/* [DEFINE_END] */ - - -/* -[ENUM] -[ - [DESCRIPTION] - These values describe what state a sound is in after FMOD_NONBLOCKING has been used to open it. - - [REMARKS] - With streams, if you are using FMOD_NONBLOCKING, note that if the user calls Sound::getSubSound, a stream will go into FMOD_OPENSTATE_SEEKING state and sound related commands will return FMOD_ERR_NOTREADY. - With streams, if you are using FMOD_NONBLOCKING, note that if the user calls Channel::getPosition, a stream will go into FMOD_OPENSTATE_SETPOSITION state and sound related commands will return FMOD_ERR_NOTREADY. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Sound::getOpenState - FMOD_MODE -] -*/ -typedef enum -{ - FMOD_OPENSTATE_READY = 0, /* Opened and ready to play. */ - FMOD_OPENSTATE_LOADING, /* Initial load in progress. */ - FMOD_OPENSTATE_ERROR, /* Failed to open - file not found, out of memory etc. See return value of Sound::getOpenState for what happened. */ - FMOD_OPENSTATE_CONNECTING, /* Connecting to remote host (internet sounds only). */ - FMOD_OPENSTATE_BUFFERING, /* Buffering data. */ - FMOD_OPENSTATE_SEEKING, /* Seeking to subsound and re-flushing stream buffer. */ - FMOD_OPENSTATE_PLAYING, /* Ready and playing, but not possible to release at this time without stalling the main thread. */ - FMOD_OPENSTATE_SETPOSITION, /* Seeking within a stream to a different position. */ - - FMOD_OPENSTATE_MAX, /* Maximum number of open state types. */ - FMOD_OPENSTATE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_OPENSTATE; - - -/* -[ENUM] -[ - [DESCRIPTION] - These flags are used with SoundGroup::setMaxAudibleBehavior to determine what happens when more sounds - are played than are specified with SoundGroup::setMaxAudible. - - [REMARKS] - When using FMOD_SOUNDGROUP_BEHAVIOR_MUTE, SoundGroup::setMuteFadeSpeed can be used to stop a sudden transition. - Instead, the time specified will be used to cross fade between the sounds that go silent and the ones that become audible. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - SoundGroup::setMaxAudibleBehavior - SoundGroup::getMaxAudibleBehavior - SoundGroup::setMaxAudible - SoundGroup::getMaxAudible - SoundGroup::setMuteFadeSpeed - SoundGroup::getMuteFadeSpeed -] -*/ -typedef enum -{ - FMOD_SOUNDGROUP_BEHAVIOR_FAIL, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will simply fail during System::playSound. */ - FMOD_SOUNDGROUP_BEHAVIOR_MUTE, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will be silent, then if another sound in the group stops the sound that was silent before becomes audible again. */ - FMOD_SOUNDGROUP_BEHAVIOR_STEALLOWEST, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will steal the quietest / least important sound playing in the group. */ - - FMOD_SOUNDGROUP_BEHAVIOR_MAX, /* Maximum number of open state types. */ - FMOD_SOUNDGROUP_BEHAVIOR_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_SOUNDGROUP_BEHAVIOR; - - -/* -[ENUM] -[ - [DESCRIPTION] - These callback types are used with Channel::setCallback. - - [REMARKS] - Each callback has commanddata parameters passed as int unique to the type of callback. - See reference to FMOD_CHANNEL_CALLBACK to determine what they might mean for each type of callback. - - Note! Currently the user must call System::update for these callbacks to trigger! - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Channel::setCallback - FMOD_CHANNEL_CALLBACK - System::update -] -*/ -typedef enum -{ - FMOD_CHANNEL_CALLBACKTYPE_END, /* Called when a sound ends. */ - FMOD_CHANNEL_CALLBACKTYPE_VIRTUALVOICE, /* Called when a voice is swapped out or swapped in. */ - FMOD_CHANNEL_CALLBACKTYPE_SYNCPOINT, /* Called when a syncpoint is encountered. Can be from wav file markers. */ - FMOD_CHANNEL_CALLBACKTYPE_OCCLUSION, /* Called when the channel has its geometry occlusion value calculated. Can be used to clamp or change the value. */ - - FMOD_CHANNEL_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ - FMOD_CHANNEL_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_CHANNEL_CALLBACKTYPE; - - -/* -[ENUM] -[ - [DESCRIPTION] - These callback types are used with System::setCallback. - - [REMARKS] - Each callback has commanddata parameters passed as void* unique to the type of callback. - See reference to FMOD_SYSTEM_CALLBACK to determine what they might mean for each type of callback. - - Note! Using FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED (on Mac only) requires the application to be running an event loop which will allow external changes to device list to be detected by FMOD. - - Note! The 'system' object pointer will be null for FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED and FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED callbacks. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::setCallback - FMOD_SYSTEM_CALLBACK - System::update - DSP::addInput -] -*/ -typedef enum -{ - FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED, /* Called from System::update when the enumerated list of devices has changed. */ - FMOD_SYSTEM_CALLBACKTYPE_DEVICELOST, /* Called from System::update when an output device has been lost due to control panel parameter changes and FMOD cannot automatically recover. */ - FMOD_SYSTEM_CALLBACKTYPE_MEMORYALLOCATIONFAILED, /* Called directly when a memory allocation fails somewhere in FMOD. (NOTE - 'system' will be NULL in this callback type.)*/ - FMOD_SYSTEM_CALLBACKTYPE_THREADCREATED, /* Called directly when a thread is created. (NOTE - 'system' will be NULL in this callback type.) */ - FMOD_SYSTEM_CALLBACKTYPE_BADDSPCONNECTION, /* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ - FMOD_SYSTEM_CALLBACKTYPE_BADDSPLEVEL, /* Called when too many effects were added exceeding the maximum tree depth of 128. This is most likely caused by accidentally adding too many DSP effects. Usually called from mixer thread because that is where the connections are made. */ - - FMOD_SYSTEM_CALLBACKTYPE_MAX, /* Maximum number of callback types supported. */ - FMOD_SYSTEM_CALLBACKTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_SYSTEM_CALLBACKTYPE; - - -/* - FMOD Callbacks -*/ -typedef FMOD_RESULT (F_CALLBACK *FMOD_SYSTEM_CALLBACK) (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACKTYPE type, void *commanddata1, void *commanddata2); - -typedef FMOD_RESULT (F_CALLBACK *FMOD_CHANNEL_CALLBACK) (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2); - -typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_NONBLOCKCALLBACK)(FMOD_SOUND *sound, FMOD_RESULT result); -typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMREADCALLBACK)(FMOD_SOUND *sound, void *data, unsigned int datalen); -typedef FMOD_RESULT (F_CALLBACK *FMOD_SOUND_PCMSETPOSCALLBACK)(FMOD_SOUND *sound, int subsound, unsigned int position, FMOD_TIMEUNIT postype); - -typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_OPENCALLBACK) (const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata); -typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_CLOSECALLBACK) (void *handle, void *userdata); -typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_READCALLBACK) (void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata); -typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_SEEKCALLBACK) (void *handle, unsigned int pos, void *userdata); -typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_ASYNCREADCALLBACK)(FMOD_ASYNCREADINFO *info, void *userdata); -typedef FMOD_RESULT (F_CALLBACK *FMOD_FILE_ASYNCCANCELCALLBACK)(void *handle, void *userdata); - -typedef void * (F_CALLBACK *FMOD_MEMORY_ALLOCCALLBACK) (unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr); -typedef void * (F_CALLBACK *FMOD_MEMORY_REALLOCCALLBACK)(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr); -typedef void (F_CALLBACK *FMOD_MEMORY_FREECALLBACK) (void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr); - -typedef float (F_CALLBACK *FMOD_3D_ROLLOFFCALLBACK) (FMOD_CHANNEL *channel, float distance); - - -/* -[ENUM] -[ - [DESCRIPTION] - List of windowing methods used in spectrum analysis to reduce leakage / transient signals intefering with the analysis. - This is a problem with analysis of continuous signals that only have a small portion of the signal sample (the fft window size). - Windowing the signal with a curve or triangle tapers the sides of the fft window to help alleviate this problem. - - [REMARKS] - Cyclic signals such as a sine wave that repeat their cycle in a multiple of the window size do not need windowing. - I.e. If the sine wave repeats every 1024, 512, 256 etc samples and the FMOD fft window is 1024, then the signal would not need windowing. - Not windowing is the same as FMOD_DSP_FFT_WINDOW_RECT, which is the default. - If the cycle of the signal (ie the sine wave) is not a multiple of the window size, it will cause frequency abnormalities, so a different windowing method is needed. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::getSpectrum - Channel::getSpectrum -] -*/ -typedef enum -{ - FMOD_DSP_FFT_WINDOW_RECT, /* w[n] = 1.0 */ - FMOD_DSP_FFT_WINDOW_TRIANGLE, /* w[n] = TRI(2n/N) */ - FMOD_DSP_FFT_WINDOW_HAMMING, /* w[n] = 0.54 - (0.46 * COS(n/N) ) */ - FMOD_DSP_FFT_WINDOW_HANNING, /* w[n] = 0.5 * (1.0 - COS(n/N) ) */ - FMOD_DSP_FFT_WINDOW_BLACKMAN, /* w[n] = 0.42 - (0.5 * COS(n/N) ) + (0.08 * COS(2.0 * n/N) ) */ - FMOD_DSP_FFT_WINDOW_BLACKMANHARRIS, /* w[n] = 0.35875 - (0.48829 * COS(1.0 * n/N)) + (0.14128 * COS(2.0 * n/N)) - (0.01168 * COS(3.0 * n/N)) */ - - FMOD_DSP_FFT_WINDOW_MAX, /* Maximum number of FFT window types supported. */ - FMOD_DSP_FFT_WINDOW_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_DSP_FFT_WINDOW; - - -/* -[ENUM] -[ - [DESCRIPTION] - List of interpolation types that the FMOD Ex software mixer supports. - - [REMARKS] - The default resampler type is FMOD_DSP_RESAMPLER_LINEAR. - Use System::setSoftwareFormat to tell FMOD the resampling quality you require for FMOD_SOFTWARE based sounds. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::setSoftwareFormat - System::getSoftwareFormat -] -*/ -typedef enum -{ - FMOD_DSP_RESAMPLER_NOINTERP, /* No interpolation. High frequency aliasing hiss will be audible depending on the sample rate of the sound. */ - FMOD_DSP_RESAMPLER_LINEAR, /* Linear interpolation (default method). Fast and good quality, causes very slight lowpass effect on low frequency sounds. */ - FMOD_DSP_RESAMPLER_CUBIC, /* Cubic interpolation. Slower than linear interpolation but better quality. */ - FMOD_DSP_RESAMPLER_SPLINE, /* 5 point spline interpolation. Slowest resampling method but best quality. */ - - FMOD_DSP_RESAMPLER_MAX, /* Maximum number of resample methods supported. */ - FMOD_DSP_RESAMPLER_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_DSP_RESAMPLER; - - -/* -[ENUM] -[ - [DESCRIPTION] - List of tag types that could be stored within a sound. These include id3 tags, metadata from netstreams and vorbis/asf data. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Sound::getTag -] -*/ -typedef enum -{ - FMOD_TAGTYPE_UNKNOWN = 0, - FMOD_TAGTYPE_ID3V1, - FMOD_TAGTYPE_ID3V2, - FMOD_TAGTYPE_VORBISCOMMENT, - FMOD_TAGTYPE_SHOUTCAST, - FMOD_TAGTYPE_ICECAST, - FMOD_TAGTYPE_ASF, - FMOD_TAGTYPE_MIDI, - FMOD_TAGTYPE_PLAYLIST, - FMOD_TAGTYPE_FMOD, - FMOD_TAGTYPE_USER, - - FMOD_TAGTYPE_MAX, /* Maximum number of tag types supported. */ - FMOD_TAGTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_TAGTYPE; - - -/* -[ENUM] -[ - [DESCRIPTION] - List of data types that can be returned by Sound::getTag - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Sound::getTag -] -*/ -typedef enum -{ - FMOD_TAGDATATYPE_BINARY = 0, - FMOD_TAGDATATYPE_INT, - FMOD_TAGDATATYPE_FLOAT, - FMOD_TAGDATATYPE_STRING, - FMOD_TAGDATATYPE_STRING_UTF16, - FMOD_TAGDATATYPE_STRING_UTF16BE, - FMOD_TAGDATATYPE_STRING_UTF8, - FMOD_TAGDATATYPE_CDTOC, - - FMOD_TAGDATATYPE_MAX, /* Maximum number of tag datatypes supported. */ - FMOD_TAGDATATYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_TAGDATATYPE; - - -/* -[ENUM] -[ - [DESCRIPTION] - Types of delay that can be used with Channel::setDelay / Channel::getDelay. - - [REMARKS] - If you haven't called Channel::setDelay yet, if you call Channel::getDelay with FMOD_DELAYTYPE_DSPCLOCK_START it will return the - equivalent global DSP clock value to determine when a channel started, so that you can use it for other channels to sync against. - - Use System::getDSPClock to also get the current dspclock time, a base for future calls to Channel::setDelay. - - Use FMOD_64BIT_ADD or FMOD_64BIT_SUB to add a hi/lo combination together and cope with wraparound. - - If FMOD_DELAYTYPE_END_MS is specified, the value is not treated as a 64 bit number, just the delayhi value is used and it is treated as milliseconds. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Channel::setDelay - Channel::getDelay - System::getDSPClock -] -*/ -typedef enum -{ - FMOD_DELAYTYPE_END_MS, /* Delay at the end of the sound in milliseconds. Use delayhi only. Channel::isPlaying will remain true until this delay has passed even though the sound itself has stopped playing.*/ - FMOD_DELAYTYPE_DSPCLOCK_START, /* Time the sound started if Channel::getDelay is used, or if Channel::setDelay is used, the sound will delay playing until this exact tick. */ - FMOD_DELAYTYPE_DSPCLOCK_END, /* Time the sound should end. If this is non-zero, the channel will go silent at this exact tick. */ - FMOD_DELAYTYPE_DSPCLOCK_PAUSE, /* Time the sound should pause. If this is non-zero, the channel will pause at this exact tick. */ - - FMOD_DELAYTYPE_MAX, /* Maximum number of tag datatypes supported. */ - FMOD_DELAYTYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_DELAYTYPE; - - -#define FMOD_64BIT_ADD(_hi1, _lo1, _hi2, _lo2) _hi1 += ((_hi2) + ((((_lo1) + (_lo2)) < (_lo1)) ? 1 : 0)); (_lo1) += (_lo2); -#define FMOD_64BIT_SUB(_hi1, _lo1, _hi2, _lo2) _hi1 -= ((_hi2) + ((((_lo1) - (_lo2)) > (_lo1)) ? 1 : 0)); (_lo1) -= (_lo2); - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure describing a piece of tag data. - - [REMARKS] - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Sound::getTag - FMOD_TAGTYPE - FMOD_TAGDATATYPE -] -*/ -typedef struct FMOD_TAG -{ - FMOD_TAGTYPE type; /* [r] The type of this tag. */ - FMOD_TAGDATATYPE datatype; /* [r] The type of data that this tag contains */ - char *name; /* [r] The name of this tag i.e. "TITLE", "ARTIST" etc. */ - void *data; /* [r] Pointer to the tag data - its format is determined by the datatype member */ - unsigned int datalen; /* [r] Length of the data contained in this tag */ - FMOD_BOOL updated; /* [r] True if this tag has been updated since last being accessed with Sound::getTag */ -} FMOD_TAG; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure describing a CD/DVD table of contents - - [REMARKS] - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Sound::getTag -] -*/ -typedef struct FMOD_CDTOC -{ - int numtracks; /* [r] The number of tracks on the CD */ - int min[100]; /* [r] The start offset of each track in minutes */ - int sec[100]; /* [r] The start offset of each track in seconds */ - int frame[100]; /* [r] The start offset of each track in frames */ -} FMOD_CDTOC; - - -/* -[DEFINE] -[ - [NAME] - FMOD_TIMEUNIT - - [DESCRIPTION] - List of time types that can be returned by Sound::getLength and used with Channel::setPosition or Channel::getPosition. - - [REMARKS] - FMOD_TIMEUNIT_SENTENCE_MS, FMOD_TIMEUNIT_SENTENCE_PCM, FMOD_TIMEUNIT_SENTENCE_PCMBYTES, FMOD_TIMEUNIT_SENTENCE and FMOD_TIMEUNIT_SENTENCE_SUBSOUND are only supported by Channel functions. - Do not combine flags except FMOD_TIMEUNIT_BUFFERED. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Sound::getLength - Channel::setPosition - Channel::getPosition -] -*/ -#define FMOD_TIMEUNIT_MS 0x00000001 /* Milliseconds. */ -#define FMOD_TIMEUNIT_PCM 0x00000002 /* PCM samples, related to milliseconds * samplerate / 1000. */ -#define FMOD_TIMEUNIT_PCMBYTES 0x00000004 /* Bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ -#define FMOD_TIMEUNIT_RAWBYTES 0x00000008 /* Raw file bytes of (compressed) sound data (does not include headers). Only used by Sound::getLength and Channel::getPosition. */ -#define FMOD_TIMEUNIT_PCMFRACTION 0x00000010 /* Fractions of 1 PCM sample. Unsigned int range 0 to 0xFFFFFFFF. Used for sub-sample granularity for DSP purposes. */ -#define FMOD_TIMEUNIT_MODORDER 0x00000100 /* MOD/S3M/XM/IT. Order in a sequenced module format. Use Sound::getFormat to determine the PCM format being decoded to. */ -#define FMOD_TIMEUNIT_MODROW 0x00000200 /* MOD/S3M/XM/IT. Current row in a sequenced module format. Sound::getLength will return the number of rows in the currently playing or seeked to pattern. */ -#define FMOD_TIMEUNIT_MODPATTERN 0x00000400 /* MOD/S3M/XM/IT. Current pattern in a sequenced module format. Sound::getLength will return the number of patterns in the song and Channel::getPosition will return the currently playing pattern. */ -#define FMOD_TIMEUNIT_SENTENCE_MS 0x00010000 /* Currently playing subsound in a sentence time in milliseconds. */ -#define FMOD_TIMEUNIT_SENTENCE_PCM 0x00020000 /* Currently playing subsound in a sentence time in PCM Samples, related to milliseconds * samplerate / 1000. */ -#define FMOD_TIMEUNIT_SENTENCE_PCMBYTES 0x00040000 /* Currently playing subsound in a sentence time in bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ -#define FMOD_TIMEUNIT_SENTENCE 0x00080000 /* Currently playing sentence index according to the channel. */ -#define FMOD_TIMEUNIT_SENTENCE_SUBSOUND 0x00100000 /* Currently playing subsound index in a sentence. */ -#define FMOD_TIMEUNIT_BUFFERED 0x10000000 /* Time value as seen by buffered stream. This is always ahead of audible time, and is only used for processing. */ -/* [DEFINE_END] */ - - -/* -[ENUM] -[ - [DESCRIPTION] - When creating a multichannel sound, FMOD will pan them to their default speaker locations, for example a 6 channel sound will default to one channel per 5.1 output speaker. - Another example is a stereo sound. It will default to left = front left, right = front right. - - This is for sounds that are not 'default'. For example you might have a sound that is 6 channels but actually made up of 3 stereo pairs, that should all be located in front left, front right only. - - [REMARKS] - For full flexibility of speaker assignments, use Channel::setSpeakerLevels. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_CREATESOUNDEXINFO - Channel::setSpeakerLevels -] -*/ -typedef enum -{ - FMOD_SPEAKERMAPTYPE_DEFAULT, /* This is the default, and just means FMOD decides which speakers it puts the source channels. */ - FMOD_SPEAKERMAPTYPE_ALLMONO, /* This means the sound is made up of all mono sounds. All voices will be panned to the front center by default in this case. */ - FMOD_SPEAKERMAPTYPE_ALLSTEREO, /* This means the sound is made up of all stereo sounds. All voices will be panned to front left and front right alternating every second channel. */ - FMOD_SPEAKERMAPTYPE_51_PROTOOLS /* Map a 5.1 sound to use protools L C R Ls Rs LFE mapping. Will return an error if not a 6 channel sound. */ -} FMOD_SPEAKERMAPTYPE; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Use this structure with System::createSound when more control is needed over loading. - The possible reasons to use this with System::createSound are: - - Loading a file from memory. - - Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. - - To create a user created / non file based sound. - - To specify a starting subsound to seek to within a multi-sample sounds (ie FSB/DLS/SF2) when created as a stream. - - To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. - - To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. - - To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. - See below on what members to fill for each of the above types of sound you want to create. - - [REMARKS] - This structure is optional! Specify 0 or NULL in System::createSound if you don't need it! - - Loading a file from memory. - - Create the sound using the FMOD_OPENMEMORY flag. - - Mandatory. Specify 'length' for the size of the memory block in bytes. - - Other flags are optional. - - - Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. - - Mandatory. Specify 'fileoffset' and 'length'. - - Other flags are optional. - - - To create a user created / non file based sound. - - Create the sound using the FMOD_OPENUSER flag. - - Mandatory. Specify 'defaultfrequency, 'numchannels' and 'format'. - - Other flags are optional. - - - To specify a starting subsound to seek to and flush with, within a multi-sample stream (ie FSB/DLS/SF2). - - - Mandatory. Specify 'initialsubsound'. - - - To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. - - - Mandatory. Specify 'inclusionlist' and 'inclusionlistnum'. - - - To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. - - - Mandatory. Specify 'pcmreadcallback' and 'pcmseekcallback'. - - - To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. - - - Mandatory. Specify 'dlsname'. - - - Setting the 'decodebuffersize' is for cpu intensive codecs that may be causing stuttering, not file intensive codecs (ie those from CD or netstreams) which are normally - altered with System::setStreamBufferSize. As an example of cpu intensive codecs, an mp3 file will take more cpu to decode than a PCM wav file. - If you have a stuttering effect, then it is using more cpu than the decode buffer playback rate can keep up with. Increasing the decode buffersize will most likely solve this problem. - - - FSB codec. If inclusionlist and numsubsounds are used together, this will trigger a special mode where subsounds are shuffled down to save memory. (useful for large FSB - files where you only want to load 1 sound). There will be no gaps, ie no null subsounds. As an example, if there are 10,000 subsounds and there is an inclusionlist with only 1 entry, - and numsubsounds = 1, then subsound 0 will be that entry, and there will only be the memory allocated for 1 subsound. Previously there would still be 10,000 subsound pointers and other - associated codec entries allocated along with it multiplied by 10,000. - - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::createSound - System::setStreamBufferSize - FMOD_MODE - FMOD_SOUND_FORMAT - FMOD_SOUND_TYPE - FMOD_SPEAKERMAPTYPE -] -*/ -typedef struct FMOD_CREATESOUNDEXINFO -{ - int cbsize; /* [w] Size of this structure. This is used so the structure can be expanded in the future and still work on older versions of FMOD Ex. */ - unsigned int length; /* [w] Optional. Specify 0 to ignore. Size in bytes of file to load, or sound to create (in this case only if FMOD_OPENUSER is used). Required if loading from memory. If 0 is specified, then it will use the size of the file (unless loading from memory then an error will be returned). */ - unsigned int fileoffset; /* [w] Optional. Specify 0 to ignore. Offset from start of the file to start loading from. This is useful for loading files from inside big data files. */ - int numchannels; /* [w] Optional. Specify 0 to ignore. Number of channels in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. */ - int defaultfrequency; /* [w] Optional. Specify 0 to ignore. Default frequency of sound in a sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the frequency determined by the file format. */ - FMOD_SOUND_FORMAT format; /* [w] Optional. Specify 0 or FMOD_SOUND_FORMAT_NONE to ignore. Format of the sound mandatory if FMOD_OPENUSER or FMOD_OPENRAW is used. Other formats use the format determined by the file format. */ - unsigned int decodebuffersize; /* [w] Optional. Specify 0 to ignore. For streams. This determines the size of the double buffer (in PCM samples) that a stream uses. Use this for user created streams if you want to determine the size of the callback buffer passed to you. Specify 0 to use FMOD's default size which is currently equivalent to 400ms of the sound format created/loaded. */ - int initialsubsound; /* [w] Optional. Specify 0 to ignore. In a multi-sample file format such as .FSB/.DLS/.SF2, specify the initial subsound to seek to, only if FMOD_CREATESTREAM is used. */ - int numsubsounds; /* [w] Optional. Specify 0 to ignore or have no subsounds. In a sound created with FMOD_OPENUSER, specify the number of subsounds that are accessable with Sound::getSubSound. If not created with FMOD_OPENUSER, this will limit the number of subsounds loaded within a multi-subsound file. If using FSB, then if FMOD_CREATESOUNDEXINFO::inclusionlist is used, this will shuffle subsounds down so that there are not any gaps. It will mean that the indices of the sounds will be different. */ - int *inclusionlist; /* [w] Optional. Specify 0 to ignore. In a multi-sample format such as .FSB/.DLS/.SF2 it may be desirable to specify only a subset of sounds to be loaded out of the whole file. This is an array of subsound indices to load into memory when created. */ - int inclusionlistnum; /* [w] Optional. Specify 0 to ignore. This is the number of integers contained within the inclusionlist array. */ - FMOD_SOUND_PCMREADCALLBACK pcmreadcallback; /* [w] Optional. Specify 0 to ignore. Callback to 'piggyback' on FMOD's read functions and accept or even write PCM data while FMOD is opening the sound. Used for user sounds created with FMOD_OPENUSER or for capturing decoded data as FMOD reads it. */ - FMOD_SOUND_PCMSETPOSCALLBACK pcmsetposcallback; /* [w] Optional. Specify 0 to ignore. Callback for when the user calls a seeking function such as Channel::setTime or Channel::setPosition within a multi-sample sound, and for when it is opened.*/ - FMOD_SOUND_NONBLOCKCALLBACK nonblockcallback; /* [w] Optional. Specify 0 to ignore. Callback for successful completion, or error while loading a sound that used the FMOD_NONBLOCKING flag.*/ - const char *dlsname; /* [w] Optional. Specify 0 to ignore. Filename for a DLS or SF2 sample set when loading a MIDI file. If not specified, on Windows it will attempt to open /windows/system32/drivers/gm.dls or /windows/system32/drivers/etc/gm.dls, on Mac it will attempt to load /System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls, otherwise the MIDI will fail to open. Current DLS support is for level 1 of the specification. */ - const char *encryptionkey; /* [w] Optional. Specify 0 to ignore. Key for encrypted FSB file. Without this key an encrypted FSB file will not load. */ - int maxpolyphony; /* [w] Optional. Specify 0 to ignore. For sequenced formats with dynamic channel allocation such as .MID and .IT, this specifies the maximum voice count allowed while playing. .IT defaults to 64. .MID defaults to 32. */ - void *userdata; /* [w] Optional. Specify 0 to ignore. This is user data to be attached to the sound during creation. Access via Sound::getUserData. Note: This is not passed to FMOD_FILE_OPENCALLBACK, that is a different userdata that is file specific. */ - FMOD_SOUND_TYPE suggestedsoundtype; /* [w] Optional. Specify 0 or FMOD_SOUND_TYPE_UNKNOWN to ignore. Instead of scanning all codec types, use this to speed up loading by making it jump straight to this codec. */ - FMOD_FILE_OPENCALLBACK useropen; /* [w] Optional. Specify 0 to ignore. Callback for opening this file. */ - FMOD_FILE_CLOSECALLBACK userclose; /* [w] Optional. Specify 0 to ignore. Callback for closing this file. */ - FMOD_FILE_READCALLBACK userread; /* [w] Optional. Specify 0 to ignore. Callback for reading from this file. */ - FMOD_FILE_SEEKCALLBACK userseek; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ - FMOD_FILE_ASYNCREADCALLBACK userasyncread; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ - FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel; /* [w] Optional. Specify 0 to ignore. Callback for seeking within this file. */ - FMOD_SPEAKERMAPTYPE speakermap; /* [w] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_SPEAKERMAPTYPE for more. */ - FMOD_SOUNDGROUP *initialsoundgroup; /* [w] Optional. Specify 0 to ignore. Specify a sound group if required, to put sound in as it is created. */ - unsigned int initialseekposition;/* [w] Optional. Specify 0 to ignore. For streams. Specify an initial position to seek the stream to. */ - FMOD_TIMEUNIT initialseekpostype; /* [w] Optional. Specify 0 to ignore. For streams. Specify the time unit for the position set in initialseekposition. */ - int ignoresetfilesystem;/* [w] Optional. Specify 0 to ignore. Set to 1 to use fmod's built in file system. Ignores setFileSystem callbacks and also FMOD_CREATESOUNEXINFO file callbacks. Useful for specific cases where you don't want to use your own file system but want to use fmod's file system (ie net streaming). */ - int cddaforceaspi; /* [w] Optional. Specify 0 to ignore. For CDDA sounds only - if non-zero use ASPI instead of NTSCSI to access the specified CD/DVD device. */ - unsigned int audioqueuepolicy; /* [w] Optional. Specify 0 or FMOD_AUDIOQUEUE_CODECPOLICY_DEFAULT to ignore. Policy used to determine whether hardware or software is used for decoding, see FMOD_AUDIOQUEUE_CODECPOLICY for options (iOS >= 3.0 required, otherwise only hardware is available) */ - unsigned int minmidigranularity; /* [w] Optional. Specify 0 to ignore. Allows you to set a minimum desired MIDI mixer granularity. Values smaller than 512 give greater than default accuracy at the cost of more CPU and vice versa. Specify 0 for default (512 samples). */ - int nonblockthreadid; /* [w] Optional. Specify 0 to ignore. Specifies a thread index to execute non blocking load on. Allows for up to 5 threads to be used for loading at once. This is to avoid one load blocking another. Maximum value = 4. */ -} FMOD_CREATESOUNDEXINFO; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure defining a reverb environment. - - [REMARKS] - Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset. - Note that integer values that typically range from -10,000 to 1000 are represented in - decibels, and are of a logarithmic scale, not linear, wheras float values are always linear. - - The numerical values listed below are the maximum, minimum and default values for each variable respectively. - - SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't. - WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE). - PSP means Playstation Portable hardware reverb (must use FMOD_HARDWARE). - SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds. - --- means unsupported/deprecated. Will either be removed or supported by SFX in the future. - - Nintendo Wii Notes: - This structure supports only limited parameters, and maps them to the Wii hardware reverb as follows. - DecayTime = 'time' - ReverbDelay = 'predelay' - ModulationDepth = 'damping' - Reflections = 'coloration' - EnvDiffusion = 'crosstalk' - Room = 'mix' - - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - Members marked with [r/w] are either read or write depending on if you are using System::setReverbProperties (w) or System::getReverbProperties (r). - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::setReverbProperties - System::getReverbProperties - FMOD_REVERB_PRESETS - FMOD_REVERB_FLAGS -] -*/ -typedef struct FMOD_REVERB_PROPERTIES -{ /* MIN MAX DEFAULT DESCRIPTION */ - int Instance; /* [w] 0 3 0 Environment Instance. (SUPPORTED:SFX(4 instances) and Wii (3 instances)) */ - int Environment; /* [r/w] -1 25 -1 Sets all listener properties. -1 = OFF. (SUPPORTED:SFX(-1 only)/PSP) */ - float EnvDiffusion; /* [r/w] 0.0 1.0 1.0 Environment diffusion (SUPPORTED:WII) */ - int Room; /* [r/w] -10000 0 -1000 Room effect level (at mid frequencies) (SUPPORTED:SFX/WII/PSP) */ - int RoomHF; /* [r/w] -10000 0 -100 Relative room effect level at high frequencies (SUPPORTED:SFX) */ - int RoomLF; /* [r/w] -10000 0 0 Relative room effect level at low frequencies (SUPPORTED:SFX) */ - float DecayTime; /* [r/w] 0.1 20.0 1.49 Reverberation decay time at mid frequencies (SUPPORTED:SFX/WII) */ - float DecayHFRatio; /* [r/w] 0.1 2.0 0.83 High-frequency to mid-frequency decay time ratio (SUPPORTED:SFX) */ - float DecayLFRatio; /* [r/w] 0.1 2.0 1.0 Low-frequency to mid-frequency decay time ratio (SUPPORTED:---) */ - int Reflections; /* [r/w] -10000 1000 -2602 Early reflections level relative to room effect (SUPPORTED:SFX/WII) */ - float ReflectionsDelay; /* [r/w] 0.0 0.3 0.007 Initial reflection delay time (SUPPORTED:SFX) */ - int Reverb; /* [r/w] -10000 2000 200 Late reverberation level relative to room effect (SUPPORTED:SFX) */ - float ReverbDelay; /* [r/w] 0.0 0.1 0.011 Late reverberation delay time relative to initial reflection (SUPPORTED:SFX/WII) */ - float ModulationTime; /* [r/w] 0.04 4.0 0.25 Modulation time (SUPPORTED:---) */ - float ModulationDepth; /* [r/w] 0.0 1.0 0.0 Modulation depth (SUPPORTED:WII) */ - float HFReference; /* [r/w] 20.0 20000.0 5000.0 Reference high frequency (hz) (SUPPORTED:SFX) */ - float LFReference; /* [r/w] 20.0 1000.0 250.0 Reference low frequency (hz) (SUPPORTED:SFX) */ - float Diffusion; /* [r/w] 0.0 100.0 100.0 Value that controls the echo density in the late reverberation decay. (SUPPORTED:SFX) */ - float Density; /* [r/w] 0.0 100.0 100.0 Value that controls the modal density in the late reverberation decay (SUPPORTED:SFX) */ - unsigned int Flags; /* [r/w] FMOD_REVERB_FLAGS - modifies the behavior of above properties (SUPPORTED:WII) */ -} FMOD_REVERB_PROPERTIES; - - -/* -[DEFINE] -[ - [NAME] - FMOD_REVERB_FLAGS - - [DESCRIPTION] - Values for the Flags member of the FMOD_REVERB_PROPERTIES structure. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_REVERB_PROPERTIES -] -*/ -#define FMOD_REVERB_FLAGS_HIGHQUALITYREVERB 0x00000400 /* Wii. Use high quality reverb */ -#define FMOD_REVERB_FLAGS_HIGHQUALITYDPL2REVERB 0x00000800 /* Wii. Use high quality DPL2 reverb */ -#define FMOD_REVERB_FLAGS_HARDWAREONLY 0x00001000 /* Don't create an SFX reverb for FMOD_SOFTWARE channels, hardware reverb only */ -#define FMOD_REVERB_FLAGS_DEFAULT 0x00000000 -/* [DEFINE_END] */ - - -/* -[DEFINE] -[ - [NAME] - FMOD_REVERB_PRESETS - - [DESCRIPTION] - A set of predefined environment PARAMETERS. - These are used to initialize an FMOD_REVERB_PROPERTIES structure statically. - i.e. - FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_GENERIC; - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::setReverbProperties -] -*/ -/* Inst Env Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel Revb RevDel ModTm ModDp HFRef LFRef Diffus Densty FLAGS */ -#define FMOD_PRESET_OFF { 0, -1, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 0.0f, 0.0f, 0x33f } -#define FMOD_PRESET_GENERIC { 0, 0, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_PADDEDCELL { 0, 1, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, 207, 0.002f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_ROOM { 0, 2, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, 53, 0.003f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_BATHROOM { 0, 3, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, 1030, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 60.0f, 0x3f } -#define FMOD_PRESET_LIVINGROOM { 0, 4, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, -1104, 0.004f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_STONEROOM { 0, 5, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, 83, 0.017f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_AUDITORIUM { 0, 6, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, -289, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_CONCERTHALL { 0, 7, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, -2, 0.029f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_CAVE { 0, 8, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, -302, 0.022f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f } -#define FMOD_PRESET_ARENA { 0, 9, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, 16, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_HANGAR { 0, 10, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, 198, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_CARPETTEDHALLWAY { 0, 11, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, -1630, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_HALLWAY { 0, 12, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, 441, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_STONECORRIDOR { 0, 13, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, 395, 0.020f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_ALLEY { 0, 14, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, -4, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_FOREST { 0, 15, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, -229, 0.088f, 0.25f, 0.000f, 5000.0f, 250.0f, 79.0f, 100.0f, 0x3f } -#define FMOD_PRESET_CITY { 0, 16, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, -1691, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 50.0f, 100.0f, 0x3f } -#define FMOD_PRESET_MOUNTAINS { 0, 17, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, -1434, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 27.0f, 100.0f, 0x1f } -#define FMOD_PRESET_QUARRY { 0, 18, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, 500, 0.025f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } -#define FMOD_PRESET_PLAIN { 0, 19, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, -1926, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 21.0f, 100.0f, 0x3f } -#define FMOD_PRESET_PARKINGLOT { 0, 20, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, -1153, 0.012f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f } -#define FMOD_PRESET_SEWERPIPE { 0, 21, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, 1023, 0.021f, 0.25f, 0.000f, 5000.0f, 250.0f, 80.0f, 60.0f, 0x3f } -#define FMOD_PRESET_UNDERWATER { 0, 22, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, 1700, 0.011f, 1.18f, 0.348f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f } - -/* PlayStation Portable Only presets */ -#define FMOD_PRESET_PSP_ROOM { 0, 1, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_STUDIO_A { 0, 2, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_STUDIO_B { 0, 3, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_STUDIO_C { 0, 4, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_HALL { 0, 5, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_SPACE { 0, 6, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_ECHO { 0, 7, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_DELAY { 0, 8, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -#define FMOD_PRESET_PSP_PIPE { 0, 9, 0, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0, 0.000f, 0, 0.000f, 0.00f, 0.000f, 0000.0f, 0.0f, 0.0f, 0.0f, 0x31f } -/* [DEFINE_END] */ - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure defining the properties for a reverb source, related to a FMOD channel. - - Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset. - Note that integer values that typically range from -10,000 to 1000 are represented in - decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear. - PORTABILITY: Each member has the platform it supports in braces ie (win32/wii). - - The numerical values listed below are the maximum, minimum and default values for each variable respectively. - - [REMARKS] - SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't. - WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE). - PSP means Playstation Portable hardware reverb (must use FMOD_HARDWARE). - SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds. - --- means unsupported/deprecated. Will either be removed or supported by SFX in the future. - - - 'ConnectionPoint' Parameter. This parameter is for the FMOD software reverb only (known as SFX in the list above). - By default the dsp network connection for a channel and its reverb is between the 'SFX Reverb' unit, and the channel's wavetable/resampler/dspcodec/oscillator unit (the unit below the channel DSP head). NULL can be used for this parameter to make it use this default behaviour. - This parameter allows the user to connect the SFX reverb to somewhere else internally, for example the channel DSP head, or a related channelgroup. The event system uses this so that it can have the output of an event going to the reverb, instead of just the output of the event's channels (thereby ignoring event effects/submixes etc). - Do not use if you are unaware of DSP network connection issues. Leave it at the default of NULL instead. - - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - Members marked with [r/w] are either read or write depending on if you are using Channel::setReverbProperties (w) or Channel::getReverbProperties (r). - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - Channel::setReverbProperties - Channel::getReverbProperties - FMOD_REVERB_CHANNELFLAGS -] -*/ -typedef struct FMOD_REVERB_CHANNELPROPERTIES -{ /* MIN MAX DEFAULT DESCRIPTION */ - int Direct; /* [r/w] -10000 1000 0 Direct path level (SUPPORTED:SFX) */ - int Room; /* [r/w] -10000 1000 0 Room effect level (SUPPORTED:SFX) */ - unsigned int Flags; /* [r/w] FMOD_REVERB_CHANNELFLAGS - modifies the behavior of properties (SUPPORTED:SFX) */ - FMOD_DSP *ConnectionPoint; /* [r/w] See remarks. DSP network location to connect reverb for this channel. (SUPPORTED:SFX).*/ -} FMOD_REVERB_CHANNELPROPERTIES; - - -/* -[DEFINE] -[ - [NAME] - FMOD_REVERB_CHANNELFLAGS - - [DESCRIPTION] - Values for the Flags member of the FMOD_REVERB_CHANNELPROPERTIES structure. - - [REMARKS] - For SFX Reverb, there is support for multiple reverb environments. - Use FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT0 to FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT3 in the flags member - of FMOD_REVERB_CHANNELPROPERTIES to specify which environment instance(s) to target. - - If you do not specify any instance the first reverb instance will be used. - - If you specify more than one instance with getReverbProperties, the first instance will be used. - - If you specify more than one instance with setReverbProperties, it will set more than 1 instance at once. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_REVERB_CHANNELPROPERTIES -] -*/ -#define FMOD_REVERB_CHANNELFLAGS_INSTANCE0 0x00000010 /* SFX/Wii. Specify channel to target reverb instance 0. Default target. */ -#define FMOD_REVERB_CHANNELFLAGS_INSTANCE1 0x00000020 /* SFX/Wii. Specify channel to target reverb instance 1. */ -#define FMOD_REVERB_CHANNELFLAGS_INSTANCE2 0x00000040 /* SFX/Wii. Specify channel to target reverb instance 2. */ -#define FMOD_REVERB_CHANNELFLAGS_INSTANCE3 0x00000080 /* SFX. Specify channel to target reverb instance 3. */ - -#define FMOD_REVERB_CHANNELFLAGS_DEFAULT FMOD_REVERB_CHANNELFLAGS_INSTANCE0 -/* [DEFINE_END] */ - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Settings for advanced features like configuring memory and cpu usage for the FMOD_CREATECOMPRESSEDSAMPLE feature. - - [REMARKS] - maxMPEGcodecs / maxADPCMcodecs / maxXMAcodecs will determine the maximum cpu usage of playing realtime samples. Use this to lower potential excess cpu usage and also control memory usage. - - maxPCMcodecs is for use with PS3 only. It will determine the maximum number of PCM voices that can be played at once. This includes streams of any format and all sounds created - *without* the FMOD_CREATECOMPRESSEDSAMPLE flag. - - Memory will be allocated for codecs 'up front' (during System::init) if these values are specified as non zero. If any are zero, it allocates memory for the codec whenever a file of the type in question is loaded. So if maxMPEGcodecs is 0 for example, it will allocate memory for the mpeg codecs the first time an mp3 is loaded or an mp3 based .FSB file is loaded. - - Due to inefficient encoding techniques on certain .wav based ADPCM files, FMOD can can need an extra 29720 bytes per codec. This means for lowest memory consumption. Use FSB as it uses an optimal/small ADPCM block size. - - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - Members marked with [r/w] are either read or write depending on if you are using System::setAdvancedSettings (w) or System::getAdvancedSettings (r). - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::setAdvancedSettings - System::getAdvancedSettings - System::init - FMOD_MODE -] -*/ -typedef struct FMOD_ADVANCEDSETTINGS -{ - int cbsize; /* [w] Size of this structure. Use sizeof(FMOD_ADVANCEDSETTINGS) NOTE: This must be set before calling System::getAdvancedSettings! */ - int maxMPEGcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Mpeg codecs consume 21,684 bytes per instance and this number will determine how many mpeg channels can be played simultaneously. Default = 32. */ - int maxADPCMcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. ADPCM codecs consume 2,136 bytes per instance and this number will determine how many ADPCM channels can be played simultaneously. Default = 32. */ - int maxXMAcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. XMA codecs consume 14,836 bytes per instance and this number will determine how many XMA channels can be played simultaneously. Default = 32. */ - int maxCELTcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. CELT codecs consume 11,500 bytes per instance and this number will determine how many CELT channels can be played simultaneously. Default = 32. */ - int maxVORBIScodecs; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Vorbis codecs consume 12,000 bytes per instance and this number will determine how many Vorbis channels can be played simultaneously. Default = 32. */ - int maxPCMcodecs; /* [r/w] Optional. Specify 0 to ignore. For use with PS3 only. PCM codecs consume 12,672 bytes per instance and this number will determine how many streams and PCM voices can be played simultaneously. Default = 16. */ - int ASIONumChannels; /* [r/w] Optional. Specify 0 to ignore. Number of channels available on the ASIO device. */ - char **ASIOChannelList; /* [r/w] Optional. Specify 0 to ignore. Pointer to an array of strings (number of entries defined by ASIONumChannels) with ASIO channel names. */ - FMOD_SPEAKER *ASIOSpeakerList; /* [r/w] Optional. Specify 0 to ignore. Pointer to a list of speakers that the ASIO channels map to. This can be called after System::init to remap ASIO output. */ - int max3DReverbDSPs; /* [r/w] Optional. Specify 0 to ignore. The max number of 3d reverb DSP's in the system. (NOTE: CURRENTLY DISABLED / UNUSED) */ - float HRTFMinAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function begins to have an effect. 0 = in front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 180.0. */ - float HRTFMaxAngle; /* [r/w] Optional. For use with FMOD_INIT_HRTF_LOWPASS. The angle range (0-360) of a 3D sound in relation to the listener, at which the HRTF function has maximum effect. 0 = front of the listener. 180 = from 90 degrees to the left of the listener to 90 degrees to the right. 360 = behind the listener. Default = 360.0. */ - float HRTFFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_HRTF_LOWPASS. The cutoff frequency of the HRTF's lowpass filter function when at maximum effect. (i.e. at HRTFMaxAngle). Default = 4000.0. */ - float vol0virtualvol; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_VOL0_BECOMES_VIRTUAL. If this flag is used, and the volume is 0.0, then the sound will become virtual. Use this value to raise the threshold to a different point where a sound goes virtual. */ - int eventqueuesize; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD Event system only. Specifies the number of slots available for simultaneous non blocking loads, across all threads. Default = 32. */ - unsigned int defaultDecodeBufferSize; /* [r/w] Optional. Specify 0 to ignore. For streams. This determines the default size of the double buffer (in milliseconds) that a stream uses. Default = 400ms */ - char *debugLogFilename; /* [r/w] Optional. Specify 0 to ignore. Gives fmod's logging system a path/filename. Normally the log is placed in the same directory as the executable and called fmod.log. When using System::getAdvancedSettings, provide at least 256 bytes of memory to copy into. */ - unsigned short profileport; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_ENABLE_PROFILE. Specify the port to listen on for connections by the profiler application. */ - unsigned int geometryMaxFadeTime; /* [r/w] Optional. Specify 0 to ignore. The maximum time in miliseconds it takes for a channel to fade to the new level when its occlusion changes. */ - unsigned int maxSpectrumWaveDataBuffers; /* [r/w] Optional. Specify 0 to ignore. Tells System::init to allocate a pool of wavedata/spectrum buffers to prevent memory fragmentation, any additional buffers will be allocated normally. */ - unsigned int musicSystemCacheDelay; /* [r/w] Optional. Specify 0 to ignore. The delay the music system should allow for loading a sample from disk (in milliseconds). Default = 400 ms. */ - float distanceFilterCenterFreq; /* [r/w] Optional. Specify 0 to ignore. For use with FMOD_INIT_DISTANCE_FILTERING. The default center frequency in Hz for the distance filtering effect. Default = 1500.0. */ - unsigned int stackSizeStream; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD Stream thread in bytes. Useful for custom codecs that use excess stack. Default 49,152 (48kb) */ - unsigned int stackSizeNonBlocking; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD_NONBLOCKING loading thread. Useful for custom codecs that use excess stack. Default 65,536 (64kb) */ - unsigned int stackSizeMixer; /* [r/w] Optional. Specify 0 to ignore. Specify the stack size for the FMOD mixer thread. Useful for custom dsps that use excess stack. Default 49,152 (48kb) */ -} FMOD_ADVANCEDSETTINGS; - - -/* -[ENUM] -[ - [DESCRIPTION] - Special channel index values for FMOD functions. - - [REMARKS] - To get 'all' of the channels, use System::getMasterChannelGroup. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::playSound - System::playDSP - System::getChannel - System::getMasterChannelGroup -] -*/ -typedef enum -{ - FMOD_CHANNEL_FREE = -1, /* For a channel index, FMOD chooses a free voice using the priority system. */ - FMOD_CHANNEL_REUSE = -2 /* For a channel index, re-use the channel handle that was passed in. */ -} FMOD_CHANNELINDEX; - -#include "fmod_codec.h" -#include "fmod_dsp.h" -#include "fmod_memoryinfo.h" - -/* ========================================================================================== */ -/* FUNCTION PROTOTYPES */ -/* ========================================================================================== */ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* - FMOD global system functions (optional). -*/ - -FMOD_RESULT F_API FMOD_Memory_Initialize (void *poolmem, int poollen, FMOD_MEMORY_ALLOCCALLBACK useralloc, FMOD_MEMORY_REALLOCCALLBACK userrealloc, FMOD_MEMORY_FREECALLBACK userfree, FMOD_MEMORY_TYPE memtypeflags); -FMOD_RESULT F_API FMOD_Memory_GetStats (int *currentalloced, int *maxalloced, FMOD_BOOL blocking); -FMOD_RESULT F_API FMOD_Debug_SetLevel (FMOD_DEBUGLEVEL level); -FMOD_RESULT F_API FMOD_Debug_GetLevel (FMOD_DEBUGLEVEL *level); -FMOD_RESULT F_API FMOD_File_SetDiskBusy (int busy); -FMOD_RESULT F_API FMOD_File_GetDiskBusy (int *busy); - -/* - FMOD System factory functions. Use this to create an FMOD System Instance. below you will see FMOD_System_Init/Close to get started. -*/ - -FMOD_RESULT F_API FMOD_System_Create (FMOD_SYSTEM **system); -FMOD_RESULT F_API FMOD_System_Release (FMOD_SYSTEM *system); - - -/* - 'System' API -*/ - -/* - Pre-init functions. -*/ - -FMOD_RESULT F_API FMOD_System_SetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE output); -FMOD_RESULT F_API FMOD_System_GetOutput (FMOD_SYSTEM *system, FMOD_OUTPUTTYPE *output); -FMOD_RESULT F_API FMOD_System_GetNumDrivers (FMOD_SYSTEM *system, int *numdrivers); -FMOD_RESULT F_API FMOD_System_GetDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); -FMOD_RESULT F_API FMOD_System_GetDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); -FMOD_RESULT F_API FMOD_System_GetDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *controlpaneloutputrate, FMOD_SPEAKERMODE *controlpanelspeakermode); -FMOD_RESULT F_API FMOD_System_SetDriver (FMOD_SYSTEM *system, int driver); -FMOD_RESULT F_API FMOD_System_GetDriver (FMOD_SYSTEM *system, int *driver); -FMOD_RESULT F_API FMOD_System_SetHardwareChannels (FMOD_SYSTEM *system, int numhardwarechannels); -FMOD_RESULT F_API FMOD_System_SetSoftwareChannels (FMOD_SYSTEM *system, int numsoftwarechannels); -FMOD_RESULT F_API FMOD_System_GetSoftwareChannels (FMOD_SYSTEM *system, int *numsoftwarechannels); -FMOD_RESULT F_API FMOD_System_SetSoftwareFormat (FMOD_SYSTEM *system, int samplerate, FMOD_SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, FMOD_DSP_RESAMPLER resamplemethod); -FMOD_RESULT F_API FMOD_System_GetSoftwareFormat (FMOD_SYSTEM *system, int *samplerate, FMOD_SOUND_FORMAT *format, int *numoutputchannels, int *maxinputchannels, FMOD_DSP_RESAMPLER *resamplemethod, int *bits); -FMOD_RESULT F_API FMOD_System_SetDSPBufferSize (FMOD_SYSTEM *system, unsigned int bufferlength, int numbuffers); -FMOD_RESULT F_API FMOD_System_GetDSPBufferSize (FMOD_SYSTEM *system, unsigned int *bufferlength, int *numbuffers); -FMOD_RESULT F_API FMOD_System_SetFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek, FMOD_FILE_ASYNCREADCALLBACK userasyncread, FMOD_FILE_ASYNCCANCELCALLBACK userasynccancel, int blockalign); -FMOD_RESULT F_API FMOD_System_AttachFileSystem (FMOD_SYSTEM *system, FMOD_FILE_OPENCALLBACK useropen, FMOD_FILE_CLOSECALLBACK userclose, FMOD_FILE_READCALLBACK userread, FMOD_FILE_SEEKCALLBACK userseek); -FMOD_RESULT F_API FMOD_System_SetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); -FMOD_RESULT F_API FMOD_System_GetAdvancedSettings (FMOD_SYSTEM *system, FMOD_ADVANCEDSETTINGS *settings); -FMOD_RESULT F_API FMOD_System_SetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE speakermode); -FMOD_RESULT F_API FMOD_System_GetSpeakerMode (FMOD_SYSTEM *system, FMOD_SPEAKERMODE *speakermode); -FMOD_RESULT F_API FMOD_System_SetCallback (FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK callback); - -/* - Plug-in support -*/ - -FMOD_RESULT F_API FMOD_System_SetPluginPath (FMOD_SYSTEM *system, const char *path); -FMOD_RESULT F_API FMOD_System_LoadPlugin (FMOD_SYSTEM *system, const char *filename, unsigned int *handle, unsigned int priority); -FMOD_RESULT F_API FMOD_System_UnloadPlugin (FMOD_SYSTEM *system, unsigned int handle); -FMOD_RESULT F_API FMOD_System_GetNumPlugins (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int *numplugins); -FMOD_RESULT F_API FMOD_System_GetPluginHandle (FMOD_SYSTEM *system, FMOD_PLUGINTYPE plugintype, int index, unsigned int *handle); -FMOD_RESULT F_API FMOD_System_GetPluginInfo (FMOD_SYSTEM *system, unsigned int handle, FMOD_PLUGINTYPE *plugintype, char *name, int namelen, unsigned int *version); -FMOD_RESULT F_API FMOD_System_SetOutputByPlugin (FMOD_SYSTEM *system, unsigned int handle); -FMOD_RESULT F_API FMOD_System_GetOutputByPlugin (FMOD_SYSTEM *system, unsigned int *handle); -FMOD_RESULT F_API FMOD_System_CreateDSPByPlugin (FMOD_SYSTEM *system, unsigned int handle, FMOD_DSP **dsp); -FMOD_RESULT F_API FMOD_System_RegisterCodec (FMOD_SYSTEM *system, FMOD_CODEC_DESCRIPTION *description, unsigned int *handle, unsigned int priority); -FMOD_RESULT F_API FMOD_System_RegisterDSP (FMOD_SYSTEM *system, FMOD_DSP_DESCRIPTION *description, unsigned int *handle); - -/* - Init/Close -*/ - -FMOD_RESULT F_API FMOD_System_Init (FMOD_SYSTEM *system, int maxchannels, FMOD_INITFLAGS flags, void *extradriverdata); -FMOD_RESULT F_API FMOD_System_Close (FMOD_SYSTEM *system); - -/* - General post-init system functions -*/ - -FMOD_RESULT F_API FMOD_System_Update (FMOD_SYSTEM *system); - -FMOD_RESULT F_API FMOD_System_Set3DSettings (FMOD_SYSTEM *system, float dopplerscale, float distancefactor, float rolloffscale); -FMOD_RESULT F_API FMOD_System_Get3DSettings (FMOD_SYSTEM *system, float *dopplerscale, float *distancefactor, float *rolloffscale); -FMOD_RESULT F_API FMOD_System_Set3DNumListeners (FMOD_SYSTEM *system, int numlisteners); -FMOD_RESULT F_API FMOD_System_Get3DNumListeners (FMOD_SYSTEM *system, int *numlisteners); -FMOD_RESULT F_API FMOD_System_Set3DListenerAttributes(FMOD_SYSTEM *system, int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); -FMOD_RESULT F_API FMOD_System_Get3DListenerAttributes(FMOD_SYSTEM *system, int listener, FMOD_VECTOR *pos, FMOD_VECTOR *vel, FMOD_VECTOR *forward, FMOD_VECTOR *up); -FMOD_RESULT F_API FMOD_System_Set3DRolloffCallback (FMOD_SYSTEM *system, FMOD_3D_ROLLOFFCALLBACK callback); -FMOD_RESULT F_API FMOD_System_Set3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float x, float y, FMOD_BOOL active); -FMOD_RESULT F_API FMOD_System_Get3DSpeakerPosition (FMOD_SYSTEM *system, FMOD_SPEAKER speaker, float *x, float *y, FMOD_BOOL *active); - -FMOD_RESULT F_API FMOD_System_SetStreamBufferSize (FMOD_SYSTEM *system, unsigned int filebuffersize, FMOD_TIMEUNIT filebuffersizetype); -FMOD_RESULT F_API FMOD_System_GetStreamBufferSize (FMOD_SYSTEM *system, unsigned int *filebuffersize, FMOD_TIMEUNIT *filebuffersizetype); - -/* - System information functions. -*/ - -FMOD_RESULT F_API FMOD_System_GetVersion (FMOD_SYSTEM *system, unsigned int *version); -FMOD_RESULT F_API FMOD_System_GetOutputHandle (FMOD_SYSTEM *system, void **handle); -FMOD_RESULT F_API FMOD_System_GetChannelsPlaying (FMOD_SYSTEM *system, int *channels); -FMOD_RESULT F_API FMOD_System_GetHardwareChannels (FMOD_SYSTEM *system, int *numhardwarechannels); -FMOD_RESULT F_API FMOD_System_GetCPUUsage (FMOD_SYSTEM *system, float *dsp, float *stream, float *geometry, float *update, float *total); -FMOD_RESULT F_API FMOD_System_GetSoundRAM (FMOD_SYSTEM *system, int *currentalloced, int *maxalloced, int *total); -FMOD_RESULT F_API FMOD_System_GetNumCDROMDrives (FMOD_SYSTEM *system, int *numdrives); -FMOD_RESULT F_API FMOD_System_GetCDROMDriveName (FMOD_SYSTEM *system, int drive, char *drivename, int drivenamelen, char *scsiname, int scsinamelen, char *devicename, int devicenamelen); -FMOD_RESULT F_API FMOD_System_GetSpectrum (FMOD_SYSTEM *system, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); -FMOD_RESULT F_API FMOD_System_GetWaveData (FMOD_SYSTEM *system, float *wavearray, int numvalues, int channeloffset); - -/* - Sound/DSP/Channel/FX creation and retrieval. -*/ - -FMOD_RESULT F_API FMOD_System_CreateSound (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); -FMOD_RESULT F_API FMOD_System_CreateStream (FMOD_SYSTEM *system, const char *name_or_data, FMOD_MODE mode, FMOD_CREATESOUNDEXINFO *exinfo, FMOD_SOUND **sound); -FMOD_RESULT F_API FMOD_System_CreateDSP (FMOD_SYSTEM *system, FMOD_DSP_DESCRIPTION *description, FMOD_DSP **dsp); -FMOD_RESULT F_API FMOD_System_CreateDSPByType (FMOD_SYSTEM *system, FMOD_DSP_TYPE type, FMOD_DSP **dsp); -FMOD_RESULT F_API FMOD_System_CreateChannelGroup (FMOD_SYSTEM *system, const char *name, FMOD_CHANNELGROUP **channelgroup); -FMOD_RESULT F_API FMOD_System_CreateSoundGroup (FMOD_SYSTEM *system, const char *name, FMOD_SOUNDGROUP **soundgroup); -FMOD_RESULT F_API FMOD_System_CreateReverb (FMOD_SYSTEM *system, FMOD_REVERB **reverb); - -FMOD_RESULT F_API FMOD_System_PlaySound (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_SOUND *sound, FMOD_BOOL paused, FMOD_CHANNEL **channel); -FMOD_RESULT F_API FMOD_System_PlayDSP (FMOD_SYSTEM *system, FMOD_CHANNELINDEX channelid, FMOD_DSP *dsp, FMOD_BOOL paused, FMOD_CHANNEL **channel); -FMOD_RESULT F_API FMOD_System_GetChannel (FMOD_SYSTEM *system, int channelid, FMOD_CHANNEL **channel); -FMOD_RESULT F_API FMOD_System_GetMasterChannelGroup (FMOD_SYSTEM *system, FMOD_CHANNELGROUP **channelgroup); -FMOD_RESULT F_API FMOD_System_GetMasterSoundGroup (FMOD_SYSTEM *system, FMOD_SOUNDGROUP **soundgroup); - -/* - Reverb API -*/ - -FMOD_RESULT F_API FMOD_System_SetReverbProperties (FMOD_SYSTEM *system, const FMOD_REVERB_PROPERTIES *prop); -FMOD_RESULT F_API FMOD_System_GetReverbProperties (FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); -FMOD_RESULT F_API FMOD_System_SetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); -FMOD_RESULT F_API FMOD_System_GetReverbAmbientProperties(FMOD_SYSTEM *system, FMOD_REVERB_PROPERTIES *prop); - -/* - System level DSP access. -*/ - -FMOD_RESULT F_API FMOD_System_GetDSPHead (FMOD_SYSTEM *system, FMOD_DSP **dsp); -FMOD_RESULT F_API FMOD_System_AddDSP (FMOD_SYSTEM *system, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); -FMOD_RESULT F_API FMOD_System_LockDSP (FMOD_SYSTEM *system); -FMOD_RESULT F_API FMOD_System_UnlockDSP (FMOD_SYSTEM *system); -FMOD_RESULT F_API FMOD_System_GetDSPClock (FMOD_SYSTEM *system, unsigned int *hi, unsigned int *lo); - -/* - Recording API. -*/ - -FMOD_RESULT F_API FMOD_System_GetRecordNumDrivers (FMOD_SYSTEM *system, int *numdrivers); -FMOD_RESULT F_API FMOD_System_GetRecordDriverInfo (FMOD_SYSTEM *system, int id, char *name, int namelen, FMOD_GUID *guid); -FMOD_RESULT F_API FMOD_System_GetRecordDriverInfoW (FMOD_SYSTEM *system, int id, short *name, int namelen, FMOD_GUID *guid); -FMOD_RESULT F_API FMOD_System_GetRecordDriverCaps (FMOD_SYSTEM *system, int id, FMOD_CAPS *caps, int *minfrequency, int *maxfrequency); -FMOD_RESULT F_API FMOD_System_GetRecordPosition (FMOD_SYSTEM *system, int id, unsigned int *position); - -FMOD_RESULT F_API FMOD_System_RecordStart (FMOD_SYSTEM *system, int id, FMOD_SOUND *sound, FMOD_BOOL loop); -FMOD_RESULT F_API FMOD_System_RecordStop (FMOD_SYSTEM *system, int id); -FMOD_RESULT F_API FMOD_System_IsRecording (FMOD_SYSTEM *system, int id, FMOD_BOOL *recording); - -/* - Geometry API. -*/ - -FMOD_RESULT F_API FMOD_System_CreateGeometry (FMOD_SYSTEM *system, int maxpolygons, int maxvertices, FMOD_GEOMETRY **geometry); -FMOD_RESULT F_API FMOD_System_SetGeometrySettings (FMOD_SYSTEM *system, float maxworldsize); -FMOD_RESULT F_API FMOD_System_GetGeometrySettings (FMOD_SYSTEM *system, float *maxworldsize); -FMOD_RESULT F_API FMOD_System_LoadGeometry (FMOD_SYSTEM *system, const void *data, int datasize, FMOD_GEOMETRY **geometry); -FMOD_RESULT F_API FMOD_System_GetGeometryOcclusion (FMOD_SYSTEM *system, const FMOD_VECTOR *listener, const FMOD_VECTOR *source, float *direct, float *reverb); - -/* - Network functions. -*/ - -FMOD_RESULT F_API FMOD_System_SetNetworkProxy (FMOD_SYSTEM *system, const char *proxy); -FMOD_RESULT F_API FMOD_System_GetNetworkProxy (FMOD_SYSTEM *system, char *proxy, int proxylen); -FMOD_RESULT F_API FMOD_System_SetNetworkTimeout (FMOD_SYSTEM *system, int timeout); -FMOD_RESULT F_API FMOD_System_GetNetworkTimeout (FMOD_SYSTEM *system, int *timeout); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_System_SetUserData (FMOD_SYSTEM *system, void *userdata); -FMOD_RESULT F_API FMOD_System_GetUserData (FMOD_SYSTEM *system, void **userdata); - -FMOD_RESULT F_API FMOD_System_GetMemoryInfo (FMOD_SYSTEM *system, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'Sound' API -*/ - -FMOD_RESULT F_API FMOD_Sound_Release (FMOD_SOUND *sound); -FMOD_RESULT F_API FMOD_Sound_GetSystemObject (FMOD_SOUND *sound, FMOD_SYSTEM **system); - -/* - Standard sound manipulation functions. -*/ - -FMOD_RESULT F_API FMOD_Sound_Lock (FMOD_SOUND *sound, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); -FMOD_RESULT F_API FMOD_Sound_Unlock (FMOD_SOUND *sound, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); -FMOD_RESULT F_API FMOD_Sound_SetDefaults (FMOD_SOUND *sound, float frequency, float volume, float pan, int priority); -FMOD_RESULT F_API FMOD_Sound_GetDefaults (FMOD_SOUND *sound, float *frequency, float *volume, float *pan, int *priority); -FMOD_RESULT F_API FMOD_Sound_SetVariations (FMOD_SOUND *sound, float frequencyvar, float volumevar, float panvar); -FMOD_RESULT F_API FMOD_Sound_GetVariations (FMOD_SOUND *sound, float *frequencyvar, float *volumevar, float *panvar); -FMOD_RESULT F_API FMOD_Sound_Set3DMinMaxDistance (FMOD_SOUND *sound, float min, float max); -FMOD_RESULT F_API FMOD_Sound_Get3DMinMaxDistance (FMOD_SOUND *sound, float *min, float *max); -FMOD_RESULT F_API FMOD_Sound_Set3DConeSettings (FMOD_SOUND *sound, float insideconeangle, float outsideconeangle, float outsidevolume); -FMOD_RESULT F_API FMOD_Sound_Get3DConeSettings (FMOD_SOUND *sound, float *insideconeangle, float *outsideconeangle, float *outsidevolume); -FMOD_RESULT F_API FMOD_Sound_Set3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR *points, int numpoints); -FMOD_RESULT F_API FMOD_Sound_Get3DCustomRolloff (FMOD_SOUND *sound, FMOD_VECTOR **points, int *numpoints); -FMOD_RESULT F_API FMOD_Sound_SetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND *subsound); -FMOD_RESULT F_API FMOD_Sound_GetSubSound (FMOD_SOUND *sound, int index, FMOD_SOUND **subsound); -FMOD_RESULT F_API FMOD_Sound_SetSubSoundSentence (FMOD_SOUND *sound, int *subsoundlist, int numsubsounds); -FMOD_RESULT F_API FMOD_Sound_GetName (FMOD_SOUND *sound, char *name, int namelen); -FMOD_RESULT F_API FMOD_Sound_GetLength (FMOD_SOUND *sound, unsigned int *length, FMOD_TIMEUNIT lengthtype); -FMOD_RESULT F_API FMOD_Sound_GetFormat (FMOD_SOUND *sound, FMOD_SOUND_TYPE *type, FMOD_SOUND_FORMAT *format, int *channels, int *bits); -FMOD_RESULT F_API FMOD_Sound_GetNumSubSounds (FMOD_SOUND *sound, int *numsubsounds); -FMOD_RESULT F_API FMOD_Sound_GetNumTags (FMOD_SOUND *sound, int *numtags, int *numtagsupdated); -FMOD_RESULT F_API FMOD_Sound_GetTag (FMOD_SOUND *sound, const char *name, int index, FMOD_TAG *tag); -FMOD_RESULT F_API FMOD_Sound_GetOpenState (FMOD_SOUND *sound, FMOD_OPENSTATE *openstate, unsigned int *percentbuffered, FMOD_BOOL *starving, FMOD_BOOL *diskbusy); -FMOD_RESULT F_API FMOD_Sound_ReadData (FMOD_SOUND *sound, void *buffer, unsigned int lenbytes, unsigned int *read); -FMOD_RESULT F_API FMOD_Sound_SeekData (FMOD_SOUND *sound, unsigned int pcm); - -FMOD_RESULT F_API FMOD_Sound_SetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP *soundgroup); -FMOD_RESULT F_API FMOD_Sound_GetSoundGroup (FMOD_SOUND *sound, FMOD_SOUNDGROUP **soundgroup); - -/* - Synchronization point API. These points can come from markers embedded in wav files, and can also generate channel callbacks. -*/ - -FMOD_RESULT F_API FMOD_Sound_GetNumSyncPoints (FMOD_SOUND *sound, int *numsyncpoints); -FMOD_RESULT F_API FMOD_Sound_GetSyncPoint (FMOD_SOUND *sound, int index, FMOD_SYNCPOINT **point); -FMOD_RESULT F_API FMOD_Sound_GetSyncPointInfo (FMOD_SOUND *sound, FMOD_SYNCPOINT *point, char *name, int namelen, unsigned int *offset, FMOD_TIMEUNIT offsettype); -FMOD_RESULT F_API FMOD_Sound_AddSyncPoint (FMOD_SOUND *sound, unsigned int offset, FMOD_TIMEUNIT offsettype, const char *name, FMOD_SYNCPOINT **point); -FMOD_RESULT F_API FMOD_Sound_DeleteSyncPoint (FMOD_SOUND *sound, FMOD_SYNCPOINT *point); - -/* - Functions also in Channel class but here they are the 'default' to save having to change it in Channel all the time. -*/ - -FMOD_RESULT F_API FMOD_Sound_SetMode (FMOD_SOUND *sound, FMOD_MODE mode); -FMOD_RESULT F_API FMOD_Sound_GetMode (FMOD_SOUND *sound, FMOD_MODE *mode); -FMOD_RESULT F_API FMOD_Sound_SetLoopCount (FMOD_SOUND *sound, int loopcount); -FMOD_RESULT F_API FMOD_Sound_GetLoopCount (FMOD_SOUND *sound, int *loopcount); -FMOD_RESULT F_API FMOD_Sound_SetLoopPoints (FMOD_SOUND *sound, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); -FMOD_RESULT F_API FMOD_Sound_GetLoopPoints (FMOD_SOUND *sound, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); - -/* - For MOD/S3M/XM/IT/MID sequenced formats only. -*/ - -FMOD_RESULT F_API FMOD_Sound_GetMusicNumChannels (FMOD_SOUND *sound, int *numchannels); -FMOD_RESULT F_API FMOD_Sound_SetMusicChannelVolume (FMOD_SOUND *sound, int channel, float volume); -FMOD_RESULT F_API FMOD_Sound_GetMusicChannelVolume (FMOD_SOUND *sound, int channel, float *volume); -FMOD_RESULT F_API FMOD_Sound_SetMusicSpeed (FMOD_SOUND *sound, float speed); -FMOD_RESULT F_API FMOD_Sound_GetMusicSpeed (FMOD_SOUND *sound, float *speed); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_Sound_SetUserData (FMOD_SOUND *sound, void *userdata); -FMOD_RESULT F_API FMOD_Sound_GetUserData (FMOD_SOUND *sound, void **userdata); - -FMOD_RESULT F_API FMOD_Sound_GetMemoryInfo (FMOD_SOUND *sound, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'Channel' API -*/ - -FMOD_RESULT F_API FMOD_Channel_GetSystemObject (FMOD_CHANNEL *channel, FMOD_SYSTEM **system); - -FMOD_RESULT F_API FMOD_Channel_Stop (FMOD_CHANNEL *channel); -FMOD_RESULT F_API FMOD_Channel_SetPaused (FMOD_CHANNEL *channel, FMOD_BOOL paused); -FMOD_RESULT F_API FMOD_Channel_GetPaused (FMOD_CHANNEL *channel, FMOD_BOOL *paused); -FMOD_RESULT F_API FMOD_Channel_SetVolume (FMOD_CHANNEL *channel, float volume); -FMOD_RESULT F_API FMOD_Channel_GetVolume (FMOD_CHANNEL *channel, float *volume); -FMOD_RESULT F_API FMOD_Channel_SetFrequency (FMOD_CHANNEL *channel, float frequency); -FMOD_RESULT F_API FMOD_Channel_GetFrequency (FMOD_CHANNEL *channel, float *frequency); -FMOD_RESULT F_API FMOD_Channel_SetPan (FMOD_CHANNEL *channel, float pan); -FMOD_RESULT F_API FMOD_Channel_GetPan (FMOD_CHANNEL *channel, float *pan); -FMOD_RESULT F_API FMOD_Channel_SetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo); -FMOD_RESULT F_API FMOD_Channel_GetDelay (FMOD_CHANNEL *channel, FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo); -FMOD_RESULT F_API FMOD_Channel_SetSpeakerMix (FMOD_CHANNEL *channel, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); -FMOD_RESULT F_API FMOD_Channel_GetSpeakerMix (FMOD_CHANNEL *channel, float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright); -FMOD_RESULT F_API FMOD_Channel_SetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); -FMOD_RESULT F_API FMOD_Channel_GetSpeakerLevels (FMOD_CHANNEL *channel, FMOD_SPEAKER speaker, float *levels, int numlevels); -FMOD_RESULT F_API FMOD_Channel_SetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); -FMOD_RESULT F_API FMOD_Channel_GetInputChannelMix (FMOD_CHANNEL *channel, float *levels, int numlevels); -FMOD_RESULT F_API FMOD_Channel_SetMute (FMOD_CHANNEL *channel, FMOD_BOOL mute); -FMOD_RESULT F_API FMOD_Channel_GetMute (FMOD_CHANNEL *channel, FMOD_BOOL *mute); -FMOD_RESULT F_API FMOD_Channel_SetPriority (FMOD_CHANNEL *channel, int priority); -FMOD_RESULT F_API FMOD_Channel_GetPriority (FMOD_CHANNEL *channel, int *priority); -FMOD_RESULT F_API FMOD_Channel_SetPosition (FMOD_CHANNEL *channel, unsigned int position, FMOD_TIMEUNIT postype); -FMOD_RESULT F_API FMOD_Channel_GetPosition (FMOD_CHANNEL *channel, unsigned int *position, FMOD_TIMEUNIT postype); -FMOD_RESULT F_API FMOD_Channel_SetReverbProperties (FMOD_CHANNEL *channel, const FMOD_REVERB_CHANNELPROPERTIES *prop); -FMOD_RESULT F_API FMOD_Channel_GetReverbProperties (FMOD_CHANNEL *channel, FMOD_REVERB_CHANNELPROPERTIES *prop); -FMOD_RESULT F_API FMOD_Channel_SetLowPassGain (FMOD_CHANNEL *channel, float gain); -FMOD_RESULT F_API FMOD_Channel_GetLowPassGain (FMOD_CHANNEL *channel, float *gain); - -FMOD_RESULT F_API FMOD_Channel_SetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP *channelgroup); -FMOD_RESULT F_API FMOD_Channel_GetChannelGroup (FMOD_CHANNEL *channel, FMOD_CHANNELGROUP **channelgroup); -FMOD_RESULT F_API FMOD_Channel_SetCallback (FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACK callback); - -/* - 3D functionality. -*/ - -FMOD_RESULT F_API FMOD_Channel_Set3DAttributes (FMOD_CHANNEL *channel, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); -FMOD_RESULT F_API FMOD_Channel_Get3DAttributes (FMOD_CHANNEL *channel, FMOD_VECTOR *pos, FMOD_VECTOR *vel); -FMOD_RESULT F_API FMOD_Channel_Set3DMinMaxDistance (FMOD_CHANNEL *channel, float mindistance, float maxdistance); -FMOD_RESULT F_API FMOD_Channel_Get3DMinMaxDistance (FMOD_CHANNEL *channel, float *mindistance, float *maxdistance); -FMOD_RESULT F_API FMOD_Channel_Set3DConeSettings (FMOD_CHANNEL *channel, float insideconeangle, float outsideconeangle, float outsidevolume); -FMOD_RESULT F_API FMOD_Channel_Get3DConeSettings (FMOD_CHANNEL *channel, float *insideconeangle, float *outsideconeangle, float *outsidevolume); -FMOD_RESULT F_API FMOD_Channel_Set3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); -FMOD_RESULT F_API FMOD_Channel_Get3DConeOrientation (FMOD_CHANNEL *channel, FMOD_VECTOR *orientation); -FMOD_RESULT F_API FMOD_Channel_Set3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR *points, int numpoints); -FMOD_RESULT F_API FMOD_Channel_Get3DCustomRolloff (FMOD_CHANNEL *channel, FMOD_VECTOR **points, int *numpoints); -FMOD_RESULT F_API FMOD_Channel_Set3DOcclusion (FMOD_CHANNEL *channel, float directocclusion, float reverbocclusion); -FMOD_RESULT F_API FMOD_Channel_Get3DOcclusion (FMOD_CHANNEL *channel, float *directocclusion, float *reverbocclusion); -FMOD_RESULT F_API FMOD_Channel_Set3DSpread (FMOD_CHANNEL *channel, float angle); -FMOD_RESULT F_API FMOD_Channel_Get3DSpread (FMOD_CHANNEL *channel, float *angle); -FMOD_RESULT F_API FMOD_Channel_Set3DPanLevel (FMOD_CHANNEL *channel, float level); -FMOD_RESULT F_API FMOD_Channel_Get3DPanLevel (FMOD_CHANNEL *channel, float *level); -FMOD_RESULT F_API FMOD_Channel_Set3DDopplerLevel (FMOD_CHANNEL *channel, float level); -FMOD_RESULT F_API FMOD_Channel_Get3DDopplerLevel (FMOD_CHANNEL *channel, float *level); -FMOD_RESULT F_API FMOD_Channel_Set3DDistanceFilter (FMOD_CHANNEL *channel, FMOD_BOOL custom, float customLevel, float centerFreq); -FMOD_RESULT F_API FMOD_Channel_Get3DDistanceFilter (FMOD_CHANNEL *channel, FMOD_BOOL *custom, float *customLevel, float *centerFreq); - -/* - DSP functionality only for channels playing sounds created with FMOD_SOFTWARE. -*/ - -FMOD_RESULT F_API FMOD_Channel_GetDSPHead (FMOD_CHANNEL *channel, FMOD_DSP **dsp); -FMOD_RESULT F_API FMOD_Channel_AddDSP (FMOD_CHANNEL *channel, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); - -/* - Information only functions. -*/ - -FMOD_RESULT F_API FMOD_Channel_IsPlaying (FMOD_CHANNEL *channel, FMOD_BOOL *isplaying); -FMOD_RESULT F_API FMOD_Channel_IsVirtual (FMOD_CHANNEL *channel, FMOD_BOOL *isvirtual); -FMOD_RESULT F_API FMOD_Channel_GetAudibility (FMOD_CHANNEL *channel, float *audibility); -FMOD_RESULT F_API FMOD_Channel_GetCurrentSound (FMOD_CHANNEL *channel, FMOD_SOUND **sound); -FMOD_RESULT F_API FMOD_Channel_GetSpectrum (FMOD_CHANNEL *channel, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); -FMOD_RESULT F_API FMOD_Channel_GetWaveData (FMOD_CHANNEL *channel, float *wavearray, int numvalues, int channeloffset); -FMOD_RESULT F_API FMOD_Channel_GetIndex (FMOD_CHANNEL *channel, int *index); - -/* - Functions also found in Sound class but here they can be set per channel. -*/ - -FMOD_RESULT F_API FMOD_Channel_SetMode (FMOD_CHANNEL *channel, FMOD_MODE mode); -FMOD_RESULT F_API FMOD_Channel_GetMode (FMOD_CHANNEL *channel, FMOD_MODE *mode); -FMOD_RESULT F_API FMOD_Channel_SetLoopCount (FMOD_CHANNEL *channel, int loopcount); -FMOD_RESULT F_API FMOD_Channel_GetLoopCount (FMOD_CHANNEL *channel, int *loopcount); -FMOD_RESULT F_API FMOD_Channel_SetLoopPoints (FMOD_CHANNEL *channel, unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype); -FMOD_RESULT F_API FMOD_Channel_GetLoopPoints (FMOD_CHANNEL *channel, unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_Channel_SetUserData (FMOD_CHANNEL *channel, void *userdata); -FMOD_RESULT F_API FMOD_Channel_GetUserData (FMOD_CHANNEL *channel, void **userdata); - -FMOD_RESULT F_API FMOD_Channel_GetMemoryInfo (FMOD_CHANNEL *channel, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'ChannelGroup' API -*/ - -FMOD_RESULT F_API FMOD_ChannelGroup_Release (FMOD_CHANNELGROUP *channelgroup); -FMOD_RESULT F_API FMOD_ChannelGroup_GetSystemObject (FMOD_CHANNELGROUP *channelgroup, FMOD_SYSTEM **system); - -/* - Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them) -*/ - -FMOD_RESULT F_API FMOD_ChannelGroup_SetVolume (FMOD_CHANNELGROUP *channelgroup, float volume); -FMOD_RESULT F_API FMOD_ChannelGroup_GetVolume (FMOD_CHANNELGROUP *channelgroup, float *volume); -FMOD_RESULT F_API FMOD_ChannelGroup_SetPitch (FMOD_CHANNELGROUP *channelgroup, float pitch); -FMOD_RESULT F_API FMOD_ChannelGroup_GetPitch (FMOD_CHANNELGROUP *channelgroup, float *pitch); -FMOD_RESULT F_API FMOD_ChannelGroup_Set3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float directocclusion, float reverbocclusion); -FMOD_RESULT F_API FMOD_ChannelGroup_Get3DOcclusion (FMOD_CHANNELGROUP *channelgroup, float *directocclusion, float *reverbocclusion); -FMOD_RESULT F_API FMOD_ChannelGroup_SetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL paused); -FMOD_RESULT F_API FMOD_ChannelGroup_GetPaused (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *paused); -FMOD_RESULT F_API FMOD_ChannelGroup_SetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL mute); -FMOD_RESULT F_API FMOD_ChannelGroup_GetMute (FMOD_CHANNELGROUP *channelgroup, FMOD_BOOL *mute); - -/* - Channelgroup override values. (recursively overwrites whatever settings the channels had) -*/ - -FMOD_RESULT F_API FMOD_ChannelGroup_Stop (FMOD_CHANNELGROUP *channelgroup); -FMOD_RESULT F_API FMOD_ChannelGroup_OverrideVolume (FMOD_CHANNELGROUP *channelgroup, float volume); -FMOD_RESULT F_API FMOD_ChannelGroup_OverrideFrequency(FMOD_CHANNELGROUP *channelgroup, float frequency); -FMOD_RESULT F_API FMOD_ChannelGroup_OverridePan (FMOD_CHANNELGROUP *channelgroup, float pan); -FMOD_RESULT F_API FMOD_ChannelGroup_OverrideReverbProperties(FMOD_CHANNELGROUP *channelgroup, const FMOD_REVERB_CHANNELPROPERTIES *prop); -FMOD_RESULT F_API FMOD_ChannelGroup_Override3DAttributes(FMOD_CHANNELGROUP *channelgroup, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel); -FMOD_RESULT F_API FMOD_ChannelGroup_OverrideSpeakerMix(FMOD_CHANNELGROUP *channelgroup, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); - -/* - Nested channel groups. -*/ - -FMOD_RESULT F_API FMOD_ChannelGroup_AddGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP *group); -FMOD_RESULT F_API FMOD_ChannelGroup_GetNumGroups (FMOD_CHANNELGROUP *channelgroup, int *numgroups); -FMOD_RESULT F_API FMOD_ChannelGroup_GetGroup (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNELGROUP **group); -FMOD_RESULT F_API FMOD_ChannelGroup_GetParentGroup (FMOD_CHANNELGROUP *channelgroup, FMOD_CHANNELGROUP **group); - -/* - DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. -*/ - -FMOD_RESULT F_API FMOD_ChannelGroup_GetDSPHead (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP **dsp); -FMOD_RESULT F_API FMOD_ChannelGroup_AddDSP (FMOD_CHANNELGROUP *channelgroup, FMOD_DSP *dsp, FMOD_DSPCONNECTION **connection); - -/* - Information only functions. -*/ - -FMOD_RESULT F_API FMOD_ChannelGroup_GetName (FMOD_CHANNELGROUP *channelgroup, char *name, int namelen); -FMOD_RESULT F_API FMOD_ChannelGroup_GetNumChannels (FMOD_CHANNELGROUP *channelgroup, int *numchannels); -FMOD_RESULT F_API FMOD_ChannelGroup_GetChannel (FMOD_CHANNELGROUP *channelgroup, int index, FMOD_CHANNEL **channel); -FMOD_RESULT F_API FMOD_ChannelGroup_GetSpectrum (FMOD_CHANNELGROUP *channelgroup, float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype); -FMOD_RESULT F_API FMOD_ChannelGroup_GetWaveData (FMOD_CHANNELGROUP *channelgroup, float *wavearray, int numvalues, int channeloffset); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_ChannelGroup_SetUserData (FMOD_CHANNELGROUP *channelgroup, void *userdata); -FMOD_RESULT F_API FMOD_ChannelGroup_GetUserData (FMOD_CHANNELGROUP *channelgroup, void **userdata); - -FMOD_RESULT F_API FMOD_ChannelGroup_GetMemoryInfo (FMOD_CHANNELGROUP *channelgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'SoundGroup' API -*/ - -FMOD_RESULT F_API FMOD_SoundGroup_Release (FMOD_SOUNDGROUP *soundgroup); -FMOD_RESULT F_API FMOD_SoundGroup_GetSystemObject (FMOD_SOUNDGROUP *soundgroup, FMOD_SYSTEM **system); - -/* - SoundGroup control functions. -*/ - -FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int maxaudible); -FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudible (FMOD_SOUNDGROUP *soundgroup, int *maxaudible); -FMOD_RESULT F_API FMOD_SoundGroup_SetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR behavior); -FMOD_RESULT F_API FMOD_SoundGroup_GetMaxAudibleBehavior(FMOD_SOUNDGROUP *soundgroup, FMOD_SOUNDGROUP_BEHAVIOR *behavior); -FMOD_RESULT F_API FMOD_SoundGroup_SetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float speed); -FMOD_RESULT F_API FMOD_SoundGroup_GetMuteFadeSpeed (FMOD_SOUNDGROUP *soundgroup, float *speed); -FMOD_RESULT F_API FMOD_SoundGroup_SetVolume (FMOD_SOUNDGROUP *soundgroup, float volume); -FMOD_RESULT F_API FMOD_SoundGroup_GetVolume (FMOD_SOUNDGROUP *soundgroup, float *volume); -FMOD_RESULT F_API FMOD_SoundGroup_Stop (FMOD_SOUNDGROUP *soundgroup); - -/* - Information only functions. -*/ - -FMOD_RESULT F_API FMOD_SoundGroup_GetName (FMOD_SOUNDGROUP *soundgroup, char *name, int namelen); -FMOD_RESULT F_API FMOD_SoundGroup_GetNumSounds (FMOD_SOUNDGROUP *soundgroup, int *numsounds); -FMOD_RESULT F_API FMOD_SoundGroup_GetSound (FMOD_SOUNDGROUP *soundgroup, int index, FMOD_SOUND **sound); -FMOD_RESULT F_API FMOD_SoundGroup_GetNumPlaying (FMOD_SOUNDGROUP *soundgroup, int *numplaying); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_SoundGroup_SetUserData (FMOD_SOUNDGROUP *soundgroup, void *userdata); -FMOD_RESULT F_API FMOD_SoundGroup_GetUserData (FMOD_SOUNDGROUP *soundgroup, void **userdata); - -FMOD_RESULT F_API FMOD_SoundGroup_GetMemoryInfo (FMOD_SOUNDGROUP *soundgroup, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'DSP' API -*/ - -FMOD_RESULT F_API FMOD_DSP_Release (FMOD_DSP *dsp); -FMOD_RESULT F_API FMOD_DSP_GetSystemObject (FMOD_DSP *dsp, FMOD_SYSTEM **system); - -/* - Connection / disconnection / input and output enumeration. -*/ - -FMOD_RESULT F_API FMOD_DSP_AddInput (FMOD_DSP *dsp, FMOD_DSP *target, FMOD_DSPCONNECTION **connection); -FMOD_RESULT F_API FMOD_DSP_DisconnectFrom (FMOD_DSP *dsp, FMOD_DSP *target); -FMOD_RESULT F_API FMOD_DSP_DisconnectAll (FMOD_DSP *dsp, FMOD_BOOL inputs, FMOD_BOOL outputs); -FMOD_RESULT F_API FMOD_DSP_Remove (FMOD_DSP *dsp); -FMOD_RESULT F_API FMOD_DSP_GetNumInputs (FMOD_DSP *dsp, int *numinputs); -FMOD_RESULT F_API FMOD_DSP_GetNumOutputs (FMOD_DSP *dsp, int *numoutputs); -FMOD_RESULT F_API FMOD_DSP_GetInput (FMOD_DSP *dsp, int index, FMOD_DSP **input, FMOD_DSPCONNECTION **inputconnection); -FMOD_RESULT F_API FMOD_DSP_GetOutput (FMOD_DSP *dsp, int index, FMOD_DSP **output, FMOD_DSPCONNECTION **outputconnection); - -/* - DSP unit control. -*/ - -FMOD_RESULT F_API FMOD_DSP_SetActive (FMOD_DSP *dsp, FMOD_BOOL active); -FMOD_RESULT F_API FMOD_DSP_GetActive (FMOD_DSP *dsp, FMOD_BOOL *active); -FMOD_RESULT F_API FMOD_DSP_SetBypass (FMOD_DSP *dsp, FMOD_BOOL bypass); -FMOD_RESULT F_API FMOD_DSP_GetBypass (FMOD_DSP *dsp, FMOD_BOOL *bypass); -FMOD_RESULT F_API FMOD_DSP_SetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL active); -FMOD_RESULT F_API FMOD_DSP_GetSpeakerActive (FMOD_DSP *dsp, FMOD_SPEAKER speaker, FMOD_BOOL *active); -FMOD_RESULT F_API FMOD_DSP_Reset (FMOD_DSP *dsp); - -/* - DSP parameter control. -*/ - -FMOD_RESULT F_API FMOD_DSP_SetParameter (FMOD_DSP *dsp, int index, float value); -FMOD_RESULT F_API FMOD_DSP_GetParameter (FMOD_DSP *dsp, int index, float *value, char *valuestr, int valuestrlen); -FMOD_RESULT F_API FMOD_DSP_GetNumParameters (FMOD_DSP *dsp, int *numparams); -FMOD_RESULT F_API FMOD_DSP_GetParameterInfo (FMOD_DSP *dsp, int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max); -FMOD_RESULT F_API FMOD_DSP_ShowConfigDialog (FMOD_DSP *dsp, void *hwnd, FMOD_BOOL show); - -/* - DSP attributes. -*/ - -FMOD_RESULT F_API FMOD_DSP_GetInfo (FMOD_DSP *dsp, char *name, unsigned int *version, int *channels, int *configwidth, int *configheight); -FMOD_RESULT F_API FMOD_DSP_GetType (FMOD_DSP *dsp, FMOD_DSP_TYPE *type); -FMOD_RESULT F_API FMOD_DSP_SetDefaults (FMOD_DSP *dsp, float frequency, float volume, float pan, int priority); -FMOD_RESULT F_API FMOD_DSP_GetDefaults (FMOD_DSP *dsp, float *frequency, float *volume, float *pan, int *priority); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_DSP_SetUserData (FMOD_DSP *dsp, void *userdata); -FMOD_RESULT F_API FMOD_DSP_GetUserData (FMOD_DSP *dsp, void **userdata); - -FMOD_RESULT F_API FMOD_DSP_GetMemoryInfo (FMOD_DSP *dsp, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'DSPConnection' API -*/ - -FMOD_RESULT F_API FMOD_DSPConnection_GetInput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **input); -FMOD_RESULT F_API FMOD_DSPConnection_GetOutput (FMOD_DSPCONNECTION *dspconnection, FMOD_DSP **output); -FMOD_RESULT F_API FMOD_DSPConnection_SetMix (FMOD_DSPCONNECTION *dspconnection, float volume); -FMOD_RESULT F_API FMOD_DSPConnection_GetMix (FMOD_DSPCONNECTION *dspconnection, float *volume); -FMOD_RESULT F_API FMOD_DSPConnection_SetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); -FMOD_RESULT F_API FMOD_DSPConnection_GetLevels (FMOD_DSPCONNECTION *dspconnection, FMOD_SPEAKER speaker, float *levels, int numlevels); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_DSPConnection_SetUserData (FMOD_DSPCONNECTION *dspconnection, void *userdata); -FMOD_RESULT F_API FMOD_DSPConnection_GetUserData (FMOD_DSPCONNECTION *dspconnection, void **userdata); - -FMOD_RESULT F_API FMOD_DSPConnection_GetMemoryInfo (FMOD_DSPCONNECTION *dspconnection, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'Geometry' API -*/ - -FMOD_RESULT F_API FMOD_Geometry_Release (FMOD_GEOMETRY *geometry); - -/* - Polygon manipulation. -*/ - -FMOD_RESULT F_API FMOD_Geometry_AddPolygon (FMOD_GEOMETRY *geometry, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided, int numvertices, const FMOD_VECTOR *vertices, int *polygonindex); -FMOD_RESULT F_API FMOD_Geometry_GetNumPolygons (FMOD_GEOMETRY *geometry, int *numpolygons); -FMOD_RESULT F_API FMOD_Geometry_GetMaxPolygons (FMOD_GEOMETRY *geometry, int *maxpolygons, int *maxvertices); -FMOD_RESULT F_API FMOD_Geometry_GetPolygonNumVertices(FMOD_GEOMETRY *geometry, int index, int *numvertices); -FMOD_RESULT F_API FMOD_Geometry_SetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, const FMOD_VECTOR *vertex); -FMOD_RESULT F_API FMOD_Geometry_GetPolygonVertex (FMOD_GEOMETRY *geometry, int index, int vertexindex, FMOD_VECTOR *vertex); -FMOD_RESULT F_API FMOD_Geometry_SetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float directocclusion, float reverbocclusion, FMOD_BOOL doublesided); -FMOD_RESULT F_API FMOD_Geometry_GetPolygonAttributes (FMOD_GEOMETRY *geometry, int index, float *directocclusion, float *reverbocclusion, FMOD_BOOL *doublesided); - -/* - Object manipulation. -*/ - -FMOD_RESULT F_API FMOD_Geometry_SetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL active); -FMOD_RESULT F_API FMOD_Geometry_GetActive (FMOD_GEOMETRY *geometry, FMOD_BOOL *active); -FMOD_RESULT F_API FMOD_Geometry_SetRotation (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *forward, const FMOD_VECTOR *up); -FMOD_RESULT F_API FMOD_Geometry_GetRotation (FMOD_GEOMETRY *geometry, FMOD_VECTOR *forward, FMOD_VECTOR *up); -FMOD_RESULT F_API FMOD_Geometry_SetPosition (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *position); -FMOD_RESULT F_API FMOD_Geometry_GetPosition (FMOD_GEOMETRY *geometry, FMOD_VECTOR *position); -FMOD_RESULT F_API FMOD_Geometry_SetScale (FMOD_GEOMETRY *geometry, const FMOD_VECTOR *scale); -FMOD_RESULT F_API FMOD_Geometry_GetScale (FMOD_GEOMETRY *geometry, FMOD_VECTOR *scale); -FMOD_RESULT F_API FMOD_Geometry_Save (FMOD_GEOMETRY *geometry, void *data, int *datasize); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_Geometry_SetUserData (FMOD_GEOMETRY *geometry, void *userdata); -FMOD_RESULT F_API FMOD_Geometry_GetUserData (FMOD_GEOMETRY *geometry, void **userdata); - -FMOD_RESULT F_API FMOD_Geometry_GetMemoryInfo (FMOD_GEOMETRY *geometry, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -/* - 'Reverb' API -*/ - -FMOD_RESULT F_API FMOD_Reverb_Release (FMOD_REVERB *reverb); - -/* - Reverb manipulation. -*/ - -FMOD_RESULT F_API FMOD_Reverb_Set3DAttributes (FMOD_REVERB *reverb, const FMOD_VECTOR *position, float mindistance, float maxdistance); -FMOD_RESULT F_API FMOD_Reverb_Get3DAttributes (FMOD_REVERB *reverb, FMOD_VECTOR *position, float *mindistance, float *maxdistance); -FMOD_RESULT F_API FMOD_Reverb_SetProperties (FMOD_REVERB *reverb, const FMOD_REVERB_PROPERTIES *properties); -FMOD_RESULT F_API FMOD_Reverb_GetProperties (FMOD_REVERB *reverb, FMOD_REVERB_PROPERTIES *properties); -FMOD_RESULT F_API FMOD_Reverb_SetActive (FMOD_REVERB *reverb, FMOD_BOOL active); -FMOD_RESULT F_API FMOD_Reverb_GetActive (FMOD_REVERB *reverb, FMOD_BOOL *active); - -/* - Userdata set/get. -*/ - -FMOD_RESULT F_API FMOD_Reverb_SetUserData (FMOD_REVERB *reverb, void *userdata); -FMOD_RESULT F_API FMOD_Reverb_GetUserData (FMOD_REVERB *reverb, void **userdata); - -FMOD_RESULT F_API FMOD_Reverb_GetMemoryInfo (FMOD_REVERB *reverb, unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/libs/fmodex/inc/fmod_codec.h b/libs/fmodex/inc/fmod_codec.h deleted file mode 100644 index 2e13eb69d..000000000 --- a/libs/fmodex/inc/fmod_codec.h +++ /dev/null @@ -1,159 +0,0 @@ -/* ==================================================================================================== */ -/* FMOD Ex - codec development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ -/* */ -/* Use this header if you are wanting to develop your own file format plugin to use with */ -/* FMOD's codec system. With this header you can make your own fileformat plugin that FMOD */ -/* can register and use. See the documentation and examples on how to make a working plugin. */ -/* */ -/* ==================================================================================================== */ - -#ifndef _FMOD_CODEC_H -#define _FMOD_CODEC_H - -typedef struct FMOD_CODEC_STATE FMOD_CODEC_STATE; -typedef struct FMOD_CODEC_WAVEFORMAT FMOD_CODEC_WAVEFORMAT; - -/* - Codec callbacks -*/ -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_OPENCALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CLOSECALLBACK) (FMOD_CODEC_STATE *codec_state); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_READCALLBACK) (FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETLENGTHCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETPOSITIONCALLBACK) (FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SOUNDCREATECALLBACK) (FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_METADATACALLBACK) (FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE tagtype, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique); -typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETWAVEFORMAT) (FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat); - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - When creating a codec, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file. - - [REMARKS] - Members marked with [in] mean the variable can be written to. The user can set the value. - Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_CODEC_STATE -] -*/ -typedef struct FMOD_CODEC_DESCRIPTION -{ - const char *name; /* [in] Name of the codec. */ - unsigned int version; /* [in] Plugin writer's version number. */ - int defaultasstream; /* [in] Tells FMOD to open the file as a stream when calling System::createSound, and not a static sample. Should normally be 0 (FALSE), because generally the user wants to decode the file into memory when using System::createSound. Mainly used for formats that decode for a very long time, or could use large amounts of memory when decoded. Usually sequenced formats such as mod/s3m/xm/it/midi fall into this category. It is mainly to stop users that don't know what they're doing from getting FMOD_ERR_MEMORY returned from createSound when they should have in fact called System::createStream or used FMOD_CREATESTREAM in System::createSound. */ - FMOD_TIMEUNIT timeunits; /* [in] When setposition codec is called, only these time formats will be passed to the codec. Use bitwise OR to accumulate different types. */ - FMOD_CODEC_OPENCALLBACK open; /* [in] Open callback for the codec for when FMOD tries to open a sound using this codec. */ - FMOD_CODEC_CLOSECALLBACK close; /* [in] Close callback for the codec for when FMOD tries to close a sound using this codec. */ - FMOD_CODEC_READCALLBACK read; /* [in] Read callback for the codec for when FMOD tries to read some data from the file to the destination format (specified in the open callback). */ - FMOD_CODEC_GETLENGTHCALLBACK getlength; /* [in] Callback to return the length of the song in whatever format required when Sound::getLength is called. */ - FMOD_CODEC_SETPOSITIONCALLBACK setposition; /* [in] Seek callback for the codec for when FMOD tries to seek within the file with Channel::setPosition. */ - FMOD_CODEC_GETPOSITIONCALLBACK getposition; /* [in] Tell callback for the codec for when FMOD tries to get the current position within the with Channel::getPosition. */ - FMOD_CODEC_SOUNDCREATECALLBACK soundcreate; /* [in] Sound creation callback for the codec when FMOD finishes creating the sound. (So the codec can set more parameters for the related created sound, ie loop points/mode or 3D attributes etc). */ - FMOD_CODEC_GETWAVEFORMAT getwaveformat; /* [in] Callback to tell FMOD about the waveformat of a particular subsound. This is to save memory, rather than saving 1000 FMOD_CODEC_WAVEFORMAT structures in the codec, the codec might have a more optimal way of storing this information. */ -} FMOD_CODEC_DESCRIPTION; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Set these values marked 'in' to tell fmod what sort of sound to create. - The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2. - Members marked as 'out' are set by fmod. Do not modify these. Simply specify 0 for these values when declaring the structure, FMOD will fill in the values for you after creation with the correct function pointers. - - [REMARKS] - Members marked with [in] mean the variable can be written to. The user can set the value. - Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - - An FMOD file might be from disk, memory or network, however the file may be opened by the user. - - 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF. - 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), MIDI/MOD/S3M/XM/IT (contain instruments). - The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute. - When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_SOUND_FORMAT - FMOD_FILE_READCALLBACK - FMOD_FILE_SEEKCALLBACK - FMOD_CODEC_METADATACALLBACK - Sound::getSubSound - Sound::getNumSubSounds -] -*/ -struct FMOD_CODEC_WAVEFORMAT -{ - char name[256]; /* [in] Name of sound.*/ - FMOD_SOUND_FORMAT format; /* [in] Format for (decompressed) codec output, ie FMOD_SOUND_FORMAT_PCM8, FMOD_SOUND_FORMAT_PCM16.*/ - int channels; /* [in] Number of channels used by codec, ie mono = 1, stereo = 2. */ - int frequency; /* [in] Default frequency in hz of the codec, ie 44100. */ - unsigned int lengthbytes; /* [in] Length in bytes of the source data. */ - unsigned int lengthpcm; /* [in] Length in decompressed, PCM samples of the file, ie length in seconds * frequency. Used for Sound::getLength and for memory allocation of static decompressed sample data. */ - int blockalign; /* [in] Blockalign in decompressed, PCM samples of the optimal decode chunk size for this format. The codec read callback will be called in multiples of this value. */ - int loopstart; /* [in] Loopstart in decompressed, PCM samples of file. */ - int loopend; /* [in] Loopend in decompressed, PCM samples of file. */ - FMOD_MODE mode; /* [in] Mode to determine whether the sound should by default load as looping, non looping, 2d or 3d. */ - unsigned int channelmask; /* [in] Microsoft speaker channel mask, as defined for WAVEFORMATEXTENSIBLE and is found in ksmedia.h. Leave at 0 to play in natural speaker order. */ -}; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Codec plugin structure that is passed into each callback. - - Set these numsubsounds and waveformat members when called in FMOD_CODEC_OPENCALLBACK to tell fmod what sort of sound to create. - - The format, channels and frequency tell FMOD what sort of hardware buffer to create when you initialize your code. So if you wrote an MP3 codec that decoded to stereo 16bit integer PCM, you would specify FMOD_SOUND_FORMAT_PCM16, and channels would be equal to 2. - - [REMARKS] - Members marked with [in] mean the variable can be written to. The user can set the value. - Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - - An FMOD file might be from disk, memory or internet, however the file may be opened by the user. - - 'numsubsounds' should be 0 if the file is a normal single sound stream or sound. Examples of this would be .WAV, .WMA, .MP3, .AIFF. - 'numsubsounds' should be 1+ if the file is a container format, and does not contain wav data itself. Examples of these types would be CDDA (multiple CD tracks), FSB (contains multiple sounds), DLS (contain instruments). - The arrays of format, channel, frequency, length and blockalign should point to arrays of information based on how many subsounds are in the format. If the number of subsounds is 0 then it should point to 1 of each attribute, the same as if the number of subsounds was 1. If subsounds was 100 for example, each pointer should point to an array of 100 of each attribute. - When a sound has 1 or more subsounds, you must play the individual sounds specified by first obtaining the subsound with Sound::getSubSound. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_SOUND_FORMAT - FMOD_FILE_READCALLBACK - FMOD_FILE_SEEKCALLBACK - FMOD_CODEC_METADATACALLBACK - Sound::getSubSound - Sound::getNumSubSounds -] -*/ -struct FMOD_CODEC_STATE -{ - int numsubsounds; /* [in] Number of 'subsounds' in this sound. Anything other than 0 makes it a 'container' format (ie CDDA/DLS/FSB etc which contain 1 or more su bsounds). For most normal, single sound codec such as WAV/AIFF/MP3, this should be 0 as they are not a container for subsounds, they are the sound by itself. */ - FMOD_CODEC_WAVEFORMAT *waveformat; /* [in] Pointer to an array of format structures containing information about each sample. Can be 0 or NULL if FMOD_CODEC_GETWAVEFORMAT callback is preferred. The number of entries here must equal the number of subsounds defined in the subsound parameter. If numsubsounds = 0 then there should be 1 instance of this structure. */ - void *plugindata; /* [in] Plugin writer created data the codec author wants to attach to this object. */ - - void *filehandle; /* [out] This will return an internal FMOD file handle to use with the callbacks provided. */ - unsigned int filesize; /* [out] This will contain the size of the file in bytes. */ - FMOD_FILE_READCALLBACK fileread; /* [out] This will return a callable FMOD file function to use from codec. */ - FMOD_FILE_SEEKCALLBACK fileseek; /* [out] This will return a callable FMOD file function to use from codec. */ - FMOD_CODEC_METADATACALLBACK metadata; /* [out] This will return a callable FMOD metadata function to use from codec. */ -}; - -#endif - - diff --git a/libs/fmodex/inc/fmod_dsp.h b/libs/fmodex/inc/fmod_dsp.h deleted file mode 100644 index 1c5e2a62b..000000000 --- a/libs/fmodex/inc/fmod_dsp.h +++ /dev/null @@ -1,743 +0,0 @@ -/* ========================================================================================== */ -/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ -/* */ -/* Use this header if you are interested in delving deeper into the FMOD software mixing / */ -/* DSP engine. In this header you can find parameter structures for FMOD system reigstered */ -/* DSP effects and generators. */ -/* Also use this header if you are wanting to develop your own DSP plugin to use with FMOD's */ -/* dsp system. With this header you can make your own DSP plugin that FMOD can */ -/* register and use. See the documentation and examples on how to make a working plugin. */ -/* */ -/* ========================================================================================== */ - -#ifndef _FMOD_DSP_H -#define _FMOD_DSP_H - -typedef struct FMOD_DSP_STATE FMOD_DSP_STATE; - -/* - DSP callbacks -*/ -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_CREATECALLBACK) (FMOD_DSP_STATE *dsp_state); -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RELEASECALLBACK) (FMOD_DSP_STATE *dsp_state); -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_RESETCALLBACK) (FMOD_DSP_STATE *dsp_state); -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_READCALLBACK) (FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPOSITIONCALLBACK)(FMOD_DSP_STATE *dsp_state, unsigned int pos); -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_SETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float value); -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_GETPARAMCALLBACK) (FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr); -typedef FMOD_RESULT (F_CALLBACK *FMOD_DSP_DIALOGCALLBACK) (FMOD_DSP_STATE *dsp_state, void *hwnd, int show); - -/* -[ENUM] -[ - [DESCRIPTION] - These definitions can be used for creating FMOD defined special effects or DSP units. - - [REMARKS] - To get them to be active, first create the unit, then add it somewhere into the DSP network, either at the front of the network near the soundcard unit to affect the global output (by using System::getDSPHead), or on a single channel (using Channel::getDSPHead). - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::createDSPByType -] -*/ -typedef enum -{ - FMOD_DSP_TYPE_UNKNOWN, /* This unit was created via a non FMOD plugin so has an unknown purpose. */ - FMOD_DSP_TYPE_MIXER, /* This unit does nothing but take inputs and mix them together then feed the result to the soundcard unit. */ - FMOD_DSP_TYPE_OSCILLATOR, /* This unit generates sine/square/saw/triangle or noise tones. */ - FMOD_DSP_TYPE_LOWPASS, /* This unit filters sound using a high quality, resonant lowpass filter algorithm but consumes more CPU time. */ - FMOD_DSP_TYPE_ITLOWPASS, /* This unit filters sound using a resonant lowpass filter algorithm that is used in Impulse Tracker, but with limited cutoff range (0 to 8060hz). */ - FMOD_DSP_TYPE_HIGHPASS, /* This unit filters sound using a resonant highpass filter algorithm. */ - FMOD_DSP_TYPE_ECHO, /* This unit produces an echo on the sound and fades out at the desired rate. */ - FMOD_DSP_TYPE_FLANGE, /* This unit produces a flange effect on the sound. */ - FMOD_DSP_TYPE_DISTORTION, /* This unit distorts the sound. */ - FMOD_DSP_TYPE_NORMALIZE, /* This unit normalizes or amplifies the sound to a certain level. */ - FMOD_DSP_TYPE_PARAMEQ, /* This unit attenuates or amplifies a selected frequency range. */ - FMOD_DSP_TYPE_PITCHSHIFT, /* This unit bends the pitch of a sound without changing the speed of playback. */ - FMOD_DSP_TYPE_CHORUS, /* This unit produces a chorus effect on the sound. */ - FMOD_DSP_TYPE_VSTPLUGIN, /* This unit allows the use of Steinberg VST plugins */ - FMOD_DSP_TYPE_WINAMPPLUGIN, /* This unit allows the use of Nullsoft Winamp plugins */ - FMOD_DSP_TYPE_ITECHO, /* This unit produces an echo on the sound and fades out at the desired rate as is used in Impulse Tracker. */ - FMOD_DSP_TYPE_COMPRESSOR, /* This unit implements dynamic compression (linked multichannel, wideband) */ - FMOD_DSP_TYPE_SFXREVERB, /* This unit implements SFX reverb */ - FMOD_DSP_TYPE_LOWPASS_SIMPLE, /* This unit filters sound using a simple lowpass with no resonance, but has flexible cutoff and is fast. */ - FMOD_DSP_TYPE_DELAY, /* This unit produces different delays on individual channels of the sound. */ - FMOD_DSP_TYPE_TREMOLO, /* This unit produces a tremolo / chopper effect on the sound. */ - FMOD_DSP_TYPE_LADSPAPLUGIN, /* This unit allows the use of LADSPA standard plugins. */ - FMOD_DSP_TYPE_HIGHPASS_SIMPLE, /* This unit filters sound using a simple highpass with no resonance, but has flexible cutoff and is fast. */ - FMOD_DSP_TYPE_HARDWARE = 1000, /* Offset that platform specific FMOD_HARDWARE DSPs will start at. */ - FMOD_DSP_TYPE_FORCEINT = 65536 /* Makes sure this enum is signed 32bit. */ -} FMOD_DSP_TYPE; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure to define a parameter for a DSP unit. - - [REMARKS] - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::createDSP - DSP::setParameter -] -*/ -typedef struct FMOD_DSP_PARAMETERDESC -{ - float min; /* [w] Minimum value of the parameter (ie 100.0). */ - float max; /* [w] Maximum value of the parameter (ie 22050.0). */ - float defaultval; /* [w] Default value of parameter. */ - char name[16]; /* [w] Name of the parameter to be displayed (ie "Cutoff frequency"). */ - char label[16]; /* [w] Short string to be put next to value to denote the unit type (ie "hz"). */ - const char *description; /* [w] Description of the parameter to be displayed as a help item / tooltip for this parameter. */ -} FMOD_DSP_PARAMETERDESC; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - When creating a DSP unit, declare one of these and provide the relevant callbacks and name for FMOD to use when it creates and uses a DSP unit of this type. - - [REMARKS] - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - - There are 2 different ways to change a parameter in this architecture. - One is to use DSP::setParameter / DSP::getParameter. This is platform independant and is dynamic, so new unknown plugins can have their parameters enumerated and used. - The other is to use DSP::showConfigDialog. This is platform specific and requires a GUI, and will display a dialog box to configure the plugin. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::createDSP - FMOD_DSP_STATE -] -*/ -typedef struct FMOD_DSP_DESCRIPTION -{ - char name[32]; /* [w] Name of the unit to be displayed in the network. */ - unsigned int version; /* [w] Plugin writer's version number. */ - int channels; /* [w] Number of channels. Use 0 to process whatever number of channels is currently in the network. >0 would be mostly used if the unit is a unit that only generates sound. */ - FMOD_DSP_CREATECALLBACK create; /* [w] Create callback. This is called when DSP unit is created. Can be null. */ - FMOD_DSP_RELEASECALLBACK release; /* [w] Release callback. This is called just before the unit is freed so the user can do any cleanup needed for the unit. Can be null. */ - FMOD_DSP_RESETCALLBACK reset; /* [w] Reset callback. This is called by the user to reset any history buffers that may need resetting for a filter, when it is to be used or re-used for the first time to its initial clean state. Use to avoid clicks or artifacts. */ - FMOD_DSP_READCALLBACK read; /* [w] Read callback. Processing is done here. Can be null. */ - FMOD_DSP_SETPOSITIONCALLBACK setposition; /* [w] Set position callback. This is called if the unit wants to update its position info but not process data, or reset a cursor position internally if it is reading data from a certain source. Can be null. */ - - int numparameters; /* [w] Number of parameters used in this filter. The user finds this with DSP::getNumParameters */ - FMOD_DSP_PARAMETERDESC *paramdesc; /* [w] Variable number of parameter structures. */ - FMOD_DSP_SETPARAMCALLBACK setparameter; /* [w] This is called when the user calls DSP::setParameter. Can be null. */ - FMOD_DSP_GETPARAMCALLBACK getparameter; /* [w] This is called when the user calls DSP::getParameter. Can be null. */ - FMOD_DSP_DIALOGCALLBACK config; /* [w] This is called when the user calls DSP::showConfigDialog. Can be used to display a dialog to configure the filter. Can be null. */ - int configwidth; /* [w] Width of config dialog graphic if there is one. 0 otherwise.*/ - int configheight; /* [w] Height of config dialog graphic if there is one. 0 otherwise.*/ - void *userdata; /* [w] Optional. Specify 0 to ignore. This is user data to be attached to the DSP unit during creation. Access via DSP::getUserData. */ -} FMOD_DSP_DESCRIPTION; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - DSP plugin structure that is passed into each callback. - - [REMARKS] - Members marked with [r] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - Members marked with [w] mean the variable can be written to. The user can set the value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_DSP_DESCRIPTION -] -*/ -struct FMOD_DSP_STATE -{ - FMOD_DSP *instance; /* [r] Handle to the DSP hand the user created. Not to be modified. C++ users cast to FMOD::DSP to use. */ - void *plugindata; /* [w] Plugin writer created data the output author wants to attach to this object. */ - unsigned short speakermask; /* [w] Specifies which speakers the DSP effect is active on */ -}; - - -/* - =================================================================================================== - - FMOD built in effect parameters. - Use DSP::setParameter with these enums for the 'index' parameter. - - =================================================================================================== -*/ - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_OSCILLATOR filter. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_OSCILLATOR_TYPE, /* Waveform type. 0 = sine. 1 = square. 2 = sawup. 3 = sawdown. 4 = triangle. 5 = noise. */ - FMOD_DSP_OSCILLATOR_RATE /* Frequency of the sinewave in hz. 1.0 to 22000.0. Default = 220.0. */ -} FMOD_DSP_OSCILLATOR; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_LOWPASS filter. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_LOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0. */ - FMOD_DSP_LOWPASS_RESONANCE /* Lowpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ -} FMOD_DSP_LOWPASS; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_ITLOWPASS filter. - This is different to the default FMOD_DSP_TYPE_ITLOWPASS filter in that it uses a different quality algorithm and is - the filter used to produce the correct sounding playback in .IT files. - FMOD Ex's .IT playback uses this filter. - - [REMARKS] - Note! This filter actually has a limited cutoff frequency below the specified maximum, due to its limited design, - so for a more open range filter use FMOD_DSP_LOWPASS or if you don't mind not having resonance, - FMOD_DSP_LOWPASS_SIMPLE. - The effective maximum cutoff is about 8060hz. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_ITLOWPASS_CUTOFF, /* Lowpass cutoff frequency in hz. 1.0 to 22000.0. Default = 5000.0/ */ - FMOD_DSP_ITLOWPASS_RESONANCE /* Lowpass resonance Q value. 0.0 to 127.0. Default = 1.0. */ -} FMOD_DSP_ITLOWPASS; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_HIGHPASS filter. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_HIGHPASS_CUTOFF, /* Highpass cutoff frequency in hz. 1.0 to output 22000.0. Default = 5000.0. */ - FMOD_DSP_HIGHPASS_RESONANCE /* Highpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ -} FMOD_DSP_HIGHPASS; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_ECHO filter. - - [REMARKS] - Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer. - Larger echo delays result in larger amounts of memory allocated. - - 'maxchannels' also dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the echo unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel echo, etc. - If the echo effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes. - When the echo is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count. - If a channel echo is set to a lower number than the sound's channel count that is coming in, it will not echo the sound. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_ECHO_DELAY, /* Echo delay in ms. 10 to 5000. Default = 500. */ - FMOD_DSP_ECHO_DECAYRATIO, /* Echo decay per delay. 0 to 1. 1.0 = No decay, 0.0 = total decay (ie simple 1 line delay). Default = 0.5. */ - FMOD_DSP_ECHO_MAXCHANNELS, /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ - FMOD_DSP_ECHO_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 1.0. */ - FMOD_DSP_ECHO_WETMIX /* Volume of echo signal to pass to output. 0.0 to 1.0. Default = 1.0. */ -} FMOD_DSP_ECHO; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_DELAY filter. - - [REMARKS] - Note. Every time MaxDelay is changed, the plugin re-allocates the delay buffer. This means the delay will dissapear at that time while it refills its new buffer. - A larger MaxDelay results in larger amounts of memory allocated. - Channel delays above MaxDelay will be clipped to MaxDelay and the delay buffer will not be resized. - - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_DELAY_CH0, /* Channel #0 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH1, /* Channel #1 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH2, /* Channel #2 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH3, /* Channel #3 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH4, /* Channel #4 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH5, /* Channel #5 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH6, /* Channel #6 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH7, /* Channel #7 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH8, /* Channel #8 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH9, /* Channel #9 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH10, /* Channel #10 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH11, /* Channel #11 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH12, /* Channel #12 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH13, /* Channel #13 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH14, /* Channel #14 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_CH15, /* Channel #15 Delay in ms. 0 to 10000. Default = 0. */ - FMOD_DSP_DELAY_MAXDELAY /* Maximum delay in ms. 0 to 10000. Default = 10. */ -} FMOD_DSP_DELAY; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_FLANGE filter. - - [REMARKS] - Flange is an effect where the signal is played twice at the same time, and one copy slides back and forth creating a whooshing or flanging effect. - As there are 2 copies of the same signal, by default each signal is given 50% mix, so that the total is not louder than the original unaffected signal. - - Flange depth is a percentage of a 10ms shift from the original signal. Anything above 10ms is not considered flange because to the ear it begins to 'echo' so 10ms is the highest value possible. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_FLANGE_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.45. */ - FMOD_DSP_FLANGE_WETMIX, /* Volume of flange signal to pass to output. 0.0 to 1.0. Default = 0.55. */ - FMOD_DSP_FLANGE_DEPTH, /* Flange depth (percentage of 40ms delay). 0.01 to 1.0. Default = 1.0. */ - FMOD_DSP_FLANGE_RATE /* Flange speed in hz. 0.0 to 20.0. Default = 0.1. */ -} FMOD_DSP_FLANGE; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_TREMOLO filter. - - [REMARKS] - The tremolo effect varies the amplitude of a sound. Depending on the settings, this unit can produce a tremolo, chopper or auto-pan effect. - - The shape of the LFO (low freq. oscillator) can morphed between sine, triangle and sawtooth waves using the FMOD_DSP_TREMOLO_SHAPE and FMOD_DSP_TREMOLO_SKEW parameters. - FMOD_DSP_TREMOLO_DUTY and FMOD_DSP_TREMOLO_SQUARE are useful for a chopper-type effect where the first controls the on-time duration and second controls the flatness of the envelope. - FMOD_DSP_TREMOLO_SPREAD varies the LFO phase between channels to get an auto-pan effect. This works best with a sine shape LFO. - The LFO can be synchronized using the FMOD_DSP_TREMOLO_PHASE parameter which sets its instantaneous phase. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_TREMOLO_FREQUENCY, /* LFO frequency in Hz. 0.1 to 20. Default = 4. */ - FMOD_DSP_TREMOLO_DEPTH, /* Tremolo depth. 0 to 1. Default = 0. */ - FMOD_DSP_TREMOLO_SHAPE, /* LFO shape morph between triangle and sine. 0 to 1. Default = 0. */ - FMOD_DSP_TREMOLO_SKEW, /* Time-skewing of LFO cycle. -1 to 1. Default = 0. */ - FMOD_DSP_TREMOLO_DUTY, /* LFO on-time. 0 to 1. Default = 0.5. */ - FMOD_DSP_TREMOLO_SQUARE, /* Flatness of the LFO shape. 0 to 1. Default = 0. */ - FMOD_DSP_TREMOLO_PHASE, /* Instantaneous LFO phase. 0 to 1. Default = 0. */ - FMOD_DSP_TREMOLO_SPREAD /* Rotation / auto-pan effect. -1 to 1. Default = 0. */ -} FMOD_DSP_TREMOLO; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_DISTORTION filter. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_DISTORTION_LEVEL /* Distortion value. 0.0 to 1.0. Default = 0.5. */ -} FMOD_DSP_DISTORTION; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_NORMALIZE filter. - - [REMARKS] - Normalize amplifies the sound based on the maximum peaks within the signal. - For example if the maximum peaks in the signal were 50% of the bandwidth, it would scale the whole sound by 2. - The lower threshold value makes the normalizer ignores peaks below a certain point, to avoid over-amplification if a loud signal suddenly came in, and also to avoid amplifying to maximum things like background hiss. - - Because FMOD is a realtime audio processor, it doesn't have the luxury of knowing the peak for the whole sound (ie it can't see into the future), so it has to process data as it comes in. - To avoid very sudden changes in volume level based on small samples of new data, fmod fades towards the desired amplification which makes for smooth gain control. The fadetime parameter can control this. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_NORMALIZE_FADETIME, /* Time to ramp the silence to full in ms. 0.0 to 20000.0. Default = 5000.0. */ - FMOD_DSP_NORMALIZE_THRESHHOLD, /* Lower volume range threshold to ignore. 0.0 to 1.0. Default = 0.1. Raise higher to stop amplification of very quiet signals. */ - FMOD_DSP_NORMALIZE_MAXAMP /* Maximum amplification allowed. 1.0 to 100000.0. Default = 20.0. 1.0 = no amplifaction, higher values allow more boost. */ -} FMOD_DSP_NORMALIZE; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_PARAMEQ filter. - - [REMARKS] - Parametric EQ is a bandpass filter that attenuates or amplifies a selected frequency and its neighbouring frequencies. - - To create a multi-band EQ create multiple FMOD_DSP_TYPE_PARAMEQ units and set each unit to different frequencies, for example 1000hz, 2000hz, 4000hz, 8000hz, 16000hz with a range of 1 octave each. - - When a frequency has its gain set to 1.0, the sound will be unaffected and represents the original signal exactly. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_PARAMEQ_CENTER, /* Frequency center. 20.0 to 22000.0. Default = 8000.0. */ - FMOD_DSP_PARAMEQ_BANDWIDTH, /* Octave range around the center frequency to filter. 0.2 to 5.0. Default = 1.0. */ - FMOD_DSP_PARAMEQ_GAIN /* Frequency Gain. 0.05 to 3.0. Default = 1.0. */ -} FMOD_DSP_PARAMEQ; - - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_PITCHSHIFT filter. - - [REMARKS] - This pitch shifting unit can be used to change the pitch of a sound without speeding it up or slowing it down. - It can also be used for time stretching or scaling, for example if the pitch was doubled, and the frequency of the sound was halved, the pitch of the sound would sound correct but it would be twice as slow. - - Warning! This filter is very computationally expensive! Similar to a vocoder, it requires several overlapping FFT and IFFT's to produce smooth output, and can require around 440mhz for 1 stereo 48khz signal using the default settings. - Reducing the signal to mono will half the cpu usage. - Reducing this will lower audio quality, but what settings to use are largely dependant on the sound being played. A noisy polyphonic signal will need higher fft size compared to a speaking voice for example. - - This pitch shifter is based on the pitch shifter code at http://www.dspdimension.com, written by Stephan M. Bernsee. - The original code is COPYRIGHT 1999-2003 Stephan M. Bernsee . - - 'maxchannels' dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the pitch shift unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel pitch shift, etc. - If the pitch shift effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes. - When the pitch shift is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count. - If a channel pitch shift is set to a lower number than the sound's channel count that is coming in, it will not pitch shift the sound. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_PITCHSHIFT_PITCH, /* Pitch value. 0.5 to 2.0. Default = 1.0. 0.5 = one octave down, 2.0 = one octave up. 1.0 does not change the pitch. */ - FMOD_DSP_PITCHSHIFT_FFTSIZE, /* FFT window size. 256, 512, 1024, 2048, 4096. Default = 1024. Increase this to reduce 'smearing'. This effect is a warbling sound similar to when an mp3 is encoded at very low bitrates. */ - FMOD_DSP_PITCHSHIFT_OVERLAP, /* Removed. Do not use. FMOD now uses 4 overlaps and cannot be changed. */ - FMOD_DSP_PITCHSHIFT_MAXCHANNELS /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ -} FMOD_DSP_PITCHSHIFT; - - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_CHORUS filter. - - [REMARKS] - Chrous is an effect where the sound is more 'spacious' due to 1 to 3 versions of the sound being played along side the original signal but with the pitch of each copy modulating on a sine wave. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_CHORUS_DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.5. */ - FMOD_DSP_CHORUS_WETMIX1, /* Volume of 1st chorus tap. 0.0 to 1.0. Default = 0.5. */ - FMOD_DSP_CHORUS_WETMIX2, /* Volume of 2nd chorus tap. This tap is 90 degrees out of phase of the first tap. 0.0 to 1.0. Default = 0.5. */ - FMOD_DSP_CHORUS_WETMIX3, /* Volume of 3rd chorus tap. This tap is 90 degrees out of phase of the second tap. 0.0 to 1.0. Default = 0.5. */ - FMOD_DSP_CHORUS_DELAY, /* Chorus delay in ms. 0.1 to 100.0. Default = 40.0 ms. */ - FMOD_DSP_CHORUS_RATE, /* Chorus modulation rate in hz. 0.0 to 20.0. Default = 0.8 hz. */ - FMOD_DSP_CHORUS_DEPTH /* Chorus modulation depth. 0.0 to 1.0. Default = 0.03. */ -} FMOD_DSP_CHORUS; - - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_ITECHO filter. - This is effectively a software based echo filter that emulates the DirectX DMO echo effect. Impulse tracker files can support this, and FMOD will produce the effect on ANY platform, not just those that support DirectX effects! - - [REMARKS] - Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer. - Larger echo delays result in larger amounts of memory allocated. - - As this is a stereo filter made mainly for IT playback, it is targeted for stereo signals. - With mono signals only the FMOD_DSP_ITECHO_LEFTDELAY is used. - For multichannel signals (>2) there will be no echo on those channels. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::SetParameter - DSP::GetParameter - FMOD_DSP_TYPE - System::addDSP -] -*/ -typedef enum -{ - FMOD_DSP_ITECHO_WETDRYMIX, /* Ratio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0.0 through 100.0 (all wet). The default value is 50. */ - FMOD_DSP_ITECHO_FEEDBACK, /* Percentage of output fed back into input, in the range from 0.0 through 100.0. The default value is 50. */ - FMOD_DSP_ITECHO_LEFTDELAY, /* Delay for left channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ - FMOD_DSP_ITECHO_RIGHTDELAY, /* Delay for right channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ - FMOD_DSP_ITECHO_PANDELAY /* Value that specifies whether to swap left and right delays with each successive echo. The default value is zero, meaning no swap. Possible values are defined as 0.0 (equivalent to FALSE) and 1.0 (equivalent to TRUE). CURRENTLY NOT SUPPORTED. */ -} FMOD_DSP_ITECHO; - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_COMPRESSOR unit. - This is a simple linked multichannel software limiter that is uniform across the whole spectrum. - - [REMARKS] - The limiter is not guaranteed to catch every peak above the threshold level, - because it cannot apply gain reduction instantaneously - the time delay is - determined by the attack time. However setting the attack time too short will - distort the sound, so it is a compromise. High level peaks can be avoided by - using a short attack time - but not too short, and setting the threshold a few - decibels below the critical level. - - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::SetParameter - DSP::GetParameter - FMOD_DSP_TYPE - System::addDSP -] -*/ -typedef enum -{ - FMOD_DSP_COMPRESSOR_THRESHOLD, /* Threshold level (dB) in the range from -60 through 0. The default value is 0. */ - FMOD_DSP_COMPRESSOR_ATTACK, /* Gain reduction attack time (milliseconds), in the range from 10 through 200. The default value is 50. */ - FMOD_DSP_COMPRESSOR_RELEASE, /* Gain reduction release time (milliseconds), in the range from 20 through 1000. The default value is 50. */ - FMOD_DSP_COMPRESSOR_GAINMAKEUP /* Make-up gain (dB) applied after limiting, in the range from 0 through 30. The default value is 0. */ -} FMOD_DSP_COMPRESSOR; - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_SFXREVERB unit. - - [REMARKS] - This is a high quality I3DL2 based reverb. - On top of the I3DL2 property set, "Dry Level" is also included to allow the dry mix to be changed. - - These properties can be set with presets in FMOD_REVERB_PRESETS. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::SetParameter - DSP::GetParameter - FMOD_DSP_TYPE - System::addDSP - FMOD_REVERB_PRESETS -] -*/ -typedef enum -{ - FMOD_DSP_SFXREVERB_DRYLEVEL, /* Dry Level : Mix level of dry signal in output in mB. Ranges from -10000.0 to 0.0. Default is 0. */ - FMOD_DSP_SFXREVERB_ROOM, /* Room : Room effect level at low frequencies in mB. Ranges from -10000.0 to 0.0. Default is -10000.0. */ - FMOD_DSP_SFXREVERB_ROOMHF, /* Room HF : Room effect high-frequency level re. low frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ - FMOD_DSP_SFXREVERB_DECAYTIME, /* Decay Time : Reverberation decay time at low-frequencies in seconds. Ranges from 0.1 to 20.0. Default is 1.0. */ - FMOD_DSP_SFXREVERB_DECAYHFRATIO, /* Decay HF Ratio : High-frequency to low-frequency decay time ratio. Ranges from 0.1 to 2.0. Default is 0.5. */ - FMOD_DSP_SFXREVERB_REFLECTIONSLEVEL, /* Reflections : Early reflections level relative to room effect in mB. Ranges from -10000.0 to 1000.0. Default is -10000.0. */ - FMOD_DSP_SFXREVERB_REFLECTIONSDELAY, /* Reflect Delay : Delay time of first reflection in seconds. Ranges from 0.0 to 0.3. Default is 0.02. */ - FMOD_DSP_SFXREVERB_REVERBLEVEL, /* Reverb : Late reverberation level relative to room effect in mB. Ranges from -10000.0 to 2000.0. Default is 0.0. */ - FMOD_DSP_SFXREVERB_REVERBDELAY, /* Reverb Delay : Late reverberation delay time relative to first reflection in seconds. Ranges from 0.0 to 0.1. Default is 0.04. */ - FMOD_DSP_SFXREVERB_DIFFUSION, /* Diffusion : Reverberation diffusion (echo density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ - FMOD_DSP_SFXREVERB_DENSITY, /* Density : Reverberation density (modal density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ - FMOD_DSP_SFXREVERB_HFREFERENCE, /* HF Reference : Reference high frequency in Hz. Ranges from 20.0 to 20000.0. Default is 5000.0. */ - FMOD_DSP_SFXREVERB_ROOMLF, /* Room LF : Room effect low-frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ - FMOD_DSP_SFXREVERB_LFREFERENCE /* LF Reference : Reference low-frequency in Hz. Ranges from 20.0 to 1000.0. Default is 250.0. */ -} FMOD_DSP_SFXREVERB; - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_LOWPASS_SIMPLE filter. - This is a very simple low pass filter, based on two single-pole RC time-constant modules. - The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_LOWPASS_SIMPLE_CUTOFF /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0 */ -} FMOD_DSP_LOWPASS_SIMPLE; - -/* -[ENUM] -[ - [DESCRIPTION] - Parameter types for the FMOD_DSP_TYPE_HIGHPASS_SIMPLE filter. - This is a very simple single-order high pass filter. - The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering. - - [REMARKS] - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - DSP::setParameter - DSP::getParameter - FMOD_DSP_TYPE -] -*/ -typedef enum -{ - FMOD_DSP_HIGHPASS_SIMPLE_CUTOFF /* Highpass cutoff frequency in hz. 10.0 to 22000.0. Default = 1000.0 */ -} FMOD_DSP_HIGHPASS_SIMPLE; - -#endif - diff --git a/libs/fmodex/inc/fmod_errors.h b/libs/fmodex/inc/fmod_errors.h deleted file mode 100644 index fdb85984b..000000000 --- a/libs/fmodex/inc/fmod_errors.h +++ /dev/null @@ -1,123 +0,0 @@ - -/* ============================================================================================== */ -/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ -/* */ -/* Use this header if you want to store or display a string version / english explanation of */ -/* the FMOD error codes. */ -/* */ -/* ============================================================================================== */ - -#ifndef _FMOD_ERRORS_H -#define _FMOD_ERRORS_H - -#include "fmod.h" - -#ifdef __GNUC__ -static const char *FMOD_ErrorString(FMOD_RESULT errcode) __attribute__((unused)); -#endif - -static const char *FMOD_ErrorString(FMOD_RESULT errcode) -{ - switch (errcode) - { - case FMOD_ERR_ALREADYLOCKED: return "Tried to call lock a second time before unlock was called. "; - case FMOD_ERR_BADCOMMAND: return "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). "; - case FMOD_ERR_CDDA_DRIVERS: return "Neither NTSCSI nor ASPI could be initialised. "; - case FMOD_ERR_CDDA_INIT: return "An error occurred while initialising the CDDA subsystem. "; - case FMOD_ERR_CDDA_INVALID_DEVICE: return "Couldn't find the specified device. "; - case FMOD_ERR_CDDA_NOAUDIO: return "No audio tracks on the specified disc. "; - case FMOD_ERR_CDDA_NODEVICES: return "No CD/DVD devices were found. "; - case FMOD_ERR_CDDA_NODISC: return "No disc present in the specified drive. "; - case FMOD_ERR_CDDA_READ: return "A CDDA read error occurred. "; - case FMOD_ERR_CHANNEL_ALLOC: return "Error trying to allocate a channel. "; - case FMOD_ERR_CHANNEL_STOLEN: return "The specified channel has been reused to play another sound. "; - case FMOD_ERR_COM: return "A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. "; - case FMOD_ERR_DMA: return "DMA Failure. See debug output for more information. "; - case FMOD_ERR_DSP_CONNECTION: return "DSP connection error. Connection possibly caused a cyclic dependancy. Or tried to connect a tree too many units deep (more than 128). "; - case FMOD_ERR_DSP_FORMAT: return "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. "; - case FMOD_ERR_DSP_NOTFOUND: return "DSP connection error. Couldn't find the DSP unit specified. "; - case FMOD_ERR_DSP_RUNNING: return "DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. "; - case FMOD_ERR_DSP_TOOMANYCONNECTIONS: return "DSP connection error. The unit being connected to or disconnected should only have 1 input or output. "; - case FMOD_ERR_EVENT_ALREADY_LOADED: return "The specified project or bank has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. "; - case FMOD_ERR_EVENT_FAILED: return "An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. "; - case FMOD_ERR_EVENT_GUIDCONFLICT: return "An event with the same GUID already exists. "; - case FMOD_ERR_EVENT_INFOONLY: return "Can't execute this command on an EVENT_INFOONLY event. "; - case FMOD_ERR_EVENT_INTERNAL: return "An error occured that wasn't supposed to. See debug log for reason. "; - case FMOD_ERR_EVENT_MAXSTREAMS: return "Event failed because 'Max streams' was hit when FMOD_EVENT_INIT_FAIL_ON_MAXSTREAMS was specified. "; - case FMOD_ERR_EVENT_MISMATCH: return "FSB mismatches the FEV it was compiled with, the stream/sample mode it was meant to be created with was different, or the FEV was built for a different platform. "; - case FMOD_ERR_EVENT_NAMECONFLICT: return "A category with the same name already exists. "; - case FMOD_ERR_EVENT_NEEDSSIMPLE: return "Tried to call a function on a complex event that's only supported by simple events. "; - case FMOD_ERR_EVENT_NOTFOUND: return "The requested event, event group, event category or event property could not be found. "; - case FMOD_ERR_FILE_BAD: return "Error loading file. "; - case FMOD_ERR_FILE_COULDNOTSEEK: return "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. "; - case FMOD_ERR_FILE_DISKEJECTED: return "Media was ejected while reading. "; - case FMOD_ERR_FILE_EOF: return "End of file unexpectedly reached while trying to read essential data (truncated data?). "; - case FMOD_ERR_FILE_NOTFOUND: return "File not found. "; - case FMOD_ERR_FILE_UNWANTED: return "Unwanted file access occured. "; - case FMOD_ERR_FORMAT: return "Unsupported file or audio format. "; - case FMOD_ERR_HTTP: return "A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. "; - case FMOD_ERR_HTTP_ACCESS: return "The specified resource requires authentication or is forbidden. "; - case FMOD_ERR_HTTP_PROXY_AUTH: return "Proxy authentication is required to access the specified resource. "; - case FMOD_ERR_HTTP_SERVER_ERROR: return "A HTTP server error occurred. "; - case FMOD_ERR_HTTP_TIMEOUT: return "The HTTP request timed out. "; - case FMOD_ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function. "; - case FMOD_ERR_INITIALIZED: return "Cannot call this command after System::init. "; - case FMOD_ERR_INTERNAL: return "An error occured that wasn't supposed to. Contact support. "; - case FMOD_ERR_INVALID_ADDRESS: return "On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) "; - case FMOD_ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float. "; - case FMOD_ERR_INVALID_HANDLE: return "An invalid object handle was used. "; - case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function. "; - case FMOD_ERR_INVALID_POSITION: return "An invalid seek position was passed to this function. "; - case FMOD_ERR_INVALID_SPEAKER: return "An invalid speaker was passed to this function based on the current speaker mode. "; - case FMOD_ERR_INVALID_SYNCPOINT: return "The syncpoint did not come from this sound handle. "; - case FMOD_ERR_INVALID_VECTOR: return "The vectors passed in are not unit length, or perpendicular. "; - case FMOD_ERR_MAXAUDIBLE: return "Reached maximum audible playback count for this sound's soundgroup. "; - case FMOD_ERR_MEMORY: return "Not enough memory or resources. "; - case FMOD_ERR_MEMORY_CANTPOINT: return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. "; - case FMOD_ERR_MEMORY_SRAM: return "Not enough memory or resources on console sound ram. "; - case FMOD_ERR_MUSIC_NOCALLBACK: return "The music callback is required, but it has not been set. "; - case FMOD_ERR_MUSIC_NOTFOUND: return "The requested music entity could not be found. "; - case FMOD_ERR_MUSIC_UNINITIALIZED: return "Music system is not initialized probably because no music data is loaded. "; - case FMOD_ERR_NEEDS2D: return "Tried to call a command on a 3d sound when the command was meant for 2d sound. "; - case FMOD_ERR_NEEDS3D: return "Tried to call a command on a 2d sound when the command was meant for 3d sound. "; - case FMOD_ERR_NEEDSHARDWARE: return "Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). "; - case FMOD_ERR_NEEDSSOFTWARE: return "Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. "; - case FMOD_ERR_NET_CONNECT: return "Couldn't connect to the specified host. "; - case FMOD_ERR_NET_SOCKET_ERROR: return "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. "; - case FMOD_ERR_NET_URL: return "The specified URL couldn't be resolved. "; - case FMOD_ERR_NET_WOULD_BLOCK: return "Operation on a non-blocking socket could not complete immediately. "; - case FMOD_ERR_NOTREADY: return "Operation could not be performed because specified sound/DSP connection is not ready. "; - case FMOD_ERR_OUTPUT_ALLOCATED: return "Error initializing output device, but more specifically, the output device is already in use and cannot be reused. "; - case FMOD_ERR_OUTPUT_CREATEBUFFER: return "Error creating hardware sound buffer. "; - case FMOD_ERR_OUTPUT_DRIVERCALL: return "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. "; - case FMOD_ERR_OUTPUT_ENUMERATION: return "Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. "; - case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). "; - case FMOD_ERR_OUTPUT_INIT: return "Error initializing output device. "; - case FMOD_ERR_OUTPUT_NOHARDWARE: return "FMOD_HARDWARE was specified but the sound card does not have the resources necessary to play it. "; - case FMOD_ERR_OUTPUT_NOSOFTWARE: return "Attempted to create a software sound but no software channels were specified in System::init. "; - case FMOD_ERR_PAN: return "Panning only works with mono or stereo sound sources. "; - case FMOD_ERR_PLUGIN: return "An unspecified error has been returned from a 3rd party plugin. "; - case FMOD_ERR_PLUGIN_INSTANCES: return "The number of allowed instances of a plugin has been exceeded. "; - case FMOD_ERR_PLUGIN_MISSING: return "A requested output, dsp unit type or codec was not available. "; - case FMOD_ERR_PLUGIN_RESOURCE: return "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback or other DLLs that it needs to load) "; - case FMOD_ERR_PRELOADED: return "The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. "; - case FMOD_ERR_PROGRAMMERSOUND: return "The specified sound is still in use by the event system, wait for the event which is using it finish with it. "; - case FMOD_ERR_RECORD: return "An error occured trying to initialize the recording device. "; - case FMOD_ERR_REVERB_INSTANCE: return "Specified instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because it is an invalid instance number or the reverb doesnt exist. "; - case FMOD_ERR_SUBSOUNDS: return "The error occured because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound, or a parent sound was played without setting up a sentence first. "; - case FMOD_ERR_SUBSOUND_ALLOCATED: return "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. "; - case FMOD_ERR_SUBSOUND_CANTMOVE: return "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. "; - case FMOD_ERR_SUBSOUND_MODE: return "The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. "; - case FMOD_ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags. "; - case FMOD_ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. "; - case FMOD_ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support! "; - case FMOD_ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called. "; - case FMOD_ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. "; - case FMOD_ERR_UPDATE: return "An error caused by System::update occured. "; - case FMOD_ERR_VERSION: return "The version number of this file format is not supported. "; - case FMOD_OK: return "No errors."; - default : return "Unknown error."; - }; -} - -#endif diff --git a/libs/fmodex/inc/fmod_memoryinfo.h b/libs/fmodex/inc/fmod_memoryinfo.h deleted file mode 100644 index 6db9de3b8..000000000 --- a/libs/fmodex/inc/fmod_memoryinfo.h +++ /dev/null @@ -1,201 +0,0 @@ -/* ============================================================================================= */ -/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2008-2011. */ -/* */ -/* Use this header if you are interested in getting detailed information on FMOD's memory */ -/* usage. See the documentation for more details. */ -/* */ -/* ============================================================================================= */ - -#ifndef _FMOD_MEMORYINFO_H -#define _FMOD_MEMORYINFO_H - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Structure to be filled with detailed memory usage information of an FMOD object - - [REMARKS] - Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. - On return from getMemoryInfo, each member of this structure will hold the amount of memory used for its type in bytes. - - Members marked with [in] mean the user sets the value before passing it to the function. - Members marked with [out] mean FMOD sets the value to be used after the function exits. - - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - System::getMemoryInfo - EventSystem::getMemoryInfo - FMOD_MEMBITS - FMOD_EVENT_MEMBITS -] -*/ -typedef struct FMOD_MEMORY_USAGE_DETAILS -{ - unsigned int other; /* [out] Memory not accounted for by other types */ - unsigned int string; /* [out] String data */ - unsigned int system; /* [out] System object and various internals */ - unsigned int plugins; /* [out] Plugin objects and internals */ - unsigned int output; /* [out] Output module object and internals */ - unsigned int channel; /* [out] Channel related memory */ - unsigned int channelgroup; /* [out] ChannelGroup objects and internals */ - unsigned int codec; /* [out] Codecs allocated for streaming */ - unsigned int file; /* [out] File buffers and structures */ - unsigned int sound; /* [out] Sound objects and internals */ - unsigned int secondaryram; /* [out] Sound data stored in secondary RAM */ - unsigned int soundgroup; /* [out] SoundGroup objects and internals */ - unsigned int streambuffer; /* [out] Stream buffer memory */ - unsigned int dspconnection; /* [out] DSPConnection objects and internals */ - unsigned int dsp; /* [out] DSP implementation objects */ - unsigned int dspcodec; /* [out] Realtime file format decoding DSP objects */ - unsigned int profile; /* [out] Profiler memory footprint. */ - unsigned int recordbuffer; /* [out] Buffer used to store recorded data from microphone */ - unsigned int reverb; /* [out] Reverb implementation objects */ - unsigned int reverbchannelprops; /* [out] Reverb channel properties structs */ - unsigned int geometry; /* [out] Geometry objects and internals */ - unsigned int syncpoint; /* [out] Sync point memory. */ - unsigned int eventsystem; /* [out] EventSystem and various internals */ - unsigned int musicsystem; /* [out] MusicSystem and various internals */ - unsigned int fev; /* [out] Definition of objects contained in all loaded projects e.g. events, groups, categories */ - unsigned int memoryfsb; /* [out] Data loaded with preloadFSB */ - unsigned int eventproject; /* [out] EventProject objects and internals */ - unsigned int eventgroupi; /* [out] EventGroup objects and internals */ - unsigned int soundbankclass; /* [out] Objects used to manage wave banks */ - unsigned int soundbanklist; /* [out] Data used to manage lists of wave bank usage */ - unsigned int streaminstance; /* [out] Stream objects and internals */ - unsigned int sounddefclass; /* [out] Sound definition objects */ - unsigned int sounddefdefclass; /* [out] Sound definition static data objects */ - unsigned int sounddefpool; /* [out] Sound definition pool data */ - unsigned int reverbdef; /* [out] Reverb definition objects */ - unsigned int eventreverb; /* [out] Reverb objects */ - unsigned int userproperty; /* [out] User property objects */ - unsigned int eventinstance; /* [out] Event instance base objects */ - unsigned int eventinstance_complex; /* [out] Complex event instance objects */ - unsigned int eventinstance_simple; /* [out] Simple event instance objects */ - unsigned int eventinstance_layer; /* [out] Event layer instance objects */ - unsigned int eventinstance_sound; /* [out] Event sound instance objects */ - unsigned int eventenvelope; /* [out] Event envelope objects */ - unsigned int eventenvelopedef; /* [out] Event envelope definition objects */ - unsigned int eventparameter; /* [out] Event parameter objects */ - unsigned int eventcategory; /* [out] Event category objects */ - unsigned int eventenvelopepoint; /* [out] Event envelope point objects */ - unsigned int eventinstancepool; /* [out] Event instance pool memory */ -} FMOD_MEMORY_USAGE_DETAILS; - - -/* -[DEFINE] -[ - [NAME] - FMOD_MEMBITS - - [DESCRIPTION] - Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Ex class. - Use with the "memorybits" parameter of getMemoryInfo to get information on FMOD Ex memory usage. - - [REMARKS] - Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. - The FMOD_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See System::getMemoryInfo for an example. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_EVENT_MEMBITS - System::getMemoryInfo -] -*/ -#define FMOD_MEMBITS_OTHER 0x00000001 /* Memory not accounted for by other types */ -#define FMOD_MEMBITS_STRING 0x00000002 /* String data */ - -#define FMOD_MEMBITS_SYSTEM 0x00000004 /* System object and various internals */ -#define FMOD_MEMBITS_PLUGINS 0x00000008 /* Plugin objects and internals */ -#define FMOD_MEMBITS_OUTPUT 0x00000010 /* Output module object and internals */ -#define FMOD_MEMBITS_CHANNEL 0x00000020 /* Channel related memory */ -#define FMOD_MEMBITS_CHANNELGROUP 0x00000040 /* ChannelGroup objects and internals */ -#define FMOD_MEMBITS_CODEC 0x00000080 /* Codecs allocated for streaming */ -#define FMOD_MEMBITS_FILE 0x00000100 /* Codecs allocated for streaming */ -#define FMOD_MEMBITS_SOUND 0x00000200 /* Sound objects and internals */ -#define FMOD_MEMBITS_SOUND_SECONDARYRAM 0x00000400 /* Sound data stored in secondary RAM */ -#define FMOD_MEMBITS_SOUNDGROUP 0x00000800 /* SoundGroup objects and internals */ -#define FMOD_MEMBITS_STREAMBUFFER 0x00001000 /* Stream buffer memory */ -#define FMOD_MEMBITS_DSPCONNECTION 0x00002000 /* DSPConnection objects and internals */ -#define FMOD_MEMBITS_DSP 0x00004000 /* DSP implementation objects */ -#define FMOD_MEMBITS_DSPCODEC 0x00008000 /* Realtime file format decoding DSP objects */ -#define FMOD_MEMBITS_PROFILE 0x00010000 /* Profiler memory footprint. */ -#define FMOD_MEMBITS_RECORDBUFFER 0x00020000 /* Buffer used to store recorded data from microphone */ -#define FMOD_MEMBITS_REVERB 0x00040000 /* Reverb implementation objects */ -#define FMOD_MEMBITS_REVERBCHANNELPROPS 0x00080000 /* Reverb channel properties structs */ -#define FMOD_MEMBITS_GEOMETRY 0x00100000 /* Geometry objects and internals */ -#define FMOD_MEMBITS_SYNCPOINT 0x00200000 /* Sync point memory. */ -#define FMOD_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Ex */ -/* [DEFINE_END] */ - - -/* -[DEFINE] -[ - [NAME] - FMOD_EVENT_MEMBITS - - [DESCRIPTION] - Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Event System class. - Use with the "event_memorybits" parameter of getMemoryInfo to get information on FMOD Event System memory usage. - - [REMARKS] - Every public FMOD Event System class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. - The FMOD_EVENT_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See EventSystem::getMemoryInfo for an example. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_MEMBITS - System::getMemoryInfo -] -*/ -#define FMOD_EVENT_MEMBITS_EVENTSYSTEM 0x00000001 /* EventSystem and various internals */ -#define FMOD_EVENT_MEMBITS_MUSICSYSTEM 0x00000002 /* MusicSystem and various internals */ -#define FMOD_EVENT_MEMBITS_FEV 0x00000004 /* Definition of objects contained in all loaded projects e.g. events, groups, categories */ -#define FMOD_EVENT_MEMBITS_MEMORYFSB 0x00000008 /* Data loaded with preloadFSB */ -#define FMOD_EVENT_MEMBITS_EVENTPROJECT 0x00000010 /* EventProject objects and internals */ -#define FMOD_EVENT_MEMBITS_EVENTGROUPI 0x00000020 /* EventGroup objects and internals */ -#define FMOD_EVENT_MEMBITS_SOUNDBANKCLASS 0x00000040 /* Objects used to manage wave banks */ -#define FMOD_EVENT_MEMBITS_SOUNDBANKLIST 0x00000080 /* Data used to manage lists of wave bank usage */ -#define FMOD_EVENT_MEMBITS_STREAMINSTANCE 0x00000100 /* Stream objects and internals */ -#define FMOD_EVENT_MEMBITS_SOUNDDEFCLASS 0x00000200 /* Sound definition objects */ -#define FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS 0x00000400 /* Sound definition static data objects */ -#define FMOD_EVENT_MEMBITS_SOUNDDEFPOOL 0x00000800 /* Sound definition pool data */ -#define FMOD_EVENT_MEMBITS_REVERBDEF 0x00001000 /* Reverb definition objects */ -#define FMOD_EVENT_MEMBITS_EVENTREVERB 0x00002000 /* Reverb objects */ -#define FMOD_EVENT_MEMBITS_USERPROPERTY 0x00004000 /* User property objects */ -#define FMOD_EVENT_MEMBITS_EVENTINSTANCE 0x00008000 /* Event instance base objects */ -#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX 0x00010000 /* Complex event instance objects */ -#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE 0x00020000 /* Simple event instance objects */ -#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER 0x00040000 /* Event layer instance objects */ -#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND 0x00080000 /* Event sound instance objects */ -#define FMOD_EVENT_MEMBITS_EVENTENVELOPE 0x00100000 /* Event envelope objects */ -#define FMOD_EVENT_MEMBITS_EVENTENVELOPEDEF 0x00200000 /* Event envelope definition objects */ -#define FMOD_EVENT_MEMBITS_EVENTPARAMETER 0x00400000 /* Event parameter objects */ -#define FMOD_EVENT_MEMBITS_EVENTCATEGORY 0x00800000 /* Event category objects */ -#define FMOD_EVENT_MEMBITS_EVENTENVELOPEPOINT 0x01000000 /* Event envelope point object+s */ -#define FMOD_EVENT_MEMBITS_EVENTINSTANCEPOOL 0x02000000 /* Event instance pool data */ -#define FMOD_EVENT_MEMBITS_ALL 0xffffffff /* All memory used by FMOD Event System */ - -/* All event instance memory */ -#define FMOD_EVENT_MEMBITS_EVENTINSTANCE_GROUP (FMOD_EVENT_MEMBITS_EVENTINSTANCE | \ - FMOD_EVENT_MEMBITS_EVENTINSTANCE_COMPLEX | \ - FMOD_EVENT_MEMBITS_EVENTINSTANCE_SIMPLE | \ - FMOD_EVENT_MEMBITS_EVENTINSTANCE_LAYER | \ - FMOD_EVENT_MEMBITS_EVENTINSTANCE_SOUND) - -/* All sound definition memory */ -#define FMOD_EVENT_MEMBITS_SOUNDDEF_GROUP (FMOD_EVENT_MEMBITS_SOUNDDEFCLASS | \ - FMOD_EVENT_MEMBITS_SOUNDDEFDEFCLASS | \ - FMOD_EVENT_MEMBITS_SOUNDDEFPOOL) -/* [DEFINE_END] */ - -#endif diff --git a/libs/fmodex/inc/fmod_output.h b/libs/fmodex/inc/fmod_output.h deleted file mode 100644 index 2ffb867bd..000000000 --- a/libs/fmodex/inc/fmod_output.h +++ /dev/null @@ -1,93 +0,0 @@ -/* ==================================================================================================== */ -/* FMOD Ex - output development header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2011. */ -/* */ -/* Use this header if you are wanting to develop your own output plugin to use with */ -/* FMOD's output system. With this header you can make your own output plugin that FMOD */ -/* can register and use. See the documentation and examples on how to make a working plugin. */ -/* */ -/* ==================================================================================================== */ - -#ifndef _FMOD_OUTPUT_H -#define _FMOD_OUTPUT_H - -#include "fmod.h" - -typedef struct FMOD_OUTPUT_STATE FMOD_OUTPUT_STATE; - -/* - Output callbacks -*/ -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETNUMDRIVERSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int *numdrivers); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERNAMECALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, char *name, int namelen); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETDRIVERCAPSCALLBACK)(FMOD_OUTPUT_STATE *output_state, int id, FMOD_CAPS *caps); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_INITCALLBACK) (FMOD_OUTPUT_STATE *output_state, int selecteddriver, FMOD_INITFLAGS flags, int *outputrate, int outputchannels, FMOD_SOUND_FORMAT *outputformat, int dspbufferlength, int dspnumbuffers, void *extradriverdata); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_CLOSECALLBACK) (FMOD_OUTPUT_STATE *output_state); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UPDATECALLBACK) (FMOD_OUTPUT_STATE *output_state); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETHANDLECALLBACK) (FMOD_OUTPUT_STATE *output_state, void **handle); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_GETPOSITIONCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int *pcm); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_LOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, unsigned int offset, unsigned int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_UNLOCKCALLBACK) (FMOD_OUTPUT_STATE *output_state, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); -typedef FMOD_RESULT (F_CALLBACK *FMOD_OUTPUT_READFROMMIXER) (FMOD_OUTPUT_STATE *output_state, void *buffer, unsigned int length); - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - When creating an output, declare one of these and provide the relevant callbacks and name for FMOD to use when it opens and reads a file of this type. - - [REMARKS] - Members marked with [in] mean the variable can be written to. The user can set the value. - Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_OUTPUT_STATE -] -*/ -typedef struct FMOD_OUTPUT_DESCRIPTION -{ - const char *name; /* [in] Name of the output. */ - unsigned int version; /* [in] Plugin writer's version number. */ - int polling; /* [in] If TRUE (non zero), this tells FMOD to start a thread and call getposition / lock / unlock for feeding data. If 0, the output is probably callback based, so all the plugin needs to do is call readfrommixer to the appropriate pointer. */ - FMOD_OUTPUT_GETNUMDRIVERSCALLBACK getnumdrivers; /* [in] For sound device enumeration. This callback is to give System::getNumDrivers somthing to return. */ - FMOD_OUTPUT_GETDRIVERNAMECALLBACK getdrivername; /* [in] For sound device enumeration. This callback is to give System::getDriverName somthing to return. */ - FMOD_OUTPUT_GETDRIVERCAPSCALLBACK getdrivercaps; /* [in] For sound device enumeration. This callback is to give System::getDriverCaps somthing to return. */ - FMOD_OUTPUT_INITCALLBACK init; /* [in] Initialization function for the output device. This is called from System::init. */ - FMOD_OUTPUT_CLOSECALLBACK close; /* [in] Cleanup / close down function for the output device. This is called from System::close. */ - FMOD_OUTPUT_UPDATECALLBACK update; /* [in] Update function that is called once a frame by the user. This is called from System::update. */ - FMOD_OUTPUT_GETHANDLECALLBACK gethandle; /* [in] This is called from System::getOutputHandle. This is just to return a pointer to the internal system device object that the system may be using.*/ - FMOD_OUTPUT_GETPOSITIONCALLBACK getposition; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This returns a position value in samples so that FMOD knows where and when to fill its buffer. */ - FMOD_OUTPUT_LOCKCALLBACK lock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This function provides a pointer to data that FMOD can write to when software mixing. */ - FMOD_OUTPUT_UNLOCKCALLBACK unlock; /* [in] This is called from the FMOD software mixer thread if 'polling' = true. This optional function accepts the data that has been mixed and copies it or does whatever it needs to before sending it to the hardware. */ -} FMOD_OUTPUT_DESCRIPTION; - - -/* -[STRUCTURE] -[ - [DESCRIPTION] - Output plugin structure that is passed into each callback. - - [REMARKS] - Members marked with [in] mean the variable can be written to. The user can set the value. - Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value. - - [PLATFORMS] - Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone, 3GS, NGP, Android - - [SEE_ALSO] - FMOD_OUTPUT_DESCRIPTION -] -*/ -struct FMOD_OUTPUT_STATE -{ - void *plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */ - FMOD_OUTPUT_READFROMMIXER readfrommixer; /* [out] Function to update mixer and write the result to the provided pointer. Used from callback based output only. Polling based output uses lock/unlock/getposition. */ -}; - -#endif - - diff --git a/libs/fmodex/lib/fmodex64_vc.lib b/libs/fmodex/lib/fmodex64_vc.lib deleted file mode 100644 index 77a761d34..000000000 Binary files a/libs/fmodex/lib/fmodex64_vc.lib and /dev/null differ diff --git a/libs/fmodex/lib/fmodexL64_vc.lib b/libs/fmodex/lib/fmodexL64_vc.lib deleted file mode 100644 index 6c008895c..000000000 Binary files a/libs/fmodex/lib/fmodexL64_vc.lib and /dev/null differ diff --git a/libs/fmodex/lib/fmodexL_bc.lib b/libs/fmodex/lib/fmodexL_bc.lib deleted file mode 100644 index 0ae81171b..000000000 Binary files a/libs/fmodex/lib/fmodexL_bc.lib and /dev/null differ diff --git a/libs/fmodex/lib/fmodexL_lcc.lib b/libs/fmodex/lib/fmodexL_lcc.lib deleted file mode 100644 index 0c0e22918..000000000 Binary files a/libs/fmodex/lib/fmodexL_lcc.lib and /dev/null differ diff --git a/libs/fmodex/lib/fmodexL_vc.lib b/libs/fmodex/lib/fmodexL_vc.lib deleted file mode 100644 index 63b6ee4fa..000000000 Binary files a/libs/fmodex/lib/fmodexL_vc.lib and /dev/null differ diff --git a/libs/fmodex/lib/fmodex_bc.lib b/libs/fmodex/lib/fmodex_bc.lib deleted file mode 100644 index 1f5c98ca3..000000000 Binary files a/libs/fmodex/lib/fmodex_bc.lib and /dev/null differ diff --git a/libs/fmodex/lib/fmodex_lcc.lib b/libs/fmodex/lib/fmodex_lcc.lib deleted file mode 100644 index 235fe165c..000000000 Binary files a/libs/fmodex/lib/fmodex_lcc.lib and /dev/null differ diff --git a/libs/fmodex/lib/fmodex_vc.lib b/libs/fmodex/lib/fmodex_vc.lib deleted file mode 100644 index ec169885f..000000000 Binary files a/libs/fmodex/lib/fmodex_vc.lib and /dev/null differ diff --git a/libs/fmodex/lib/libfmodex.a b/libs/fmodex/lib/libfmodex.a deleted file mode 100644 index 6c49195aa..000000000 Binary files a/libs/fmodex/lib/libfmodex.a and /dev/null differ diff --git a/libs/fmodex/lib/libfmodexL.a b/libs/fmodex/lib/libfmodexL.a deleted file mode 100644 index fe253aaf6..000000000 Binary files a/libs/fmodex/lib/libfmodexL.a and /dev/null differ diff --git a/libs/fmodex/lib/which library do I use.txt b/libs/fmodex/lib/which library do I use.txt deleted file mode 100644 index 12738bed0..000000000 --- a/libs/fmodex/lib/which library do I use.txt +++ /dev/null @@ -1,28 +0,0 @@ -Which library do I link? ------------------------- - -If you want to use fmodex.dll: - -Visual Studio users - fmodex_vc.lib. -Metrowerks Codewarrior users - fmodex_vc.lib. -Borland users - fmodex_bc.lib. -LCC-Win32 users - fmodex_lcc.lib. -Dev-C++, MinGW and CygWin users - libfmodex.a. - -If you want to use fmodexL.dll: (same as fmodex.dll but with debug logging enabled) - -Visual Studio users - fmodexL_vc.lib. -Metrowerks Codewarrior users - fmodexL_vc.lib. -Borland users - fmodexL_bc.lib. -LCC-Win32 users - fmodexL_lcc.lib. -Dev-C++, MinGW and CygWin users - libfmodexL.a. - -If you want to use fmodex64.dll: (same as fmodex.dll but for 64bit machines) - -Visual Studio users - fmodex64_vc.lib. - -If you want to use fmodexL64.dll: (same as fmodex64.dll but with debug logging enabled) - -Visual Studio users - fmodexL64_vc.lib. - -No other compilers are supported for 64bit libraries. \ No newline at end of file diff --git a/objs/.gitignore b/objs/.gitignore deleted file mode 100644 index 35ecd6def..000000000 --- a/objs/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -#All folders -SRB2.res -depend.dep -depend.ped -*.o -#VC9 folder only -/VC9/Win32 -/VC9/x64 diff --git a/objs/FreeBSD/SDL/Debug/.gitignore b/objs/FreeBSD/SDL/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/FreeBSD/SDL/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/FreeBSD/SDL/Release/.gitignore b/objs/FreeBSD/SDL/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/FreeBSD/SDL/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Linux/SDL/Debug/.gitignore b/objs/Linux/SDL/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Linux/SDL/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Linux/SDL/Release/.gitignore b/objs/Linux/SDL/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Linux/SDL/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Linux64/SDL/Debug/.gitignore b/objs/Linux64/SDL/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Linux64/SDL/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Linux64/SDL/Release/.gitignore b/objs/Linux64/SDL/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Linux64/SDL/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/MasterClient/.gitignore b/objs/MasterClient/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/MasterClient/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/MasterServer/.gitignore b/objs/MasterServer/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/MasterServer/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw/Debug/.gitignore b/objs/Mingw/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw/Release/.gitignore b/objs/Mingw/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw/SDL/Debug/.gitignore b/objs/Mingw/SDL/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw/SDL/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw/SDL/Release/.gitignore b/objs/Mingw/SDL/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw/SDL/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw64/Debug/.gitignore b/objs/Mingw64/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw64/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw64/Release/.gitignore b/objs/Mingw64/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw64/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw64/SDL/Debug/.gitignore b/objs/Mingw64/SDL/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw64/SDL/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/Mingw64/SDL/Release/.gitignore b/objs/Mingw64/SDL/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/Mingw64/SDL/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/SDL/Release/.gitignore b/objs/SDL/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/SDL/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/VC/.gitignore b/objs/VC/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/VC/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/VC9/.gitignore b/objs/VC9/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/VC9/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/cygwin/Debug/.gitignore b/objs/cygwin/Debug/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/cygwin/Debug/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/cygwin/Release/.gitignore b/objs/cygwin/Release/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/cygwin/Release/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/objs/dummy/.gitignore b/objs/dummy/.gitignore deleted file mode 100644 index 42c6dc2c6..000000000 --- a/objs/dummy/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# DON'T REMOVE -# This keeps the folder from disappearing diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d35e774e9..ae93aac37 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,238 +1,14 @@ # SRB2 Core +add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32) + # Core sources -set(SRB2_CORE_SOURCES - am_map.c - b_bot.c - command.c - comptime.c - console.c - d_clisrv.c - d_main.c - d_net.c - d_netcmd.c - d_netfil.c - dehacked.c - deh_soc.c - deh_lua.c - deh_tables.c - f_finale.c - f_wipe.c - filesrch.c - g_demo.c - g_game.c - g_input.c - hu_stuff.c - i_tcp.c - info.c - lzf.c - m_aatree.c - m_anigif.c - m_argv.c - m_bbox.c - m_cheat.c - m_cond.c - m_fixed.c - m_menu.c - m_misc.c - m_perfstats.c - m_queue.c - m_random.c - md5.c - mserv.c - http-mserv.c - s_sound.c - screen.c - sounds.c - st_stuff.c - #string.c - tables.c - v_video.c - w_wad.c - y_inter.c - z_zone.c -) +target_sourcefile(c) +target_sources(SRB2SDL2 PRIVATE comptime.c md5.c config.h.in) -set(SRB2_CORE_HEADERS - am_map.h - b_bot.h - byteptr.h - command.h - console.h - d_clisrv.h - d_event.h - d_main.h - d_net.h - d_netcmd.h - d_netfil.h - d_player.h - d_think.h - d_ticcmd.h - dehacked.h - deh_soc.h - deh_lua.h - deh_tables.h - doomdata.h - doomdef.h - doomstat.h - doomtype.h - endian.h - f_finale.h - fastcmp.h - filesrch.h - g_demo.h - g_game.h - g_input.h - g_state.h - hu_stuff.h - i_joy.h - i_net.h - i_sound.h - i_system.h - i_tcp.h - i_video.h - info.h - keys.h - lzf.h - m_aatree.h - m_anigif.h - m_argv.h - m_bbox.h - m_cheat.h - m_cond.h - m_dllist.h - m_fixed.h - m_menu.h - m_misc.h - m_perfstats.h - m_queue.h - m_random.h - m_swap.h - md5.h - mserv.h - p5prof.h - s_sound.h - screen.h - sounds.h - st_stuff.h - tables.h - v_video.h - w_wad.h - y_inter.h - z_zone.h - - config.h.in -) - -set(SRB2_CORE_RENDER_SOURCES - r_bsp.c - r_data.c - r_draw.c - r_main.c - r_plane.c - r_segs.c - r_skins.c - r_sky.c - r_splats.c - r_things.c - r_textures.c - r_patch.c - r_patchrotation.c - r_picformats.c - r_portal.c - - r_bsp.h - r_data.h - r_defs.h - r_draw.h - r_local.h - r_main.h - r_plane.h - r_segs.h - r_skins.h - r_sky.h - r_splats.h - r_state.h - r_things.h - r_textures.h - r_patch.h - r_patchrotation.h - r_picformats.h - r_portal.h -) - -set(SRB2_CORE_GAME_SOURCES - p_ceilng.c - p_enemy.c - p_floor.c - p_inter.c - p_lights.c - p_map.c - p_maputl.c - p_mobj.c - p_polyobj.c - p_saveg.c - p_setup.c - p_sight.c - p_slopes.c - p_spec.c - p_telept.c - p_tick.c - p_user.c - taglist.c - - p_local.h - p_maputl.h - p_mobj.h - p_polyobj.h - p_pspr.h - p_saveg.h - p_setup.h - p_slopes.h - p_spec.h - p_tick.h - taglist.h -) - -if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(SRB2_CORE_SOURCES ${SRB2_CORE_SOURCES} string.c) -endif() - -prepend_sources(SRB2_CORE_SOURCES) -prepend_sources(SRB2_CORE_HEADERS) -prepend_sources(SRB2_CORE_RENDER_SOURCES) -prepend_sources(SRB2_CORE_GAME_SOURCES) - -set(SRB2_CORE_HEADERS ${SRB2_CORE_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/config.h) -source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS}) -source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES}) -source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES}) - - -set(SRB2_ASM_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/vid_copy.s -) - -set(SRB2_NASM_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/tmap_mmx.nas - ${CMAKE_CURRENT_SOURCE_DIR}/tmap.nas -) - -if(MSVC) - list(APPEND SRB2_NASM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tmap_vc.nas) -endif() - -set(SRB2_NASM_OBJECTS - ${CMAKE_CURRENT_BINARY_DIR}/tmap_mmx.obj - ${CMAKE_CURRENT_BINARY_DIR}/tmap.obj -) - -if(MSVC) - list(APPEND SRB2_NASM_OBJECTS ${CMAKE_CURRENT_BINARY_DIR}/tmap_vc.obj) -endif() - -source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES}) +set(SRB2_ASM_SOURCES vid_copy.s) +set(SRB2_NASM_SOURCES tmap_mmx.nas tmap.nas) ### Configuration set(SRB2_CONFIG_HAVE_PNG ON CACHE BOOL @@ -268,91 +44,7 @@ if(${CMAKE_SYSTEM} MATCHES "Windows") ###set on Windows only "Use SRB2's internal copies of required dependencies (SDL2, PNG, zlib, GME, OpenMPT).") endif() -set(SRB2_LUA_SOURCES - lua_baselib.c - lua_blockmaplib.c - lua_consolelib.c - lua_hooklib.c - lua_hudlib.c - lua_infolib.c - lua_maplib.c - lua_mathlib.c - lua_mobjlib.c - lua_playerlib.c - lua_polyobjlib.c - lua_script.c - lua_skinlib.c - lua_thinkerlib.c -) -set(SRB2_LUA_HEADERS - lua_hook.h - lua_hud.h - lua_libs.h - lua_script.h -) - -prepend_sources(SRB2_LUA_SOURCES) -prepend_sources(SRB2_LUA_HEADERS) - -source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS}) - -set(SRB2_BLUA_SOURCES - blua/lapi.c - blua/lauxlib.c - blua/lbaselib.c - blua/lcode.c - blua/ldebug.c - blua/ldo.c - blua/ldump.c - blua/lfunc.c - blua/lgc.c - blua/linit.c - blua/liolib.c - blua/llex.c - blua/lmem.c - blua/lobject.c - blua/lopcodes.c - blua/lparser.c - blua/lstate.c - blua/lstring.c - blua/lstrlib.c - blua/ltable.c - blua/ltablib.c - blua/ltm.c - blua/lundump.c - blua/lvm.c - blua/lzio.c -) -set(SRB2_BLUA_HEADERS - blua/lapi.h - blua/lauxlib.h - blua/lcode.h - blua/ldebug.h - blua/ldo.h - blua/lfunc.h - blua/lgc.h - blua/llex.h - blua/llimits.h - blua/lmem.h - blua/lobject.h - blua/lopcodes.h - blua/lparser.h - blua/lstate.h - blua/lstring.h - blua/ltable.h - blua/ltm.h - blua/lua.h - blua/luaconf.h - blua/lualib.h - blua/lundump.h - blua/lvm.h - blua/lzio.h -) - -prepend_sources(SRB2_BLUA_SOURCES) -prepend_sources(SRB2_BLUA_HEADERS) - -source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS}) +add_subdirectory(blua) if(${SRB2_CONFIG_HAVE_GME}) if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES}) @@ -368,7 +60,7 @@ if(${SRB2_CONFIG_HAVE_GME}) endif() if(${GME_FOUND}) set(SRB2_HAVE_GME ON) - add_definitions(-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() @@ -388,7 +80,7 @@ if(${SRB2_CONFIG_HAVE_OPENMPT}) endif() if(${OPENMPT_FOUND}) set(SRB2_HAVE_OPENMPT ON) - add_definitions(-DHAVE_OPENMPT) + target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_OPENMPT) else() message(WARNING "You have specified that OpenMPT is available but it was not found.") endif() @@ -411,8 +103,7 @@ if(${SRB2_CONFIG_HAVE_MIXERX}) endif() if(${MIXERX_FOUND}) set(SRB2_HAVE_MIXERX ON) - set(SRB2_SDL2_SOUNDIMPL mixer_sound.c) - add_definitions(-DHAVE_MIXERX) + target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXERX) else() message(WARNING "You have specified that SDL Mixer X is available but it was not found.") endif() @@ -432,7 +123,7 @@ if(${SRB2_CONFIG_HAVE_ZLIB}) endif() if(${ZLIB_FOUND}) set(SRB2_HAVE_ZLIB ON) - add_definitions(-DHAVE_ZLIB) + target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_ZLIB) else() message(WARNING "You have specified that ZLIB is available but it was not found. SRB2 may not compile correctly.") endif() @@ -453,14 +144,9 @@ if(${SRB2_CONFIG_HAVE_PNG} AND ${SRB2_CONFIG_HAVE_ZLIB}) endif() if(${PNG_FOUND}) set(SRB2_HAVE_PNG ON) - add_definitions(-DHAVE_PNG) - add_definitions(-D_LARGEFILE64_SOURCE) - set(SRB2_PNG_SOURCES apng.c) - set(SRB2_PNG_HEADERS apng.h) - prepend_sources(SRB2_PNG_SOURCES) - prepend_sources(SRB2_PNG_HEADERS) - source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} - ${SRB2_PNG_SOURCES} ${SRB2_PNG_HEADERS}) + target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_PNG) + target_compile_definitions(SRB2SDL2 PRIVATE -D_LARGEFILE64_SOURCE) + target_sources(SRB2SDL2 PRIVATE apng.c) else() message(WARNING "You have specified that PNG is available but it was not found. SRB2 may not compile correctly.") endif() @@ -481,7 +167,7 @@ if(${SRB2_CONFIG_HAVE_CURL}) endif() if(${CURL_FOUND}) set(SRB2_HAVE_CURL ON) - add_definitions(-DHAVE_CURL) + target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_CURL) else() message(WARNING "You have specified that CURL is available but it was not found. SRB2 may not compile correctly.") endif() @@ -489,59 +175,19 @@ endif() if(${SRB2_CONFIG_HAVE_THREADS}) set(SRB2_HAVE_THREADS ON) - set(SRB2_CORE_HEADERS ${SRB2_CORE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/i_threads.h) - add_definitions(-DHAVE_THREADS) + target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_THREADS) endif() if(${SRB2_CONFIG_HWRENDER}) - add_definitions(-DHWRENDER) - set(SRB2_HWRENDER_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_batching.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_bsp.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_cache.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_draw.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.c - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.c - ) - - set (SRB2_HWRENDER_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_batching.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_clip.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_data.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_defs.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_dll.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_drv.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_glob.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2load.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md3load.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_model.h - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/u_list.h - ) - - set(SRB2_R_OPENGL_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/r_opengl/r_opengl.c - ) - - set(SRB2_R_OPENGL_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/hardware/r_opengl/r_opengl.h - ) - + target_compile_definitions(SRB2SDL2 PRIVATE -DHWRENDER) + add_subdirectory(hardware) endif() if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL}) find_package(OpenGL) if(${OPENGL_FOUND}) - add_definitions(-DHWRENDER) - add_definitions(-DSTATIC_OPENGL) + target_compile_definitions(SRB2SDL2 PRIVATE -DHWRENDER) + target_compile_definitions(SRB2SDL2 PRIVATE -DSTATIC_OPENGL) else() message(WARNING "You have specified static opengl but opengl was not found. Not setting HWRENDER.") endif() @@ -562,12 +208,16 @@ if(${SRB2_CONFIG_USEASM}) set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.") enable_language(ASM_NASM) endif() + set(SRB2_USEASM ON) - add_definitions(-DUSEASM) + target_compile_definitions(SRB2SDL2 PRIVATE -DUSEASM) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse3 -mfpmath=sse") + + target_sources(SRB2SDL2 PRIVATE ${SRB2_ASM_SOURCES} + ${SRB2_NASM_SOURCES}) else() set(SRB2_USEASM OFF) - add_definitions(-DNONX86 -DNORUSEASM) + target_compile_definitions(SRB2SDL2 PRIVATE -DNONX86 -DNORUSEASM) endif() # Targets @@ -603,7 +253,9 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -Wno-absolute-value) endif() -add_definitions(-DCMAKECONFIG) +set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -Wno-trigraphs) + +target_compile_definitions(SRB2SDL2 PRIVATE -DCMAKECONFIG) #add_library(SRB2Core STATIC # ${SRB2_CORE_SOURCES} diff --git a/src/Makefile b/src/Makefile index 1314161bd..c1aa35742 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,787 +1,416 @@ - -# GNU Make makefile for SRB2 -############################################################################# -# Copyright (C) 1998-2000 by DooM Legacy Team. -# Copyright (C) 2003-2020 by Sonic Team Junior. +# GNU Makefile for SRB2 +# the poly3 Makefile adapted over and over... +# +# Copyright 1998-2000 DooM Legacy Team. +# Copyright 2020-2022 James R. +# Copyright 2003-2022 Sonic Team Junior. # # This program is free software distributed under the # terms of the GNU General Public License, version 2. # See the 'LICENSE' file for more details. # -# -DLINUX -> use for the GNU/Linux specific -# -D_WINDOWS -> use for the Win32/DirectX specific -# -DHAVE_SDL -> use for the SDL interface +# Special targets: # -# Sets: -# Compile the SDL/Mingw version with 'make MINGW=1' -# Compile the SDL/Linux version with 'make LINUX=1' -# Compile the SDL/Solaris version with 'make SOLARIS=1' -# Compile the SDL/FreeBSD version with 'gmake FREEBSD=1' -# Compile the SDL/Cygwin version with 'make CYGWIN32=1' -# Compile the SDL/other version try with 'make SDL=1' +# clean - remove executables and objects for this build +# cleandep - remove dependency files for this build +# distclean - remove entire executable, object and +# dependency file directory structure. +# dump - disassemble executable +# info - print settings # -# 'Targets': -# clean -# Remove all object files -# cleandep -# Remove depend.dep -# dll -# compile primary HW render DLL/SO -# all_dll -# compile all HW render and 3D sound DLLs for the set -# opengl_dll -# Pure Mingw only, compile OpenGL HW render DLL -# ds3d_dll -# Pure Mingw only, compile DirectX DirectSound HW sound DLL -# fmod_dll -# Pure Mingw only, compile FMOD HW sound DLL -# openal_dll -# Pure Mingw only, compile OpenAL HW sound DLL -# fmod_so -# Non-Mingw, compile FMOD HW sound SO -# openal_so -# Non-Mingw, compile OpenAL HW sound SO +# This Makefile can automatically detect the host system +# as well as the compiler version. If system or compiler +# version cannot be detected, you may need to set a flag +# manually. # +# On Windows machines, 32-bit Windows is always targetted. # -# Addon: -# To Cross-Compile, CC=gcc-version make * PREFIX= -# Compile with GCC 2.97 version, add 'GCC29=1' -# Compile with GCC 4.0x version, add 'GCC40=1' -# Compile with GCC 4.1x version, add 'GCC41=1' -# Compile with GCC 4.2x version, add 'GCC42=1' -# Compile with GCC 4.3x version, add 'GCC43=1' -# Compile with GCC 4.4x version, add 'GCC44=1' -# Compile with GCC 4.5x version, add 'GCC45=1' -# Compile with GCC 4.6x version, add 'GCC46=1' -# Compile a profile version, add 'PROFILEMODE=1' -# Compile a debug version, add 'DEBUGMODE=1' -# Compile with less warnings, add 'RELAXWARNINGS=1' -# Generate compiler errors for most compiler warnings, add 'ERRORMODE=1' -# Compile without NASM's tmap.nas, add 'NOASM=1' -# Compile without 3D hardware support, add 'NOHW=1' -# Compile with GDBstubs, add 'RDB=1' -# Compile without PNG, add 'NOPNG=1' -# Compile without zlib, add 'NOZLIB=1' +# Platform/system flags: # -# Addon for SDL: -# To Cross-Compile, add 'SDL_CONFIG=/usr/*/bin/sdl-config' -# Compile without SDL_Mixer, add 'NOMIXER=1' -# Compile without SDL_Mixer_X, add 'NOMIXERX=1' (Win32 only) -# Compile without GME, add 'NOGME=1' -# Compile without BSD API, add 'NONET=1' -# Compile without IPX/SPX, add 'NOIPX=1' -# Compile Mingw/SDL with S_DS3S, add 'DS3D=1' -# Compile without libopenmpt, add 'NOOPENMPT=1' -# Compile with S_FMOD3D, add 'FMOD=1' (WIP) -# Compile with S_OPENAL, add 'OPENAL=1' (WIP) -# To link with the whole SDL_Image lib to load Icons, add 'SDL_IMAGE=1' but it isn't not realy needed -# To link with SDLMain to hide console or make on a console-less binary, add 'SDLMAIN=1' +# LINUX=1, LINUX64=1 +# MINGW=1, MINGW64=1 - Windows (MinGW toolchain) +# UNIX=1 - Generic Unix like system +# FREEBSD=1 +# SDL=1 - Use SDL backend. SDL is the only backend though +# and thus, always enabled. # -############################################################################# +# A list of supported GCC versions can be found in +# Makefile.d/detect.mk -- search 'gcc_versions'. +# +# Feature flags: +# +# Safe to use online +# ------------------ +# NO_IPV6=1 - Disable IPv6 address support. +# NOHW=1 - Disable OpenGL renderer. +# ZDEBUG=1 - Enable more detailed memory debugging +# HAVE_MINIUPNPC=1 - Enable automated port forwarding. +# Already enabled by default for 32-bit +# Windows. +# NOASM=1 - Disable hand optimized assembly code for the +# Software renderer. +# NOPNG=1 - Disable PNG graphics support. (TODO: double +# check netplay compatible.) +# NOCURL=1 - Disable libcurl--HTTP capability. +# NOGME=1 - Disable game music emu, retro VGM support. +# NOOPENMPT=1 - Disable module (tracker) music support. +# NOMIXER=1 - Disable SDL Mixer (audio playback). +# NOMIXERX=1 - Forgo SDL Mixer X--revert to standard SDL +# Mixer. Mixer X is the default for Windows +# builds. +# HAVE_MIXERX=1 - Enable SDL Mixer X. Outside of Windows +# builds, SDL Mixer X is not the default. +# NOTHREADS=1 - Disable multithreading. +# +# Netplay incompatible +# -------------------- +# NONET=1 - Disable online capability. +# NOMD5=1 - Disable MD5 checksum (validation tool). +# NOPOSTPROCESSING=1 - ? +# MOBJCONSISTANCY=1 - ?? +# PACKETDROP=1 - ?? +# DEBUGMODE=1 - Enable various debugging capabilities. +# Also disables optimizations. +# NOZLIB=1 - Disable some compression capability. Implies +# NOPNG=1. +# +# Development flags: +# +# VALGRIND=1 - Enable Valgrind memory debugging support. +# PROFILEMODE=1 - Enable performance profiling (gprof). +# +# General flags for building: +# +# STATIC=1 - Use static linking. +# DISTCC=1 +# CCACHE=1 +# UPX= - UPX command to use for compressing final +# executable. +# WINDOWSHELL=1 - Use Windows commands. +# PREFIX= - Prefix to many commands, for cross compiling. +# YASM=1 - Use Yasm instead of NASM assembler. +# STABS=1 - ? +# ECHO=1 - Print out each command in the build process. +# NOECHOFILENAMES=1 - Don't print out each that is being +# worked on. +# SILENT=1 - Print absolutely nothing except errors. +# RELAXWARNINGS=1 - Use less compiler warnings/errors. +# ERRORMODE=1 - Treat most compiler warnings as errors. +# NOCASTALIGNWARN=1 - ? +# NOLDWARNING=1 - ? +# NOSDLMAIN=1 - ? +# SDLMAIN=1 - ? +# +# Library configuration flags: +# Everything here is an override. +# +# PNG_PKGCONFIG= - libpng-config command. +# PNG_CFLAGS=, PNG_LDFLAGS= +# +# CURLCONFIG= - curl-config command. +# CURL_CFLAGS=, CURL_LDFLAGS= +# +# VALGRIND_PKGCONFIG= - pkg-config package name. +# VALGRIND_CFLAGS=, VALGRIND_LDFLAGS= +# +# LIBGME_PKGCONFIG=, LIBGME_CFLAGS=, LIBGME_LDFLAGS= -ALL_SYSTEMS=\ - PANDORA\ - LINUX64\ - MINGW64\ - HAIKU\ - DUMMY\ - DJGPPDOS\ - MINGW\ - UNIX\ - LINUX\ - SOLARIS\ - FREEBSD\ - MACOSX\ - SDL\ +# LIBOPENMPT_PKGCONFIG= +# LIBOPENMPT_CFLAGS=, LIBOPENMPT_LDFLAGS= +# +# ZLIB_PKGCONFIG=, ZLIB_CFLAGS=, ZLIB_LDFLAGS= +# +# SDL_PKGCONFIG= +# SDL_CONFIG= - sdl-config command. +# SDL_CFLAGS=, SDL_LDFLAGS= -# check for user specified system -ifeq (,$(filter $(ALL_SYSTEMS),$(.VARIABLES))) -ifeq ($(OS),Windows_NT) # all windows are Windows_NT... +clean_targets=cleandep clean distclean info - $(info Detected a Windows system, compiling for 32-bit MinGW SDL2...) +.PHONY : $(clean_targets) all - # go for a 32-bit sdl mingw exe by default - MINGW=1 - WINDOWSHELL=1 +goals:=$(or $(MAKECMDGOALS),all) +cleanonly:=$(filter $(clean_targets),$(goals)) +destructive:=$(filter-out info,$(cleanonly)) -else # if you on the *nix - - system:=$(shell uname -s) - - ifeq ($(system),Linux) - new_system=LINUX - else - - $(error \ - Could not automatically detect your system,\ - try specifying a system manually) - - endif - - ifeq ($(shell getconf LONG_BIT),64) - system+=64-bit - new_system:=$(new_system)64 - endif - - $(info Detected $(system) ($(new_system))...) - $(new_system)=1 - -endif +ifndef cleanonly +include Makefile.d/old.mk endif +include Makefile.d/util.mk -# SRB2 data files -D_DIR?=../bin/Resources -D_FILES=$(D_DIR)/srb2.pk3 \ - $(D_DIR)/player.dta \ - $(D_DIR)/zones.pk3 \ - $(D_DIR)/music.dta \ - -PKG_CONFIG?=pkg-config - -ifdef PANDORA -LINUX=1 -endif - -ifdef LINUX64 -LINUX=1 -NONX86=1 -# LINUX64 does not imply X86_64=1; could mean ARM64 or Itanium -endif - -ifdef MINGW64 -MINGW=1 -NONX86=1 -NOASM=1 -# MINGW64 should not necessarily imply X86_64=1, but we make that assumption elsewhere -# Once that changes, remove this -X86_64=1 -endif #ifdef MINGW64 - -ifdef HAIKU -SDL=1 -endif - -include Makefile.cfg - -ifdef DUMMY -NOPNG=1 -NOZLIB=1 -NONET=1 -NOHW=1 -NOASM=1 -NOIPX=1 -EXENAME?=srb2dummy -OBJS=$(OBJDIR)/i_video.o -LIBS=-lm -endif - -ifdef HAIKU -NOIPX=1 -NOASM=1 -ifndef NONET -LIBS=-lnetwork -endif -CFLAGS+=-DUNIXCOMMON -PNG_CFLAGS?= -PNG_LDFLAGS?=-lpng -endif - -ifdef PANDORA -NONX86=1 -NOHW=1 -endif - -ifndef NOOPENMPT -HAVE_OPENMPT=1 -endif - -ifdef MINGW -include win32/Makefile.cfg -endif #ifdef MINGW - -ifdef UNIX -UNIXCOMMON=1 -endif - -ifdef LINUX -UNIXCOMMON=1 -ifndef NOGME -HAVE_LIBGME=1 -endif -endif - -ifdef SOLARIS -UNIXCOMMON=1 -endif - -ifdef FREEBSD -UNIXCOMMON=1 -endif - -ifdef MACOSX -UNIXCOMMON=1 -endif - -ifdef SDL - include sdl/Makefile.cfg -endif #ifdef SDL - -ifdef DISTCC - CC:=distcc $(CC) -endif - -ifdef CCACHE - CC:=ccache $(CC) -endif - -MSGFMT?=msgfmt - -ifndef ECHO - NASM:=@$(NASM) - REMOVE:=@$(REMOVE) - CC:=@$(CC) - CXX:=@$(CXX) - OBJCOPY:=@$(OBJCOPY) - OBJDUMP:=@$(OBJDUMP) - STRIP:=@$(STRIP) - WINDRES:=@$(WINDRES) - MKDIR:=@$(MKDIR) - GZIP:=@$(GZIP) - MSGFMT:=@$(MSGFMT) - UPX:=@$(UPX) - UPX_OPTS+=-q -endif - -ifdef NONET - OPTS+=-DNONET - NOCURL=1 -else -ifdef NO_IPV6 - OPTS+=-DNO_IPV6 -endif -endif - -ifdef NOHW - OPTS+=-DNOHW -else - OPTS+=-DHWRENDER - OBJS+=$(OBJDIR)/hw_bsp.o $(OBJDIR)/hw_draw.o $(OBJDIR)/hw_light.o \ - $(OBJDIR)/hw_main.o $(OBJDIR)/hw_clip.o $(OBJDIR)/hw_md2.o $(OBJDIR)/hw_cache.o \ - $(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o -endif - -OPTS += -DCOMPVERSION - -ifndef NONX86 -ifndef GCC29 - ARCHOPTS?=-msse3 -mfpmath=sse -else - ARCHOPTS?=-mpentium -endif -else -ifdef X86_64 - ARCHOPTS?=-march=nocona -endif -endif - -ifndef NOASM -ifndef NONX86 - OBJS+=$(OBJDIR)/tmap.o $(OBJDIR)/tmap_mmx.o - OPTS+=-DUSEASM -endif -endif - -ifndef NOPNG -OPTS+=-DHAVE_PNG - -ifdef PNG_PKGCONFIG -PNG_CFLAGS?=$(shell $(PKG_CONFIG) $(PNG_PKGCONFIG) --cflags) -PNG_LDFLAGS?=$(shell $(PKG_CONFIG) $(PNG_PKGCONFIG) --libs) -else ifdef PREFIX -PNG_CONFIG?=$(PREFIX)-libpng-config +CC:=$(PREFIX)-gcc +endif + +OBJDUMP_OPTS?=--wide --source --line-numbers + +OBJCOPY:=$(call Prefix,objcopy) +OBJDUMP:=$(call Prefix,objdump) +WINDRES:=$(call Prefix,windres) + +ifdef YASM +NASM?=yasm else -PNG_CONFIG?=libpng-config +NASM?=nasm endif -ifdef PNG_STATIC -PNG_CFLAGS?=$(shell $(PNG_CONFIG) --static --cflags) -PNG_LDFLAGS?=$(shell $(PNG_CONFIG) --static --ldflags) -else -PNG_CFLAGS?=$(shell $(PNG_CONFIG) --cflags) -PNG_LDFLAGS?=$(shell $(PNG_CONFIG) --ldflags) -endif -endif - -ifdef LINUX -PNG_CFLAGS+=-D_LARGEFILE64_SOURCE -endif - -LIBS+=$(PNG_LDFLAGS) -CFLAGS+=$(PNG_CFLAGS) - -OBJS+=$(OBJDIR)/apng.o -endif - -ifdef HAVE_LIBGME -OPTS+=-DHAVE_LIBGME - -LIBGME_PKGCONFIG?=libgme -LIBGME_CFLAGS?=$(shell $(PKG_CONFIG) $(LIBGME_PKGCONFIG) --cflags) -LIBGME_LDFLAGS?=$(shell $(PKG_CONFIG) $(LIBGME_PKGCONFIG) --libs) - -LIBS+=$(LIBGME_LDFLAGS) -CFLAGS+=$(LIBGME_CFLAGS) -endif - -ifdef HAVE_OPENMPT -OPTS+=-DHAVE_OPENMPT - -LIBOPENMPT_PKGCONFIG?=libopenmpt -LIBOPENMPT_CFLAGS?=$(shell $(PKG_CONFIG) $(LIBOPENMPT_PKGCONFIG) --cflags) -LIBOPENMPT_LDFLAGS?=$(shell $(PKG_CONFIG) $(LIBOPENMPT_PKGCONFIG) --libs) - -LIBS+=$(LIBOPENMPT_LDFLAGS) -CFLAGS+=$(LIBOPENMPT_CFLAGS) -endif - -ifndef NOZLIB -OPTS+=-DHAVE_ZLIB -ZLIB_PKGCONFIG?=zlib -ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags) -ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs) - -LIBS+=$(ZLIB_LDFLAGS) -CFLAGS+=$(ZLIB_CFLAGS) -else -NOPNG=1 -endif - -ifndef NOCURL -OPTS+=-DHAVE_CURL -CURLCONFIG?=curl-config -CURL_CFLAGS?=$(shell $(CURLCONFIG) --cflags) -CURL_LDFLAGS?=$(shell $(CURLCONFIG) --libs) - -LIBS+=$(CURL_LDFLAGS) -CFLAGS+=$(CURL_CFLAGS) -endif - -ifdef STATIC -LIBS:=-static $(LIBS) -endif - -ifdef HAVE_MINIUPNPC -ifdef NONET -HAVE_MINIUPNPC='' -else -LIBS+=-lminiupnpc -ifdef MINGW -LIBS+=-lws2_32 -liphlpapi -endif -CFLAGS+=-DHAVE_MINIUPNPC -endif -endif - -include blua/Makefile.cfg - -ifdef NOMD5 - OPTS+=-DNOMD5 -else - OBJS:=$(OBJDIR)/md5.o $(OBJS) -endif - -ifdef NOPOSTPROCESSING - OPTS+=-DNOPOSTPROCESSING -endif - - OPTS:=-fno-exceptions $(OPTS) - -ifdef MOBJCONSISTANCY - OPTS+=-DMOBJCONSISTANCY -endif - -ifdef PACKETDROP - OPTS+=-DPACKETDROP -endif - -ifdef DEBUGMODE - - # build with debugging information - WINDRESFLAGS = -D_DEBUG -ifdef GCC48 - CFLAGS+=-Og -else - CFLAGS+=-O0 -endif - CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY -else - - - # build a normal optimised version - WINDRESFLAGS = -DNDEBUG - CFLAGS+=-O3 -endif - CFLAGS+=-g $(OPTS) $(ARCHOPTS) $(WINDRESFLAGS) - ifdef YASM ifdef STABS - NASMOPTS?= -g stabs +NASMOPTS?=-g stabs else - NASMOPTS?= -g dwarf2 +NASMOPTS?=-g dwarf2 endif else - NASMOPTS?= -g +NASMOPTS?=-g endif -ifdef PROFILEMODE - # build with profiling information - CFLAGS+=-pg - LDFLAGS+=-pg +GZIP?=gzip +GZIP_OPTS?=-9 -f -n +ifdef WINDOWSHELL +GZIP_OPTS+=--rsyncable endif -ifdef ZDEBUG - CPPFLAGS+=-DZDEBUG +UPX_OPTS?=--best --preserve-build-id +ifndef ECHO +UPX_OPTS+=-qq endif -OPTS+=$(CPPFLAGS) +include Makefile.d/detect.mk -# default EXENAME if all else fails +# make would try to remove the implicitly made directories +.PRECIOUS : %/ comptime.c + +sources:= +makedir:=../make + +# -DCOMPVERSION: flag to use comptime.h +opts:=-DCOMPVERSION -g +libs:= + +nasm_format:= + +# This is a list of variables names, of which if defined, +# also defines the name as a macro to the compiler. +passthru_opts:= + +include Makefile.d/platform.mk +include Makefile.d/features.mk +include Makefile.d/versions.mk + +ifdef DEBUGMODE +makedir:=$(makedir)/debug +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))) + +depends:=$(depends:%=$(depdir)/%.d) + +# comptime.o added directly to objects instead of thru +# sources because comptime.c includes comptime.h, but +# comptime.h may not exist yet. It's a headache so this is +# easier. +objects:=$(objects:=.o) comptime.o + +# windows resource file +rc_file:=$(basename $(filter %.rc,$(sources))) +ifdef rc_file +objects+=$(rc_file:=.res) +endif + +objects:=$(addprefix $(objdir)/,$(objects)) + +ifdef DEBUGMODE +bin:=../bin/debug +else +bin:=../bin +endif + +# default EXENAME (usually set by platform) EXENAME?=srb2 DBGNAME?=$(EXENAME).debug -# $(OBJDIR)/dstrings.o \ +exe:=$(bin)/$(EXENAME) +dbg:=$(bin)/$(DBGNAME) -# not too sophisticated dependency -OBJS:=$(i_main_o) \ - $(OBJDIR)/comptime.o \ - $(OBJDIR)/string.o \ - $(OBJDIR)/d_main.o \ - $(OBJDIR)/d_clisrv.o \ - $(OBJDIR)/d_net.o \ - $(OBJDIR)/d_netfil.o \ - $(OBJDIR)/d_netcmd.o \ - $(OBJDIR)/dehacked.o \ - $(OBJDIR)/deh_soc.o \ - $(OBJDIR)/deh_lua.o \ - $(OBJDIR)/deh_tables.o \ - $(OBJDIR)/z_zone.o \ - $(OBJDIR)/f_finale.o \ - $(OBJDIR)/f_wipe.o \ - $(OBJDIR)/g_demo.o \ - $(OBJDIR)/g_game.o \ - $(OBJDIR)/g_input.o \ - $(OBJDIR)/am_map.o \ - $(OBJDIR)/command.o \ - $(OBJDIR)/console.o \ - $(OBJDIR)/hu_stuff.o \ - $(OBJDIR)/y_inter.o \ - $(OBJDIR)/st_stuff.o \ - $(OBJDIR)/m_aatree.o \ - $(OBJDIR)/m_anigif.o \ - $(OBJDIR)/m_argv.o \ - $(OBJDIR)/m_bbox.o \ - $(OBJDIR)/m_cheat.o \ - $(OBJDIR)/m_cond.o \ - $(OBJDIR)/m_fixed.o \ - $(OBJDIR)/m_menu.o \ - $(OBJDIR)/m_misc.o \ - $(OBJDIR)/m_perfstats.o \ - $(OBJDIR)/m_random.o \ - $(OBJDIR)/m_queue.o \ - $(OBJDIR)/info.o \ - $(OBJDIR)/p_ceilng.o \ - $(OBJDIR)/p_enemy.o \ - $(OBJDIR)/p_floor.o \ - $(OBJDIR)/p_inter.o \ - $(OBJDIR)/p_lights.o \ - $(OBJDIR)/p_map.o \ - $(OBJDIR)/p_maputl.o \ - $(OBJDIR)/p_mobj.o \ - $(OBJDIR)/p_polyobj.o\ - $(OBJDIR)/p_saveg.o \ - $(OBJDIR)/p_setup.o \ - $(OBJDIR)/p_sight.o \ - $(OBJDIR)/p_spec.o \ - $(OBJDIR)/p_telept.o \ - $(OBJDIR)/p_tick.o \ - $(OBJDIR)/p_user.o \ - $(OBJDIR)/p_slopes.o \ - $(OBJDIR)/tables.o \ - $(OBJDIR)/r_bsp.o \ - $(OBJDIR)/r_data.o \ - $(OBJDIR)/r_draw.o \ - $(OBJDIR)/r_main.o \ - $(OBJDIR)/r_plane.o \ - $(OBJDIR)/r_segs.o \ - $(OBJDIR)/r_skins.o \ - $(OBJDIR)/r_sky.o \ - $(OBJDIR)/r_splats.o \ - $(OBJDIR)/r_things.o \ - $(OBJDIR)/r_textures.o \ - $(OBJDIR)/r_patch.o \ - $(OBJDIR)/r_patchrotation.o \ - $(OBJDIR)/r_picformats.o \ - $(OBJDIR)/r_portal.o \ - $(OBJDIR)/screen.o \ - $(OBJDIR)/taglist.o \ - $(OBJDIR)/v_video.o \ - $(OBJDIR)/s_sound.o \ - $(OBJDIR)/sounds.o \ - $(OBJDIR)/w_wad.o \ - $(OBJDIR)/filesrch.o \ - $(OBJDIR)/mserv.o \ - $(OBJDIR)/http-mserv.o\ - $(OBJDIR)/i_tcp.o \ - $(OBJDIR)/lzf.o \ - $(OBJDIR)/vid_copy.o \ - $(OBJDIR)/b_bot.o \ - $(i_net_o) \ - $(i_system_o) \ - $(i_sound_o) \ - $(OBJS) +build_done==== Build is done, look for \ + $( srb2.s - $(REMOVE) $(OBJDIR)/tmp.exe - -# executable -# NOTE: DJGPP's objcopy do not have --add-gnu-debuglink - -$(BIN)/$(EXENAME): $(POS) $(OBJS) - -$(MKDIR) $(BIN) - @echo Linking $(EXENAME)... - $(LD) $(LDFLAGS) $(OBJS) -o $(BIN)/$(EXENAME) $(LIBS) ifndef VALGRIND -ifndef NOOBJDUMP - @echo Dumping debugging info - $(OBJDUMP) $(OBJDUMP_OPTS) $(BIN)/$(EXENAME) > $(BIN)/$(DBGNAME).txt +dump : $(dbg).txt +endif + +ifdef STATIC +libs+=-static +endif + +# build with profiling information +ifdef PROFILEMODE +opts+=-pg +libs+=-pg +endif + +ifdef DEBUGMODE +debug_opts=-D_DEBUG +else # build a normal optimized version +debug_opts=-DNDEBUG +opts+=-O3 +endif + +# debug_opts also get passed to windres +opts+=$(debug_opts) + +opts+=$(foreach v,$(passthru_opts),$(if $($(v)),-D$(v))) + +opts+=$(WFLAGS) $(CPPFLAGS) $(CFLAGS) +libs+=$(LDFLAGS) +asflags:=$(ASFLAGS) -x assembler-with-cpp + +cc=$(CC) + +ifdef DISTCC +cc=distcc $(CC) +endif + +ifdef CCACHE +cc=ccache $(CC) +endif + +ifndef SILENT +# makefile will 'restart' when it finishes including the +# dependencies. +ifndef MAKE_RESTARTS +ifndef destructive +$(shell $(CC) -v) +define flags = + +SHELL ..... $(SHELL) + +CC ........ $(cc) + +CFLAGS .... $(opts) + +LDFLAGS ... $(libs) + +endef +$(info $(flags)) +endif +# don't generate dependency files if only cleaning +ifndef cleanonly +$(info Checking dependency files...) +include $(depends) +endif +endif +endif + +LD:=$(CC) +cc:=$(cc) $(opts) +nasm=$(NASM) $(NASMOPTS) -f $(nasm_format) +ifdef UPX +upx=$(UPX) $(UPX_OPTS) +endif +windres=$(WINDRES) $(WINDRESFLAGS)\ + $(debug_opts) --include-dir=win32 -O coff + +%/ : + $(.)$(mkdir) $(call Windows_path,$@) + +# this is needed so the target can be referenced in the +# prerequisites +.SECONDEXPANSION : + +# 'UPX' is also recognized in the environment by upx +unexport UPX + +# executable stripped of debugging symbols +$(exe) : $(dbg) | $$(@D)/ + $(.)$(OBJCOPY) --strip-debug $< $@ + $(.)-$(OBJCOPY) --add-gnu-debuglink=$< $@ +ifdef UPX + $(call Echo,Compressing final executable...) + $(.)-$(upx) $@ +endif + +# original executable with debugging symbols +$(dbg) : $(objects) | $$(@D)/ + $(call Echo,Linking $(@F)...) + $(.)$(LD) -o $@ $^ $(libs) + +# disassembly of executable +$(dbg).txt : $(dbg) + $(call Echo,Dumping debugging info...) + $(.)$(OBJDUMP) $(OBJDUMP_OPTS) $< > $@ + $(.)$(GZIP) $(GZIP_OPTS) $@ + +# '::' means run unconditionally +# this really updates comptime.h +comptime.c :: ifdef WINDOWSHELL - -$(GZIP) $(GZIP_OPTS) $(BIN)/$(DBGNAME).txt + $(.)..\comptime.bat . else - -$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt -endif + $(.)../comptime.sh . endif -# mac os x lsdlsrb2 does not like objcopy -ifndef MACOSX - $(OBJCOPY) $(BIN)/$(EXENAME) $(BIN)/$(DBGNAME) - $(OBJCOPY) --strip-debug $(BIN)/$(EXENAME) - -$(OBJCOPY) --add-gnu-debuglink=$(BIN)/$(DBGNAME) $(BIN)/$(EXENAME) -endif -ifndef NOUPX - -$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME) -endif -endif - @echo Build is done, please look for $(EXENAME) in $(BIN), \(checking for post steps\) +# I wish I could make dependencies out of rc files :( +$(objdir)/win32/Srb2win.res : \ + win32/afxres.h win32/resource.h -reobjdump: - @echo Redumping debugging info - $(OBJDUMP) $(OBJDUMP_OPTS) $(BIN)/$(DBGNAME) > $(BIN)/$(DBGNAME).txt +# dependency recipe template +# 1: source file suffix +# 2: extra flags to gcc +define _recipe = +$(depdir)/%.d : %.$(1) | $$$$(@D)/ +ifndef WINDOWSHELL +ifdef Echo_name + @printf '%-20.20s\r' $$< +endif +endif + $(.)$(cc) -MM -MF $$@ -MT $(objdir)/$$*.o $(2) $$< +endef + +$(eval $(call _recipe,c)) +$(eval $(call _recipe,s,$(asflags))) + +# compiling recipe template +# 1: target file suffix +# 2: source file suffix +# 3: compile command +define _recipe = +$(objdir)/%.$(1) : %.$(2) | $$$$(@D)/ + $(call Echo_name,$$<) + $(.)$(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 $$@)) + +_rm=$(.)$(rmrf) $(call Windows_path,$(1)) + +cleandep : + $(call _rm,$(depends) comptime.h) + +clean : + $(call _rm,$(exe) $(dbg) $(dbg).txt $(objects)) + +distclean : + $(call _rm,../bin ../objs ../dep ../make comptime.h) + +info: ifdef WINDOWSHELL - -$(GZIP) $(GZIP_OPTS) $(BIN)/$(DBGNAME).txt + @REM else - -$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt + @: endif - -$(OBJDIR): - -$(MKDIR) $(OBJDIR) - -ifdef SDL -ifdef MINGW -$(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ - doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ - command.h hardware/hw_data.h hardware/hw_defs.h \ - hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \ - hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ - am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ - p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ -else -$(OBJDIR)/r_opengl.o: hardware/r_opengl/r_opengl.c hardware/r_opengl/r_opengl.h \ - doomdef.h doomtype.h g_state.h m_swap.h hardware/hw_drv.h screen.h \ - command.h hardware/hw_data.h hardware/hw_defs.h \ - hardware/hw_md2.h hardware/hw_glob.h hardware/hw_main.h hardware/hw_clip.h \ - hardware/hw_md2load.h hardware/hw_md3load.h hardware/hw_model.h hardware/u_list.h \ - am_map.h d_event.h d_player.h p_pspr.h m_fixed.h tables.h info.h d_think.h \ - p_mobj.h doomdata.h d_ticcmd.h r_defs.h hardware/hw_dll.h - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -I/usr/X11R6/include -c $< -o $@ -endif -endif - -#dependecy made by gcc itself ! -$(OBJS): -ifndef DUMMY --include $(OBJDIR)/depend.dep -endif - -$(OBJDIR)/depend.dep: - @echo "Creating dependency file, depend.dep" - @echo > comptime.h - -$(MKDIR) $(OBJDIR) - $(CC) $(CFLAGS) -MM *.c > $(OBJDIR)/depend.ped - $(CC) $(CFLAGS) -MM $(INTERFACE)/*.c >> $(OBJDIR)/depend.ped -ifndef NOHW - $(CC) $(CFLAGS) -MM hardware/*.c >> $(OBJDIR)/depend.ped -endif - $(CC) $(CFLAGS) -MM blua/*.c >> $(OBJDIR)/depend.ped - @sed -e 's,\(.*\)\.o: ,$(subst /,\/,$(OBJDIR))\/&,g' < $(OBJDIR)/depend.ped > $(OBJDIR)/depend.dep - $(REMOVE) $(OBJDIR)/depend.ped - @echo "Created dependency file, depend.dep" - -ifdef VALGRIND -$(OBJDIR)/z_zone.o: z_zone.c - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -DHAVE_VALGRIND $(VALGRIND_CFLAGS) -c $< -o $@ -endif - -$(OBJDIR)/comptime.o: comptime.c pre-build - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ - -$(BIN)/%.mo: locale/%.po - -$(MKDIR) $(BIN) - $(echoName) - $(MSGFMT) -f -o $@ $< - -$(OBJDIR)/%.o: %.c - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ - -$(OBJDIR)/%.o: $(INTERFACE)/%.c - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ - -ifdef MACOSX -$(OBJDIR)/%.o: sdl/macosx/%.c - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ -endif - -$(OBJDIR)/%.o: hardware/%.c - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ - -$(OBJDIR)/%.o: blua/%.c - $(echoName) - $(CC) $(CFLAGS) $(LUA_CFLAGS) $(WFLAGS) -c $< -o $@ - -$(OBJDIR)/%.o: %.nas - $(echoName) - $(NASM) $(NASMOPTS) -o $@ -f $(NASMFORMAT) $< - -$(OBJDIR)/vid_copy.o: vid_copy.s asm_defs.inc - $(echoName) - $(CC) $(OPTS) $(ASFLAGS) -x assembler-with-cpp -c $< -o $@ - -$(OBJDIR)/%.o: %.s - $(echoName) - $(CC) $(OPTS) -x assembler-with-cpp -c $< -o $@ - -$(OBJDIR)/SRB2.res: win32/Srb2win.rc win32/afxres.h win32/resource.h - $(echoName) - $(WINDRES) -i $< -O rc $(WINDRESFLAGS) --include-dir=win32 -o $@ -O coff - - -ifdef SDL - -ifdef MINGW -$(OBJDIR)/win_dbg.o: win32/win_dbg.c - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ -endif - -ifdef STATICHS -$(OBJDIR)/s_openal.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \ - hardware/hw_dll.h - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ - -$(OBJDIR)/s_fmod.o: hardware/s_fmod/s_fmod.c hardware/hw3dsdrv.h \ - hardware/hw_dll.h - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ - -ifdef MINGW -$(OBJDIR)/s_ds3d.o: hardware/s_ds3d/s_ds3d.c hardware/hw3dsdrv.h \ - hardware/hw_dll.h - $(echoName) - $(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@ -endif -else - -$(OBJDIR)/s_fmod.o: hardware/s_fmod/s_fmod.c hardware/hw3dsdrv.h \ - hardware/hw_dll.h - $(echoName) - $(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_fmod.o -DHW3SOUND -DUNIXCOMMON -shared -nostartfiles -c hardware/s_fmod/s_fmod.c - -$(OBJDIR)/s_openal.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \ - hardware/hw_dll.h - $(echoName) - $(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_openal.o -DHW3SOUND -DUNIXCOMMON -shared -nostartfiles -c hardware/s_openal/s_openal.c -endif -endif - -############################################################# -# -############################################################# diff --git a/src/Makefile.cfg b/src/Makefile.cfg deleted file mode 100644 index f081eacdf..000000000 --- a/src/Makefile.cfg +++ /dev/null @@ -1,462 +0,0 @@ -# vim: ft=make -# -# Makefile.cfg for SRB2 -# - -# -# GNU compiler & tools' flags -# and other things -# - -# See the following variable don't start with 'GCC'. This is -# to avoid a false positive with the version detection... - -SUPPORTED_GCC_VERSIONS:=\ - 101 102\ - 91 92 93\ - 81 82 83 84\ - 71 72 73 74 75\ - 61 62 63 64\ - 51 52 53 54 55\ - 40 41 42 43 44 45 46 47 48 49 - -LATEST_GCC_VERSION=10.2 - -# gcc or g++ -ifdef PREFIX - CC=$(PREFIX)-gcc - CXX=$(PREFIX)-g++ - OBJCOPY=$(PREFIX)-objcopy - OBJDUMP=$(PREFIX)-objdump - STRIP=$(PREFIX)-strip - WINDRES=$(PREFIX)-windres -else - OBJCOPY=objcopy - OBJDUMP=objdump - STRIP=strip - WINDRES=windres -endif - -# because Apple screws with us on this -# need to get bintools from homebrew -ifdef MACOSX - CC=clang - CXX=clang - OBJCOPY=gobjcopy - OBJDUMP=gobjdump -endif - -# Automatically set version flag, but not if one was manually set -ifeq (,$(filter GCC%,$(.VARIABLES))) - version:=$(shell $(CC) --version) - # check if this is in fact GCC - ifneq (,$(or $(findstring gcc,$(version)),$(findstring GCC,$(version)))) - version:=$(shell $(CC) -dumpversion) - - # Turn version into words of major, minor - v:=$(subst ., ,$(version)) - # concat. major minor - v:=$(word 1,$(v))$(word 2,$(v)) - - # If this version is not in the list, default to the latest supported - ifeq (,$(filter $(v),$(SUPPORTED_GCC_VERSIONS))) - $(info\ - Your compiler version, GCC $(version), is not supported by the Makefile.\ - The Makefile will assume GCC $(LATEST_GCC_VERSION).) - GCC$(subst .,,$(LATEST_GCC_VERSION))=1 - else - $(info Detected GCC $(version) (GCC$(v))) - GCC$(v)=1 - endif - endif -endif - -ifdef GCC102 -GCC101=1 -endif - -ifdef GCC101 -GCC93=1 -endif - -ifdef GCC93 -GCC92=1 -endif - -ifdef GCC92 -GCC91=1 -endif - -ifdef GCC91 -GCC84=1 -endif - -ifdef GCC84 -GCC83=1 -endif - -ifdef GCC83 -GCC82=1 -endif - -ifdef GCC82 -GCC81=1 -endif - -ifdef GCC81 -GCC75=1 -endif - -ifdef GCC75 -GCC74=1 -endif - -ifdef GCC74 -GCC73=1 -endif - -ifdef GCC73 -GCC72=1 -endif - -ifdef GCC72 -GCC71=1 -endif - -ifdef GCC71 -GCC64=1 -endif - -ifdef GCC64 -GCC63=1 -endif - -ifdef GCC63 -GCC62=1 -endif - -ifdef GCC62 -GCC61=1 -endif - -ifdef GCC61 -GCC55=1 -endif - -ifdef GCC55 -GCC54=1 -endif - -ifdef GCC54 -GCC53=1 -endif - -ifdef GCC53 -GCC52=1 -endif - -ifdef GCC52 -GCC51=1 -endif - -ifdef GCC51 -GCC49=1 -endif - -ifdef GCC49 -GCC48=1 -endif - -ifdef GCC48 -GCC47=1 -endif - -ifdef GCC47 -GCC46=1 -endif - -ifdef GCC46 -GCC45=1 -endif - -ifdef GCC45 -GCC44=1 -endif - -ifdef GCC44 -GCC43=1 -endif - -ifdef GCC43 -GCC42=1 -endif - -ifdef GCC42 -GCC41=1 -endif - -ifdef GCC41 -GCC40=1 -VCHELP=1 -endif - -ifdef GCC295 -GCC29=1 -endif - -OLDWFLAGS:=$(WFLAGS) -# -W -Wno-unused -WFLAGS=-Wall -ifndef GCC295 -#WFLAGS+=-Wno-packed -endif -ifndef RELAXWARNINGS - WFLAGS+=-W -#WFLAGS+=-Wno-sign-compare -ifndef GCC295 - WFLAGS+=-Wno-div-by-zero -endif -#WFLAGS+=-Wsystem-headers -WFLAGS+=-Wfloat-equal -#WFLAGS+=-Wtraditional -ifdef VCHELP - WFLAGS+=-Wdeclaration-after-statement - WFLAGS+=-Wno-error=declaration-after-statement -endif - WFLAGS+=-Wundef -ifndef GCC295 - WFLAGS+=-Wendif-labels -endif -ifdef GCC41 - WFLAGS+=-Wshadow -endif -#WFLAGS+=-Wlarger-than-%len% - WFLAGS+=-Wpointer-arith -Wbad-function-cast -ifdef GCC45 -#WFLAGS+=-Wc++-compat -endif - WFLAGS+=-Wcast-qual -ifndef NOCASTALIGNWARN - WFLAGS+=-Wcast-align -endif - WFLAGS+=-Wwrite-strings -ifndef ERRORMODE -#WFLAGS+=-Wconversion -ifdef GCC43 - #WFLAGS+=-Wno-sign-conversion -endif -endif - WFLAGS+=-Wsign-compare -ifdef GCC91 - WFLAGS+=-Wno-error=address-of-packed-member -endif -ifdef GCC45 - WFLAGS+=-Wlogical-op -endif - WFLAGS+=-Waggregate-return -ifdef HAIKU -ifdef GCC41 - #WFLAGS+=-Wno-attributes -endif -endif -#WFLAGS+=-Wstrict-prototypes -ifdef GCC40 - WFLAGS+=-Wold-style-definition -endif - WFLAGS+=-Wmissing-prototypes -Wmissing-declarations -ifdef GCC40 - WFLAGS+=-Wmissing-field-initializers -endif - WFLAGS+=-Wmissing-noreturn -#WFLAGS+=-Wmissing-format-attribute -#WFLAGS+=-Wno-multichar -#WFLAGS+=-Wno-deprecated-declarations -#WFLAGS+=-Wpacked -#WFLAGS+=-Wpadded -#WFLAGS+=-Wredundant-decls - WFLAGS+=-Wnested-externs -#WFLAGS+=-Wunreachable-code - WFLAGS+=-Winline -ifdef GCC43 - WFLAGS+=-funit-at-a-time - WFLAGS+=-Wlogical-op -endif -ifndef GCC295 - WFLAGS+=-Wdisabled-optimization -endif -endif -WFLAGS+=-Wformat-y2k -ifdef GCC71 -WFLAGS+=-Wno-error=format-overflow=2 -endif -WFLAGS+=-Wformat-security -ifndef GCC29 -#WFLAGS+=-Winit-self -endif -ifdef GCC46 -WFLAGS+=-Wno-suggest-attribute=noreturn -endif - -ifdef NOLDWARNING -LDFLAGS+=-Wl,--as-needed -endif - -ifdef ERRORMODE -WFLAGS+=-Werror -endif - -WFLAGS+=$(OLDWFLAGS) - -ifdef GCC43 - #WFLAGS+=-Wno-error=clobbered -endif -ifdef GCC44 - WFLAGS+=-Wno-error=array-bounds -endif -ifdef GCC46 - WFLAGS+=-Wno-error=suggest-attribute=noreturn -endif -ifdef GCC54 - WFLAGS+=-Wno-logical-op -Wno-error=logical-op -endif -ifdef GCC61 - WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare -endif -ifdef GCC71 - WFLAGS+=-Wimplicit-fallthrough=4 -endif -ifdef GCC81 - WFLAGS+=-Wno-error=format-overflow - WFLAGS+=-Wno-error=stringop-truncation - WFLAGS+=-Wno-error=stringop-overflow - WFLAGS+=-Wno-format-overflow - WFLAGS+=-Wno-stringop-truncation - WFLAGS+=-Wno-stringop-overflow - WFLAGS+=-Wno-error=multistatement-macros -endif - - -#indicate platform and what interface use with -ifndef LINUX -ifndef FREEBSD -ifndef CYGWIN32 -ifndef MINGW -ifndef MINGW64 -ifndef SDL -ifndef DUMMY -$(error No interface or platform flag defined) -endif -endif -endif -endif -endif -endif -endif - -#determine the interface directory (where you put all i_*.c) -i_net_o=$(OBJDIR)/i_net.o -i_system_o=$(OBJDIR)/i_system.o -i_sound_o=$(OBJDIR)/i_sound.o -i_main_o=$(OBJDIR)/i_main.o -#set OBJDIR and BIN's starting place -OBJDIR=../objs -BIN=../bin -#Nasm ASM and rm -ifdef YASM -NASM?=yasm -else -NASM?=nasm -endif -REMOVE?=rm -f -MKDIR?=mkdir -p -GZIP?=gzip -GZIP_OPTS?=-9 -f -n -GZIP_OPT2=$(GZIP_OPTS) --rsyncable -UPX?=upx -UPX_OPTS?=--best --preserve-build-id -ifndef ECHO -UPX_OPTS+=-q -endif - -#Interface Setup -ifdef DUMMY - INTERFACE=dummy - OBJDIR:=$(OBJDIR)/dummy - BIN:=$(BIN)/dummy -else -ifdef LINUX - NASMFORMAT=elf -DLINUX - SDL=1 -ifdef LINUX64 - OBJDIR:=$(OBJDIR)/Linux64 - BIN:=$(BIN)/Linux64 -else - OBJDIR:=$(OBJDIR)/Linux - BIN:=$(BIN)/Linux -endif -else -ifdef FREEBSD - INTERFACE=sdl - NASMFORMAT=elf -DLINUX - SDL=1 - - OBJDIR:=$(OBJDIR)/FreeBSD - BIN:=$(BIN)/FreeBSD -else -ifdef SOLARIS - INTERFACE=sdl - NASMFORMAT=elf -DLINUX - SDL=1 - - OBJDIR:=$(OBJDIR)/Solaris - BIN:=$(BIN)/Solaris -else -ifdef CYGWIN32 - INTERFACE=sdl - NASMFORMAT=win32 - SDL=1 - - OBJDIR:=$(OBJDIR)/cygwin - BIN:=$(BIN)/Cygwin -else -ifdef MINGW64 - #NASMFORMAT=win64 - SDL=1 - OBJDIR:=$(OBJDIR)/Mingw64 - BIN:=$(BIN)/Mingw64 -else -ifdef MINGW - NASMFORMAT=win32 - SDL=1 - OBJDIR:=$(OBJDIR)/Mingw - BIN:=$(BIN)/Mingw -endif -endif -endif -endif -endif -endif -endif - -ifdef ARCHNAME - OBJDIR:=$(OBJDIR)/$(ARCHNAME) - BIN:=$(BIN)/$(ARCHNAME) -endif - -OBJDUMP_OPTS?=--wide --source --line-numbers -LD=$(CC) - -ifdef SDL - INTERFACE=sdl - OBJDIR:=$(OBJDIR)/SDL -endif - -ifndef DUMMY -ifdef DEBUGMODE - OBJDIR:=$(OBJDIR)/Debug - BIN:=$(BIN)/Debug -else - OBJDIR:=$(OBJDIR)/Release - BIN:=$(BIN)/Release -endif -endif diff --git a/src/Makefile.d/detect.mk b/src/Makefile.d/detect.mk new file mode 100644 index 000000000..f458b044c --- /dev/null +++ b/src/Makefile.d/detect.mk @@ -0,0 +1,107 @@ +# +# Detect the host system and compiler version. +# + +# Previously featured:\ + PANDORA\ + HAIKU\ + DUMMY\ + DJGPPDOS\ + SOLARIS\ + MACOSX\ + +all_systems:=\ + LINUX64\ + MINGW64\ + MINGW\ + UNIX\ + LINUX\ + FREEBSD\ + SDL\ + +# check for user specified system +ifeq (,$(filter $(all_systems),$(.VARIABLES))) +ifeq ($(OS),Windows_NT) # all windows are Windows_NT... + +_m=Detected a Windows system,\ + compiling for 32-bit MinGW SDL...) +$(call Print,$(_m)) + +# go for a 32-bit sdl mingw exe by default +MINGW:=1 + +else # if you on the *nix + +system:=$(shell uname -s) + +ifeq ($(system),Linux) +new_system:=LINUX +else + +$(error \ + Could not automatically detect your system,\ + try specifying a system manually) + +endif + +ifeq ($(shell getconf LONG_BIT),64) +system+=64-bit +new_system:=$(new_system)64 +endif + +$(call Print,Detected $(system) ($(new_system))...) +$(new_system):=1 + +endif +endif + +# This must have high to low order. +gcc_versions:=\ + 102 101\ + 93 92 91\ + 84 83 82 81\ + 75 74 73 72 71\ + 64 63 62 61\ + 55 54 53 52 51\ + 49 48 47 46 45 44 43 42 41 40 + +latest_gcc_version:=10.2 + +# Automatically set version flag, but not if one was +# manually set. And don't bother if this is a clean only +# run. +ifeq (,$(call Wildvar,GCC% destructive)) + +# 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 (,$(findstring gcc version,$(version))) + +# 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)) +# concat. major minor +v:=$(word 1,$(v))$(word 2,$(v)) + +# If this version is not in the list, +# default to the latest supported +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). +endef +$(call Print,$(line)) +GCC$(subst .,,$(latest_gcc_version)):=1 +else +$(call Print,Detected GCC $(version) (GCC$(v))) +GCC$(v):=1 +endif + +endif +endif diff --git a/src/Makefile.d/features.mk b/src/Makefile.d/features.mk new file mode 100644 index 000000000..8ba33383b --- /dev/null +++ b/src/Makefile.d/features.mk @@ -0,0 +1,75 @@ +# +# Makefile for feature flags. +# + +passthru_opts+=\ + NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ + MOBJCONSISTANCY PACKETDROP ZDEBUG\ + HAVE_MINIUPNPC\ + +# build with debugging information +ifdef DEBUGMODE +PACKETDROP=1 +opts+=-DPARANOIA -DRANGECHECK +endif + +ifndef NOHW +opts+=-DHWRENDER +sources+=$(call List,hardware/Sourcefile) +endif + +ifndef NOASM +ifndef NONX86 +sources+=tmap.nas tmap_mmx.nas +opts+=-DUSEASM +endif +endif + +ifndef NOMD5 +sources+=md5.c +endif + +ifndef NOZLIB +ifndef NOPNG +ifdef PNG_PKGCONFIG +$(eval $(call Use_pkg_config,PNG_PKGCONFIG)) +else +PNG_CONFIG?=$(call Prefix,libpng-config) +$(eval $(call Configure,PNG,$(PNG_CONFIG) \ + $(if $(PNG_STATIC),--static),,--ldflags)) +endif +ifdef LINUX +opts+=-D_LARGEFILE64_SOURCE +endif +opts+=-DHAVE_PNG +sources+=apng.c +endif +endif + +ifndef NONET +ifndef NOCURL +CURLCONFIG?=curl-config +$(eval $(call Configure,CURL,$(CURLCONFIG))) +opts+=-DHAVE_CURL +endif +endif + +ifdef HAVE_MINIUPNPC +libs+=-lminiupnpc +endif + +# (Valgrind is a memory debugger.) +ifdef VALGRIND +VALGRIND_PKGCONFIG?=valgrind +$(eval $(call Use_pkg_config,VALGRIND)) +ZDEBUG=1 +opts+=-DHAVE_VALGRIND +endif + +default_packages:=\ + GME/libgme/LIBGME\ + OPENMPT/libopenmpt/LIBOPENMPT\ + ZLIB/zlib\ + +$(foreach p,$(default_packages),\ + $(eval $(call Check_pkg_config,$(p)))) diff --git a/src/Makefile.d/nix.mk b/src/Makefile.d/nix.mk new file mode 100644 index 000000000..6642a6bcc --- /dev/null +++ b/src/Makefile.d/nix.mk @@ -0,0 +1,42 @@ +# +# Makefile options for unices (linux, bsd...) +# + +EXENAME?=lsdl2srb2 + +opts+=-DUNIXCOMMON -DLUA_USE_POSIX +# Use -rdynamic so a backtrace log shows function names +# instead of addresses +libs+=-lm -rdynamic + +ifndef nasm_format +nasm_format:=elf -DLINUX +endif + +ifndef NOHW +opts+=-I/usr/X11R6/include +libs+=-L/usr/X11R6/lib +endif + +SDL=1 + +# In common usage. +ifdef LINUX +libs+=-lrt +passthru_opts+=NOTERMIOS +endif + +# Tested by Steel, as of release 2.2.8. +ifdef FREEBSD +opts+=-I/usr/X11R6/include -DLINUX -DFREEBSD +libs+=-L/usr/X11R6/lib -lipx -lkvm +endif + +# FIXME: UNTESTED +#ifdef SOLARIS +#NOIPX=1 +#NOASM=1 +#opts+=-I/usr/local/include -I/opt/sfw/include \ +# -DSOLARIS -DINADDR_NONE=INADDR_ANY -DBSD_COMP +#libs+=-L/opt/sfw/lib -lsocket -lnsl +#endif 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 new file mode 100644 index 000000000..fad4be191 --- /dev/null +++ b/src/Makefile.d/platform.mk @@ -0,0 +1,69 @@ +# +# Platform specific options. +# + +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 +LINUX=1 +endif + +ifdef MINGW64 +MINGW=1 +endif + +ifdef LINUX +UNIX=1 +ifdef LINUX64 +NONX86=1 +# LINUX64 does not imply X86_64=1; +# could mean ARM64 or Itanium +platform=linux/64 +else +platform=linux +endif +else ifdef FREEBSD +UNIX=1 +platform=freebsd +else ifdef SOLARIS # FIXME: UNTESTED +UNIX=1 +platform=solaris +else ifdef CYGWIN32 # FIXME: UNTESTED +nasm_format=win32 +platform=cygwin +else ifdef MINGW +ifdef MINGW64 +NONX86=1 +NOASM=1 +# MINGW64 should not necessarily imply X86_64=1, +# but we make that assumption elsewhere +# Once that changes, remove this +X86_64=1 +platform=mingw/64 +else +platform=mingw +endif +include Makefile.d/win32.mk +endif + +ifdef platform +makedir:=$(makedir)/$(platform) +endif + +ifdef UNIX +include Makefile.d/nix.mk +endif + +ifdef SDL +include Makefile.d/sdl.mk +endif diff --git a/src/Makefile.d/sdl.mk b/src/Makefile.d/sdl.mk new file mode 100644 index 000000000..99ca624e6 --- /dev/null +++ b/src/Makefile.d/sdl.mk @@ -0,0 +1,79 @@ +# +# Makefile options for SDL2 backend. +# + +# +# SDL...., *looks at Alam*, THIS IS A MESS! +# +# ...a little bird flexes its muscles... +# + +makedir:=$(makedir)/SDL + +sources+=$(call List,sdl/Sourcefile) +opts+=-DDIRECTFULLSCREEN -DHAVE_SDL + +# FIXME: UNTESTED +#ifdef PANDORA +#include sdl/SRB2Pandora/Makefile.cfg +#endif #ifdef PANDORA + +# FIXME: UNTESTED +#ifdef CYGWIN32 +#include sdl/MakeCYG.cfg +#endif #ifdef CYGWIN32 + +ifndef NOHW +sources+=sdl/ogl_sdl.c +endif + +ifdef NOMIXER +sources+=sdl/sdl_sound.c +else +opts+=-DHAVE_MIXER +sources+=sdl/mixer_sound.c + + ifdef HAVE_MIXERX + opts+=-DHAVE_MIXERX + libs+=-lSDL2_mixer_ext + else + libs+=-lSDL2_mixer + endif +endif + +ifndef NOTHREADS +opts+=-DHAVE_THREADS +sources+=sdl/i_threads.c +endif + +ifdef SDL_PKGCONFIG +$(eval $(call Use_pkg_config,SDL)) +else +SDL_CONFIG?=$(call Prefix,sdl2-config) +SDL_CFLAGS?=$(shell $(SDL_CONFIG) --cflags) +SDL_LDFLAGS?=$(shell $(SDL_CONFIG) \ + $(if $(STATIC),--static-libs,--libs)) +$(eval $(call Propogate_flags,SDL)) +endif + +# use the x86 asm code +ifndef CYGWIN32 +ifndef NOASM +USEASM=1 +endif +endif + +ifdef MINGW +ifndef NOSDLMAIN +SDLMAIN=1 +endif +endif + +ifdef SDLMAIN +opts+=-DSDLMAIN +else +ifdef MINGW +opts+=-Umain +libs+=-mconsole +endif +endif diff --git a/src/Makefile.d/util.mk b/src/Makefile.d/util.mk new file mode 100644 index 000000000..bda68df13 --- /dev/null +++ b/src/Makefile.d/util.mk @@ -0,0 +1,93 @@ +# +# Utility macros for the rest of the Makefiles. +# + +Ifnot=$(if $(1),$(3),$(2)) +Ifndef=$(call Ifnot,$($(1)),$(2),$(3)) + +# Match and expand a list of variables by pattern. +Wildvar=$(foreach v,$(filter $(1),$(.VARIABLES)),$($(v))) + +# Read a list of words from file and prepend each with the +# directory of the file. +_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)) + +define Propogate_flags = +opts+=$$($(1)_CFLAGS) +libs+=$$($(1)_LDFLAGS) +endef + +# Set library's _CFLAGS and _LDFLAGS from some command. +# Automatically propogates the flags too. +# 1: variable prefix (e.g. CURL) +# 2: start of command (e.g. curl-config) +# --- optional ---- +# 3: CFLAGS command arguments, default '--cflags' +# 4: LDFLAGS command arguments, default '--libs' +# 5: common command arguments at the end of command +define Configure = +$(1)_CFLAGS?=$$(shell $(2) $(or $(3),--cflags) $(5)) +$(1)_LDFLAGS?=$$(shell $(2) $(or $(4),--libs) $(5)) +$(call Propogate_flags,$(1)) +endef + +# Configure library with pkg-config. The package name is +# taken from a _PKGCONFIG variable. +# 1: variable prefix +# +# LIBGME_PKGCONFIG=libgme +# $(eval $(call Use_pkg_config,LIBGME)) +define Use_pkg_config = +$(call Configure,$(1),$(PKG_CONFIG),,,$($(1)_PKGCONFIG)) +endef + +# Check disabling flag and configure package in one step +# according to delimited argument. +# (There is only one argument, but it split by slash.) +# 1/: short form library name (uppercase). This is +# prefixed with 'NO' and 'HAVE_'. E.g. NOGME, HAVE_GME +# /2: package name (e.g. libgme) +# /3: variable prefix +# +# The following example would check if NOGME is not +# defined before attempting to define LIBGME_CFLAGS and +# LIBGME_LDFLAGS as with Use_pkg_config. +# +# $(eval $(call Check_pkg_config,GME/libgme/LIBGME)) +define Check_pkg_config = +_p:=$(subst /, ,$(1)) +_v1:=$$(word 1,$$(_p)) +_v2:=$$(or $$(word 3,$$(_p)),$$(_v1)) +ifndef NO$$(_v1) +$$(_v2)_PKGCONFIG?=$$(word 2,$$(_p)) +$$(eval $$(call Use_pkg_config,$$(_v2))) +opts+=-DHAVE_$$(_v1) +endif +endef + +# $(call Prefix,gcc) +Prefix=$(if $(PREFIX),$(PREFIX)-)$(1) + +Echo= +Echo_name= +Print= + +ifndef SILENT +Echo=@echo $(1) +ifndef ECHO +ifndef NOECHOFILENAMES +Echo_name=$(call Echo,-- $(1) ...) +endif +endif +ifndef MAKE_RESTARTS +ifndef destructive +Print=$(info $(1)) +endif +endif +endif + +.=$(call Ifndef,ECHO,@) diff --git a/src/Makefile.d/versions.mk b/src/Makefile.d/versions.mk new file mode 100644 index 000000000..f0b59658e --- /dev/null +++ b/src/Makefile.d/versions.mk @@ -0,0 +1,175 @@ +# +# Flags to put a sock in GCC! +# + +# See the versions list in detect.mk +# This will define all version flags going backward. +# Yes, it's magic. +define _predecessor = +ifdef GCC$(firstword $(1)) +GCC$(lastword $(1)):=1 +endif +endef +_n:=$(words $(gcc_versions)) +$(foreach v,$(join $(wordlist 2,$(_n),- $(gcc_versions)),\ + $(addprefix =,$(wordlist 2,$(_n),$(gcc_versions)))),\ + $(and $(findstring =,$(v)),\ + $(eval $(call _predecessor,$(subst =, ,$(v)))))) + +# -W -Wno-unused +WFLAGS:=-Wall -Wno-trigraphs +ifndef GCC295 +#WFLAGS+=-Wno-packed +endif +ifndef RELAXWARNINGS + WFLAGS+=-W +#WFLAGS+=-Wno-sign-compare +ifndef GCC295 + WFLAGS+=-Wno-div-by-zero +endif +#WFLAGS+=-Wsystem-headers +WFLAGS+=-Wfloat-equal +#WFLAGS+=-Wtraditional + WFLAGS+=-Wundef +ifndef GCC295 + WFLAGS+=-Wendif-labels +endif +ifdef GCC41 + WFLAGS+=-Wshadow +endif +#WFLAGS+=-Wlarger-than-%len% + WFLAGS+=-Wpointer-arith -Wbad-function-cast +ifdef GCC45 +#WFLAGS+=-Wc++-compat +endif + WFLAGS+=-Wcast-qual +ifndef NOCASTALIGNWARN + WFLAGS+=-Wcast-align +endif + WFLAGS+=-Wwrite-strings +ifndef ERRORMODE +#WFLAGS+=-Wconversion +ifdef GCC43 + #WFLAGS+=-Wno-sign-conversion +endif +endif + WFLAGS+=-Wsign-compare +ifdef GCC91 + WFLAGS+=-Wno-error=address-of-packed-member +endif +ifdef GCC45 + WFLAGS+=-Wlogical-op +endif + WFLAGS+=-Waggregate-return +ifdef HAIKU +ifdef GCC41 + #WFLAGS+=-Wno-attributes +endif +endif +#WFLAGS+=-Wstrict-prototypes +ifdef GCC40 + WFLAGS+=-Wold-style-definition +endif + WFLAGS+=-Wmissing-prototypes -Wmissing-declarations +ifdef GCC40 + WFLAGS+=-Wmissing-field-initializers +endif + WFLAGS+=-Wmissing-noreturn +#WFLAGS+=-Wmissing-format-attribute +#WFLAGS+=-Wno-multichar +#WFLAGS+=-Wno-deprecated-declarations +#WFLAGS+=-Wpacked +#WFLAGS+=-Wpadded +#WFLAGS+=-Wredundant-decls + WFLAGS+=-Wnested-externs +#WFLAGS+=-Wunreachable-code + WFLAGS+=-Winline +ifdef GCC43 + WFLAGS+=-funit-at-a-time + WFLAGS+=-Wlogical-op +endif +ifndef GCC295 + WFLAGS+=-Wdisabled-optimization +endif +endif +WFLAGS+=-Wformat-y2k +ifdef GCC71 +WFLAGS+=-Wno-error=format-overflow=2 +endif +WFLAGS+=-Wformat-security +ifndef GCC29 +#WFLAGS+=-Winit-self +endif +ifdef GCC46 +WFLAGS+=-Wno-suggest-attribute=noreturn +endif + +ifdef NOLDWARNING +LDFLAGS+=-Wl,--as-needed +endif + +ifdef ERRORMODE +WFLAGS+=-Werror +endif + +ifdef GCC43 + #WFLAGS+=-Wno-error=clobbered +endif +ifdef GCC44 + WFLAGS+=-Wno-error=array-bounds +endif +ifdef GCC46 + WFLAGS+=-Wno-error=suggest-attribute=noreturn +endif +ifdef GCC54 + WFLAGS+=-Wno-logical-op -Wno-error=logical-op +endif +ifdef GCC61 + WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare +endif +ifdef GCC71 + WFLAGS+=-Wimplicit-fallthrough=4 +endif +ifdef GCC81 + WFLAGS+=-Wno-error=format-overflow + WFLAGS+=-Wno-error=stringop-truncation + WFLAGS+=-Wno-error=stringop-overflow + WFLAGS+=-Wno-format-overflow + WFLAGS+=-Wno-stringop-truncation + WFLAGS+=-Wno-stringop-overflow + WFLAGS+=-Wno-error=multistatement-macros +endif + +ifdef NONX86 + ifdef X86_64 # yeah that SEEMS contradictory + opts+=-march=nocona + endif +else + ifndef GCC29 + opts+=-msse3 -mfpmath=sse + else + opts+=-mpentium + endif +endif + +ifdef DEBUGMODE +ifdef GCC48 +opts+=-Og +else +opts+=O0 +endif +endif + +ifdef VALGRIND +ifdef GCC46 +WFLAGS+=-Wno-error=unused-but-set-variable +WFLAGS+=-Wno-unused-but-set-variable +endif +endif + +# Lua +ifdef GCC43 +ifndef GCC44 +WFLAGS+=-Wno-logical-op +endif +endif diff --git a/src/Makefile.d/win32.mk b/src/Makefile.d/win32.mk new file mode 100644 index 000000000..768133c15 --- /dev/null +++ b/src/Makefile.d/win32.mk @@ -0,0 +1,104 @@ +# +# Mingw, if you don't know, that's Win32/Win64 +# + +ifndef MINGW64 +EXENAME?=srb2win.exe +else +EXENAME?=srb2win64.exe +endif + +# disable dynamicbase if under msys2 +ifdef MSYSTEM +libs+=-Wl,--disable-dynamicbase +endif + +sources+=win32/Srb2win.rc +opts+=-DSTDC_HEADERS +libs+=-ladvapi32 -lkernel32 -lmsvcrt -luser32 + +nasm_format:=win32 + +SDL=1 + +ifndef NOHW +opts+=-DUSE_WGL_SWAP +endif + +ifdef MINGW64 +libs+=-lws2_32 +else +ifdef NO_IPV6 +libs+=-lwsock32 +else +libs+=-lws2_32 +endif +endif + +ifndef NONET +ifndef MINGW64 # miniupnc is broken with MINGW64 +opts+=-I../libs -DSTATIC_MINIUPNPC +libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi +endif +endif + +ifndef MINGW64 +32=32 +x86=x86 +i686=i686 +else +32=64 +x86=x86_64 +i686=x86_64 +endif + +mingw:=$(i686)-w64-mingw32 + +define _set = +$(1)_CFLAGS?=$($(1)_opts) +$(1)_LDFLAGS?=$($(1)_libs) +endef + +lib:=../libs/gme +LIBGME_opts:=-I$(lib)/include +LIBGME_libs:=-L$(lib)/win$(32) -lgme +$(eval $(call _set,LIBGME)) + +lib:=../libs/libopenmpt +LIBOPENMPT_opts:=-I$(lib)/inc +LIBOPENMPT_libs:=-L$(lib)/lib/$(x86)/mingw -lopenmpt +$(eval $(call _set,LIBOPENMPT)) + +ifndef NOMIXERX +HAVE_MIXERX=1 +lib:=../libs/SDLMixerX/$(mingw) +else +lib:=../libs/SDL2_mixer/$(mingw) +endif + +mixer_opts:=-I$(lib)/include/SDL2 +mixer_libs:=-L$(lib)/lib + +lib:=../libs/SDL2/$(mingw) +SDL_opts:=-I$(lib)/include/SDL2\ + $(mixer_opts) -Dmain=SDL_main +SDL_libs:=-L$(lib)/lib $(mixer_libs)\ + -lmingw32 -lSDL2main -lSDL2 -mwindows +$(eval $(call _set,SDL)) + +lib:=../libs/zlib +ZLIB_opts:=-I$(lib) +ZLIB_libs:=-L$(lib)/win32 -lz$(32) +$(eval $(call _set,ZLIB)) + +ifndef PNG_CONFIG +lib:=../libs/libpng-src +PNG_opts:=-I$(lib) +PNG_libs:=-L$(lib)/projects -lpng$(32) +$(eval $(call _set,PNG)) +endif + +lib:=../libs/curl +CURL_opts:=-I$(lib)/include +CURL_libs:=-L$(lib)/lib$(32) -lcurl +$(eval $(call _set,CURL)) diff --git a/src/Sourcefile b/src/Sourcefile new file mode 100644 index 000000000..983dadaf0 --- /dev/null +++ b/src/Sourcefile @@ -0,0 +1,98 @@ +string.c +d_main.c +d_clisrv.c +d_net.c +d_netfil.c +d_netcmd.c +dehacked.c +deh_soc.c +deh_lua.c +deh_tables.c +z_zone.c +f_finale.c +f_wipe.c +g_demo.c +g_game.c +g_input.c +am_map.c +command.c +console.c +hu_stuff.c +y_inter.c +st_stuff.c +m_aatree.c +m_anigif.c +m_argv.c +m_bbox.c +m_cheat.c +m_cond.c +m_easing.c +m_fixed.c +m_menu.c +m_misc.c +m_perfstats.c +m_random.c +m_queue.c +info.c +p_ceilng.c +p_enemy.c +p_floor.c +p_inter.c +p_lights.c +p_map.c +p_maputl.c +p_mobj.c +p_polyobj.c +p_saveg.c +p_setup.c +p_sight.c +p_spec.c +p_telept.c +p_tick.c +p_user.c +p_slopes.c +tables.c +r_bsp.c +r_data.c +r_draw.c +r_main.c +r_plane.c +r_segs.c +r_skins.c +r_sky.c +r_splats.c +r_things.c +r_textures.c +r_patch.c +r_patchrotation.c +r_picformats.c +r_portal.c +screen.c +taglist.c +v_video.c +s_sound.c +sounds.c +w_wad.c +filesrch.c +mserv.c +http-mserv.c +i_tcp.c +lzf.c +vid_copy.s +b_bot.c +lua_script.c +lua_baselib.c +lua_mathlib.c +lua_hooklib.c +lua_consolelib.c +lua_infolib.c +lua_mobjlib.c +lua_playerlib.c +lua_skinlib.c +lua_thinkerlib.c +lua_maplib.c +lua_taglib.c +lua_polyobjlib.c +lua_blockmaplib.c +lua_hudlib.c +lua_inputlib.c diff --git a/src/am_map.c b/src/am_map.c index 53a7480a5..65a57c09e 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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/am_map.h b/src/am_map.h index 1c8fa70e4..89c4ad9fa 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/apng.c b/src/apng.c index 0abbe541d..f4c08d979 100644 --- a/src/apng.c +++ b/src/apng.c @@ -1,5 +1,5 @@ /* -Copyright 2019-2020, James R. +Copyright 2019-2022, James R. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/apng.h b/src/apng.h index a8b5c8f24..6b9347424 100644 --- a/src/apng.h +++ b/src/apng.h @@ -1,5 +1,5 @@ /* -Copyright 2019-2020, James R. +Copyright 2019-2022, James R. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/asm_defs.inc b/src/asm_defs.inc index ec286b0bd..a8c60f19e 100644 --- a/src/asm_defs.inc +++ b/src/asm_defs.inc @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/b_bot.c b/src/b_bot.c index d3635f32c..775a13e29 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2007-2016 by John "JTE" Muniz. -// Copyright (C) 2011-2020 by Sonic Team Junior. +// Copyright (C) 2011-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -17,30 +17,45 @@ #include "p_local.h" #include "b_bot.h" #include "lua_hook.h" +#include "i_system.h" // I_BaseTiccmd -// 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->botleader) + { + player->botleader = &players[i]; // set default + return; + } + + if (!player->mo) + 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 +64,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) + // Lua can handle it! + if (LUA_HookBotAI(sonic, tails, cmd)) return; - // Lua can handle it! - if (LUAh_BotAI(sonic, tails, cmd)) + // 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 +126,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 +189,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 +209,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 +226,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 +247,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 +269,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 +284,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 +306,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,8 +317,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 - bot->drawangle = ang; + cmd->angleturn = (sonic->angle) >> 16; // NOT FRACBITS DAMNIT cmd->forwardmove = 8 * pcmd->forwardmove / 10; cmd->sidemove = 8 * pcmd->sidemove / 10; } @@ -301,7 +325,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,35 +343,36 @@ 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) { + G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver + // Can't build a ticcmd if we aren't spawned... if (!player->mo) return; @@ -363,25 +388,28 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd) CV_SetValue(&cv_analog[1], false); // Let Lua scripts build ticcmds - if (LUAh_BotTiccmd(player, 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 +448,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,21 +475,26 @@ 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; // B_RespawnBot doesn't do anything if the condition above this isn't met { - UINT8 shouldForce = LUAh_BotRespawn(sonic, tails); + UINT8 shouldForce = LUA_Hook2Mobj(sonic, tails, MOBJ_HOOK(BotRespawn)); if (P_MobjWasRemoved(sonic) || P_MobjWasRemoved(tails)) return (shouldForce == 1); // mobj was removed @@ -505,15 +538,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 +577,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,26 +594,44 @@ void B_RespawnBot(INT32 playernum) void B_HandleFlightIndicator(player_t *player) { mobj_t *tails = player->mo; + botmem_t *mem = &player->botmem; + boolean shouldExist; if (!tails) return; - if (thinkfly && player->bot == 1 && tails->health) + shouldExist = (mem->thinkstate == AI_THINKFLY) && player->botleader + && player->bot == BOT_2PAI && player->playerstate == PST_LIVE; + + // check whether the indicator doesn't exist + if (P_MobjWasRemoved(tails->hnext)) { - if (!tails->hnext) - { - P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY)); - if (tails->hnext) - { - P_SetTarget(&tails->hnext->target, tails); - P_SetTarget(&tails->hnext->hprev, tails); - P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR); - } - } + // if it shouldn't exist, everything is fine + if (!shouldExist) + return; + + // otherwise, spawn it + P_SetTarget(&tails->hnext, P_SpawnMobjFromMobj(tails, 0, 0, 0, MT_OVERLAY)); + P_SetTarget(&tails->hnext->target, tails); + P_SetTarget(&tails->hnext->hprev, tails); + P_SetMobjState(tails->hnext, S_FLIGHTINDICATOR); } - else if (tails->hnext && tails->hnext->type == MT_OVERLAY && tails->hnext->state == states+S_FLIGHTINDICATOR) + + // if the mobj isn't a flight indicator, let's not mess with it + if (tails->hnext->type != MT_OVERLAY || (tails->hnext->state != states+S_FLIGHTINDICATOR)) + return; + + // if it shouldn't exist, remove it + if (!shouldExist) { P_RemoveMobj(tails->hnext); P_SetTarget(&tails->hnext, NULL); + return; } + + // otherwise, update its visibility + if (P_IsLocalPlayer(player->botleader)) + tails->hnext->flags2 &= ~MF2_DONTDRAW; + else + tails->hnext->flags2 |= MF2_DONTDRAW; } diff --git a/src/b_bot.h b/src/b_bot.h index 2806bd68f..c29974c50 100644 --- a/src/b_bot.h +++ b/src/b_bot.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2007-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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/CMakeLists.txt b/src/blua/CMakeLists.txt new file mode 100644 index 000000000..4e9c67d2f --- /dev/null +++ b/src/blua/CMakeLists.txt @@ -0,0 +1 @@ +target_sourcefile(c) diff --git a/src/blua/Makefile.cfg b/src/blua/Makefile.cfg deleted file mode 100644 index eae95ba3a..000000000 --- a/src/blua/Makefile.cfg +++ /dev/null @@ -1,52 +0,0 @@ -ifdef UNIXCOMMON -LUA_CFLAGS+=-DLUA_USE_POSIX -endif -ifdef LINUX -LUA_CFLAGS+=-DLUA_USE_POSIX -endif -ifdef GCC43 -ifndef GCC44 -WFLAGS+=-Wno-logical-op -endif -endif - -OBJS:=$(OBJS) \ - $(OBJDIR)/lapi.o \ - $(OBJDIR)/lbaselib.o \ - $(OBJDIR)/ldo.o \ - $(OBJDIR)/lfunc.o \ - $(OBJDIR)/linit.o \ - $(OBJDIR)/liolib.o \ - $(OBJDIR)/llex.o \ - $(OBJDIR)/lmem.o \ - $(OBJDIR)/lobject.o \ - $(OBJDIR)/lstate.o \ - $(OBJDIR)/lstrlib.o \ - $(OBJDIR)/ltablib.o \ - $(OBJDIR)/lundump.o \ - $(OBJDIR)/lzio.o \ - $(OBJDIR)/lauxlib.o \ - $(OBJDIR)/lcode.o \ - $(OBJDIR)/ldebug.o \ - $(OBJDIR)/ldump.o \ - $(OBJDIR)/lgc.o \ - $(OBJDIR)/lopcodes.o \ - $(OBJDIR)/lparser.o \ - $(OBJDIR)/lstring.o \ - $(OBJDIR)/ltable.o \ - $(OBJDIR)/ltm.o \ - $(OBJDIR)/lvm.o \ - $(OBJDIR)/lua_script.o \ - $(OBJDIR)/lua_baselib.o \ - $(OBJDIR)/lua_mathlib.o \ - $(OBJDIR)/lua_hooklib.o \ - $(OBJDIR)/lua_consolelib.o \ - $(OBJDIR)/lua_infolib.o \ - $(OBJDIR)/lua_mobjlib.o \ - $(OBJDIR)/lua_playerlib.o \ - $(OBJDIR)/lua_skinlib.o \ - $(OBJDIR)/lua_thinkerlib.o \ - $(OBJDIR)/lua_maplib.o \ - $(OBJDIR)/lua_polyobjlib.o \ - $(OBJDIR)/lua_blockmaplib.o \ - $(OBJDIR)/lua_hudlib.o diff --git a/src/blua/Sourcefile b/src/blua/Sourcefile new file mode 100644 index 000000000..f99c89c8d --- /dev/null +++ b/src/blua/Sourcefile @@ -0,0 +1,25 @@ +lapi.c +lbaselib.c +ldo.c +lfunc.c +linit.c +liolib.c +llex.c +lmem.c +lobject.c +lstate.c +lstrlib.c +ltablib.c +lundump.c +lzio.c +lauxlib.c +lcode.c +ldebug.c +ldump.c +lgc.c +lopcodes.c +lparser.c +lstring.c +ltable.c +ltm.c +lvm.c 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/blua/ldump.c b/src/blua/ldump.c index c9d3d4870..b69a12729 100644 --- a/src/blua/ldump.c +++ b/src/blua/ldump.c @@ -60,7 +60,7 @@ static void DumpVector(const void* b, int n, size_t size, DumpState* D) static void DumpString(const TString* s, DumpState* D) { - if (s==NULL || getstr(s)==NULL) + if (s==NULL) { size_t size=0; DumpVar(size,D); diff --git a/src/byteptr.h b/src/byteptr.h index 01a6293b4..33c2c8a4b 100644 --- a/src/byteptr.h +++ b/src/byteptr.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -150,26 +150,78 @@ FUNCINLINE static ATTRINLINE UINT32 readulong(void *ptr) #undef DEALIGNED -#define WRITESTRINGN(p,s,n) do { size_t tmp_i = 0; for (; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); if (tmp_i < n) WRITECHAR(p, '\0');} while (0) -#define WRITESTRING(p,s) do { size_t tmp_i = 0; for (; s[tmp_i] != '\0'; tmp_i++) WRITECHAR(p, s[tmp_i]); WRITECHAR(p, '\0');} while (0) -#define WRITEMEM(p,s,n) do { memcpy(p, s, n); p += n; } while (0) +#define WRITESTRINGN(p, s, n) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; tmp_i < n && s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + if (tmp_i < n) \ + WRITECHAR(p, '\0'); \ +}) -#define SKIPSTRING(p) while (READCHAR(p) != '\0') +#define WRITESTRINGL(p, s, n) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; tmp_i < n - 1 && s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + WRITECHAR(p, '\0'); \ +}) -#define READSTRINGN(p,s,n) ({ size_t tmp_i = 0; for (; tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';}) -#define READSTRING(p,s) ({ size_t tmp_i = 0; for (; (s[tmp_i] = READCHAR(p)) != '\0'; tmp_i++); s[tmp_i] = '\0';}) -#define READMEM(p,s,n) ({ memcpy(s, p, n); p += n; }) +#define WRITESTRING(p, s) ({ \ + size_t tmp_i; \ + \ + for (tmp_i = 0; s[tmp_i] != '\0'; tmp_i++) \ + WRITECHAR(p, s[tmp_i]); \ + \ + WRITECHAR(p, '\0'); \ +}) -#if 0 // old names -#define WRITEBYTE(p,b) WRITEUINT8(p,b) -#define WRITESHORT(p,b) WRITEINT16(p,b) -#define WRITEUSHORT(p,b) WRITEUINT16(p,b) -#define WRITELONG(p,b) WRITEINT32(p,b) -#define WRITEULONG(p,b) WRITEUINT32(p,b) +#define WRITEMEM(p, s, n) ({ \ + memcpy(p, s, n); \ + p += n; \ +}) -#define READBYTE(p) READUINT8(p) -#define READSHORT(p) READINT16(p) -#define READUSHORT(p) READUINT16(p) -#define READLONG(p) READINT32(p) -#define READULONG(p) READUINT32(p) -#endif +#define SKIPSTRING(p) while (READCHAR(p) != '\0') + +#define SKIPSTRINGN(p, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n && READCHAR(p) != '\0') \ + tmp_i++; \ +}) + +#define SKIPSTRINGL(p, n) SKIPSTRINGN(p, n) + +#define READSTRINGN(p, s, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n && (s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READSTRINGL(p, s, n) ({ \ + size_t tmp_i = 0; \ + \ + while (tmp_i < n - 1 && (s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READSTRING(p, s) ({ \ + size_t tmp_i = 0; \ + \ + while ((s[tmp_i] = READCHAR(p)) != '\0') \ + tmp_i++; \ + \ + s[tmp_i] = '\0'; \ +}) + +#define READMEM(p, s, n) ({ \ + memcpy(s, p, n); \ + p += n; \ +}) diff --git a/src/command.c b/src/command.c index 58434ef89..dae4dc7b1 100644 --- a/src/command.c +++ b/src/command.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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; @@ -660,7 +660,7 @@ static void COM_ExecuteString(char *ptext) // check cvars // Hurdler: added at Ebola's request ;) // (don't flood the console in software mode with bad gl_xxx command) - if (!CV_Command() && con_destlines) + if (!CV_Command() && (con_destlines || dedicated)) CONS_Printf(M_GetText("Unknown command '%s'\n"), COM_Argv(0)); } @@ -1433,6 +1433,7 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) if (var->revert.allocated) { Z_Free(var->revert.v.string); + var->revert.allocated = false; // the below value is not allocated in zone memory, don't try to free it! } var->revert.v.const_munge = var->PossibleValue[i].strvalue; @@ -1440,6 +1441,10 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) return; } + // free the old value string + Z_Free(var->zstring); + var->zstring = NULL; + var->value = var->PossibleValue[i].value; var->string = var->PossibleValue[i].strvalue; goto finish; @@ -1502,13 +1507,7 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) found: if (client && execversion_enabled) { - if (var->revert.allocated) - { - Z_Free(var->revert.v.string); - } - var->revert.v.const_munge = var->PossibleValue[i].strvalue; - return; } @@ -1523,6 +1522,7 @@ found: if (var->revert.allocated) { Z_Free(var->revert.v.string); + // Z_StrDup creates a new zone memory block, so we can keep the allocated flag on } var->revert.v.string = Z_StrDup(valstr); @@ -1577,7 +1577,7 @@ finish: } var->flags |= CV_MODIFIED; // raise 'on change' code - LUA_CVarChanged(var->name); // let consolelib know what cvar this is. + LUA_CVarChanged(var); // let consolelib know what cvar this is. if (var->flags & CV_CALL && !stealth) var->func(); @@ -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 ); @@ -1787,6 +1789,7 @@ void CV_RevertNetVars(void) if (cvar->revert.allocated) { Z_Free(cvar->revert.v.string); + cvar->revert.allocated = false; // no value being held now } cvar->revert.v.string = NULL; @@ -2363,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/command.h b/src/command.h index ea5593395..30d7e5bbe 100644 --- a/src/command.h +++ b/src/command.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -158,7 +158,7 @@ typedef struct consvar_s //NULL, NULL, 0, NULL, NULL |, 0, NULL, NULL, 0, 0, NUL /* name, defaultvalue, flags, PossibleValue, func */ #define CVAR_INIT( ... ) \ -{ __VA_ARGS__, 0, NULL, NULL, {0}, 0U, (char)0, NULL } +{ __VA_ARGS__, 0, NULL, NULL, {0, {NULL}}, 0U, (char)0, NULL } #ifdef OLD22DEMOCOMPAT typedef struct old_demo_var old_demo_var_t; diff --git a/src/config.h.in b/src/config.h.in index a6f43a7d7..587a881c7 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -34,12 +34,14 @@ * Last updated 2020 / 07 / 10 - v2.2.6 - player.dta & patch.pk3 * Last updated 2020 / 09 / 27 - v2.2.7 - patch.pk3 * Last updated 2020 / 10 / 02 - v2.2.8 - patch.pk3 + * Last updated 2021 / 05 / 06 - v2.2.9 - patch.pk3 & zones.pk3 + * Last updated 2022 / 03 / 06 - v2.2.10 - main assets */ -#define ASSET_HASH_SRB2_PK3 "0277c9416756627004e83cbb5b2e3e28" -#define ASSET_HASH_ZONES_PK3 "f7e88afb6af7996a834c7d663144bead" -#define ASSET_HASH_PLAYER_DTA "49dad7b24634c89728cc3e0b689e12bb" +#define ASSET_HASH_SRB2_PK3 "ad911f29a28a18968ee5b2d11c2acb39" +#define ASSET_HASH_ZONES_PK3 "86ae55cae4e0a93ceda868635706a093" +#define ASSET_HASH_PLAYER_DTA "2e7aaae8a6b1b77d90ffe7606ceadb6c" #ifdef USE_PATCH_DTA -#define ASSET_HASH_PATCH_PK3 "466cdf60075262b3f5baa5e07f0999e8" +#define ASSET_HASH_PATCH_PK3 "7d467a883f7887b3c311798ee2f56b6a" #endif #endif diff --git a/src/console.c b/src/console.c index b19b8818d..40fb43121 100644 --- a/src/console.c +++ b/src/console.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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")); @@ -360,30 +360,48 @@ static void CON_SetupColormaps(void) for (i = 0; i < (256*15); i++, ++memorysrc) *memorysrc = (UINT8)(i & 0xFF); // remap each color to itself... -#define colset(map, a, b, c) \ - map[1] = (UINT8)a;\ - map[3] = (UINT8)b;\ - map[9] = (UINT8)c +#define colset(map, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ + map[0x0] = (UINT8)a;\ + map[0x1] = (UINT8)b;\ + map[0x2] = (UINT8)c;\ + map[0x3] = (UINT8)d;\ + map[0x4] = (UINT8)e;\ + map[0x5] = (UINT8)f;\ + map[0x6] = (UINT8)g;\ + map[0x7] = (UINT8)h;\ + map[0x8] = (UINT8)i;\ + map[0x9] = (UINT8)j;\ + map[0xA] = (UINT8)k;\ + map[0xB] = (UINT8)l;\ + map[0xC] = (UINT8)m;\ + map[0xD] = (UINT8)n;\ + map[0xE] = (UINT8)o;\ + map[0xF] = (UINT8)p; - colset(magentamap, 177, 178, 184); - colset(yellowmap, 82, 73, 66); - colset(lgreenmap, 97, 98, 106); - colset(bluemap, 146, 147, 155); - colset(redmap, 210, 32, 39); - colset(graymap, 6, 8, 14); - colset(orangemap, 51, 52, 57); - colset(skymap, 129, 130, 133); - colset(purplemap, 160, 161, 163); - colset(aquamap, 120, 121, 123); - colset(peridotmap, 88, 188, 190); - colset(azuremap, 144, 145, 170); - colset(brownmap, 219, 221, 224); - colset(rosymap, 200, 201, 203); - colset(invertmap, 27, 26, 22); - invertmap[26] = (UINT8)3; + // Tried to keep the colors vanilla while adding some shades in between them ~SonicX8000 + + // 0x1 0x3 0x9 0xF + colset(magentamap, 177, 177, 178, 178, 178, 180, 180, 180, 182, 182, 182, 182, 184, 184, 184, 185); + colset(yellowmap, 82, 82, 73, 73, 73, 64, 64, 64, 66, 66, 66, 66, 67, 67, 67, 68); + colset(lgreenmap, 96, 96, 98, 98, 98, 101, 101, 101, 104, 104, 104, 104, 106, 106, 106, 107); + colset(bluemap, 146, 146, 147, 147, 147, 149, 149, 149, 152, 152, 152, 152, 155, 155, 155, 157); + colset(redmap, 32, 32, 33, 33, 33, 35, 35, 35, 39, 39, 39, 39, 42, 42, 42, 44); + colset(graymap, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23); + colset(orangemap, 50, 50, 52, 52, 52, 54, 54, 54, 56, 56, 56, 56, 59, 59, 59, 60); + colset(skymap, 129, 129, 130, 130, 130, 131, 131, 131, 133, 133, 133, 133, 135, 135, 135, 136); + colset(purplemap, 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 163, 164, 164, 164, 165); + colset(aquamap, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124, 124, 125); + colset(peridotmap, 72, 72, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 94); + colset(azuremap, 144, 144, 145, 145, 145, 146, 146, 146, 170, 170, 170, 170, 171, 171, 171, 172); + colset(brownmap, 219, 219, 221, 221, 221, 222, 222, 222, 224, 224, 224, 224, 227, 227, 227, 229); + colset(rosymap, 200, 200, 201, 201, 201, 202, 202, 202, 203, 203, 203, 203, 204, 204, 204, 205); #undef colset + // Yeah just straight up invert it like a normal person + for (i = 0x00; i <= 0x1F; i++) + invertmap[0x1F - i] = i; + // Init back colormap CON_SetupBackColormap(); } @@ -466,6 +484,19 @@ void CON_Init(void) Unlock_state(); } } + +void CON_StartRefresh(void) +{ + if (con_startup) + con_refresh = true; +} + +void CON_StopRefresh(void) +{ + if (con_startup) + con_refresh = false; +} + // Console input initialization // static void CON_InputInit(void) @@ -808,6 +839,12 @@ static void CON_InputDelSelection(void) Lock_state(); + if (!input_cur) + { + Unlock_state(); + return; + } + if (input_cur > input_sel) { start = input_sel; @@ -889,12 +926,12 @@ boolean CON_Responder(event_t *ev) // let go keyup events, don't eat them if (ev->type != ev_keydown && ev->type != ev_console) { - if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1]) + if (ev->key == gamecontrol[GC_CONSOLE][0] || ev->key == gamecontrol[GC_CONSOLE][1]) consdown = false; return false; } - key = ev->data1; + key = ev->key; // check for console toggle key if (ev->type != ev_console) @@ -902,7 +939,7 @@ boolean CON_Responder(event_t *ev) if (modeattacking || metalrecording || marathonmode) return false; - if (key == gamecontrol[gc_console][0] || key == gamecontrol[gc_console][1]) + if (key == gamecontrol[GC_CONSOLE][0] || key == gamecontrol[GC_CONSOLE][1]) { if (consdown) // ignore repeat return true; @@ -1279,10 +1316,6 @@ boolean CON_Responder(event_t *ev) if (key < 32 || key > 127) return true; - // add key to cmd line here - if (key >= 'A' && key <= 'Z' && !(shiftdown ^ capslock)) //this is only really necessary for dedicated servers - key = key + 'a' - 'A'; - if (input_sel != input_cur) CON_InputDelSelection(); CON_InputAddChar(key); @@ -1677,7 +1710,10 @@ static void CON_DrawHudlines(void) { charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; p++; + c++; } + if (c >= con_width) + break; if (*p < HU_FONTSTART) ;//charwidth = 4 * con_scalefactor; else @@ -1736,8 +1772,8 @@ static void CON_DrawBackpic(void) } // Draw the patch. - V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic, - 0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h); + V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, FRACUNIT, V_NOSCALESTART, con_backpic, NULL, + 0, (BASEVIDHEIGHT - h) << FRACBITS, BASEVIDWIDTH << FRACBITS, h << FRACBITS); // Unlock the cached patch. W_UnlockCachedPatch(con_backpic); @@ -1798,7 +1834,10 @@ static void CON_DrawConsole(void) { charflags = (*p & 0x7f) << V_CHARCOLORSHIFT; p++; + c++; } + if (c >= con_width) + break; V_DrawCharacter(x, y, (INT32)(*p) | charflags | cv_constextsize.value | V_NOSCALESTART, true); } } diff --git a/src/console.h b/src/console.h index 0296f4f6e..1cd032ac1 100644 --- a/src/console.h +++ b/src/console.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -16,6 +16,9 @@ void CON_Init(void); +void CON_StartRefresh(void); +void CON_StopRefresh(void); + boolean CON_Responder(event_t *ev); #ifdef HAVE_THREADS diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 4fdc7e7ee..ac8bba608 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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" @@ -127,10 +128,14 @@ static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen static tic_t neededtic; SINT8 servernode = 0; // the number of the server node + /// \brief do we accept new players? /// \todo WORK! boolean acceptnewnode = true; +static boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not +static tic_t firstconnectattempttime = 0; + // engine // Must be a power of two @@ -510,18 +515,24 @@ static INT16 Consistancy(void); typedef enum { CL_SEARCHING, + CL_CHECKFILES, CL_DOWNLOADFILES, CL_ASKJOIN, + CL_LOADFILES, CL_WAITJOINRESPONSE, CL_DOWNLOADSAVEGAME, CL_CONNECTED, - CL_ABORTED + CL_ABORTED, + CL_ASKFULLFILELIST, + CL_CONFIRMCONNECT } cl_mode_t; static void GetPackets(void); static cl_mode_t cl_mode = CL_SEARCHING; +static UINT16 cl_lastcheckedfilecount = 0; // used for full file list + #ifndef NONET #define SNAKE_SPEED 5 @@ -663,14 +674,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; @@ -919,6 +930,8 @@ static void Snake_Draw(void) INT16 i; // Background + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + V_DrawFlatFill( SNAKE_LEFT_X + SNAKE_BORDER_SIZE, SNAKE_TOP_Y + SNAKE_BORDER_SIZE, @@ -1020,6 +1033,13 @@ static void Snake_Draw(void) ); } +static void CL_DrawConnectionStatusBox(void) +{ + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + if (cl_mode != CL_CONFIRMCONNECT) + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); +} + // // CL_DrawConnectionStatus // @@ -1030,28 +1050,32 @@ static inline void CL_DrawConnectionStatus(void) INT32 ccstime = I_GetTime(); // Draw background fade - if (!menuactive) // menu already draws its own fade - V_DrawFadeScreen(0xFF00, 16); // force default + V_DrawFadeScreen(0xFF00, 16); // force default - // Draw the bottom box. - M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); - V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); - - if (cl_mode != CL_DOWNLOADFILES) + if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES) { INT32 i, animtime = ((ccstime / 4) & 15) + 16; - UINT8 palstart = (cl_mode == CL_SEARCHING) ? 32 : 96; - // 15 pal entries total. + UINT8 palstart; const char *cltext; + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (cl_mode == CL_SEARCHING) + palstart = 32; // Red + else if (cl_mode == CL_CONFIRMCONNECT) + palstart = 48; // Orange + else + palstart = 96; // Green + if (!(cl_mode == CL_DOWNLOADSAVEGAME && lastfilenum != -1)) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // 15 pal entries total. V_DrawFill((BASEVIDWIDTH/2-128) + (i * 16), BASEVIDHEIGHT-16, 16, 8, palstart + ((animtime - i) & 15)); switch (cl_mode) { case CL_DOWNLOADSAVEGAME: - if (lastfilenum != -1) + if (fileneeded && lastfilenum != -1) { UINT32 currentsize = fileneeded[lastfilenum].currentsize; UINT32 totalsize = fileneeded[lastfilenum].totalsize; @@ -1075,9 +1099,22 @@ static inline void CL_DrawConnectionStatus(void) else cltext = M_GetText("Waiting to download game state..."); break; + case CL_ASKFULLFILELIST: + case CL_CHECKFILES: + cltext = M_GetText("Checking server addon list..."); + break; + case CL_CONFIRMCONNECT: + cltext = ""; + break; + case CL_LOADFILES: + cltext = M_GetText("Loading server addons..."); + break; case CL_ASKJOIN: case CL_WAITJOINRESPONSE: - cltext = M_GetText("Requesting to join..."); + if (serverisfull) + cltext = M_GetText("Server full, waiting for a slot..."); + else + cltext = M_GetText("Requesting to join..."); break; default: cltext = M_GetText("Connecting to server..."); @@ -1087,14 +1124,51 @@ static inline void CL_DrawConnectionStatus(void) } else { - if (lastfilenum != -1) + if (cl_mode == CL_LOADFILES) + { + INT32 totalfileslength; + INT32 loadcompletednum = 0; + INT32 i; + + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-16, V_YELLOWMAP, "Press ESC to abort"); + + //ima just count files here + if (fileneeded) + { + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_OPEN) + loadcompletednum++; + } + + // Loading progress + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, "Loading server addons..."); + totalfileslength = (INT32)((loadcompletednum/(double)(fileneedednum)) * 256); + M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-16-8, 32, 1); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, 256, 8, 111); + V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-16, totalfileslength, 8, 96); + V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16, V_20TRANS|V_MONOSPACE, + va(" %2u/%2u Files",loadcompletednum,fileneedednum)); + } + else if (lastfilenum != -1) { INT32 dldlength; static char tempname[28]; - fileneeded_t *file = &fileneeded[lastfilenum]; - char *filename = file->filename; + fileneeded_t *file; + char *filename; - Snake_Draw(); + if (snake) + Snake_Draw(); + + // Draw the bottom box. + CL_DrawConnectionStatusBox(); + + if (fileneeded) + { + file = &fileneeded[lastfilenum]; + filename = file->filename; + } + else + return; Net_GetNetStat(); dldlength = (INT32)((file->currentsize/(double)file->totalsize) * 256); @@ -1127,20 +1201,32 @@ static inline void CL_DrawConnectionStatus(void) va("%3.1fK/s ", ((double)getbps)/1024)); } else + { + if (snake) + Snake_Draw(); + + CL_DrawConnectionStatusBox(); V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-16-24, V_YELLOWMAP, M_GetText("Waiting to download files...")); + } } } #endif +static boolean CL_AskFileList(INT32 firstfile) +{ + netbuffer->packettype = PT_TELLFILESNEEDED; + netbuffer->u.filesneedednum = firstfile; + + return HSendPacket(servernode, false, 0, sizeof (INT32)); +} + /** Sends a special packet to declare how many players in local * Used only in arbitratrenetstart() * Sends a PT_CLIENTJOIN packet to the server * * \return True if the packet was successfully sent * \todo Improve the description... - * Because to be honest, I have no idea what arbitratrenetstart is... - * Is it even used...? * */ static boolean CL_SendJoin(void) @@ -1150,15 +1236,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 +1286,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,20 +1319,13 @@ 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); netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame; netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled(); - netbuffer->u.serverinfo.isdedicated = (UINT8)dedicated; + netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0); strncpy(netbuffer->u.serverinfo.servername, cv_servername.string, MAXSERVERNAME); strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7); @@ -1267,7 +1360,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime) if (mapheaderinfo[gamemap-1]) netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum; - p = PutFileNeeded(); + p = PutFileNeeded(0); HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); } @@ -1344,9 +1437,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); @@ -1521,6 +1611,8 @@ static void CL_LoadReceivedSavegame(boolean reloading) size_t length, decompressedlen; char tmpsave[256]; + FreeFileNeeded(); + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); length = FIL_ReadFile(tmpsave, &savebuffer); @@ -1565,15 +1657,6 @@ static void CL_LoadReceivedSavegame(boolean reloading) } CONS_Printf("\"\n"); } - else - { - CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n")); - Z_Free(savebuffer); - save_p = NULL; - if (unlink(tmpsave) == -1) - CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); - return; - } // done Z_Free(savebuffer); @@ -1676,20 +1759,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++; } @@ -1838,6 +1925,224 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room) #endif // ifndef NONET +static void M_ConfirmConnect(event_t *ev) +{ +#ifndef NONET + if (ev->type == ev_keydown) + { + if (ev->key == ' ' || ev->key == 'y' || ev->key == KEY_ENTER) + { + if (totalfilesrequestednum > 0) + { + if (CL_SendFileRequest()) + { + cl_mode = CL_DOWNLOADFILES; + Snake_Initialise(); + } + } + else + cl_mode = CL_LOADFILES; + + M_ClearMenus(true); + } + else if (ev->key == 'n' || ev->key == KEY_ESCAPE) + { + cl_mode = CL_ABORTED; + M_ClearMenus(true); + } + } +#else + (void)ev; +#endif +} + +static boolean CL_FinishedFileList(void) +{ + INT32 i; + char *downloadsize = NULL; + //CONS_Printf(M_GetText("Checking files...\n")); + i = CL_CheckFiles(); + if (i == 4) // still checking ... + { + return true; + } + else if (i == 3) // too many files + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have too many WAD files loaded\n" + "to add ones the server is using.\n" + "Please restart SRB2 before connecting.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 2) // cannot join for some reason + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "You have the wrong addons loaded.\n\n" + "To play on this server, restart\n" + "the game and don't load any addons.\n" + "SRB2 will automatically add\n" + "everything you need when you join.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + else if (i == 1) + { + if (serverisfull) + { + M_StartMessage(M_GetText( + "This server is full!\n" + "\n" + "You may load server addons (if any), and wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n\n" + ), M_ConfirmConnect, MM_EVENTHANDLER); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + else + cl_mode = CL_LOADFILES; + } + else + { + // must download something + // can we, though? + if (!CL_CheckDownloadable()) // nope! + { + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "An error occured when trying to\n" + "download missing addons.\n" + "(This is almost always a problem\n" + "with the server, not your game.)\n\n" + "See the console or log file\n" + "for additional details.\n\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } + +#ifndef NONET + downloadcompletednum = 0; + downloadcompletedsize = 0; + totalfilesrequestednum = 0; + totalfilesrequestedsize = 0; + + if (fileneeded == NULL) + I_Error("CL_FinishedFileList: fileneeded == NULL"); + + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) + { + totalfilesrequestednum++; + totalfilesrequestedsize += fileneeded[i].totalsize; + } + + if (totalfilesrequestedsize>>20 >= 100) + downloadsize = Z_StrDup(va("%uM",totalfilesrequestedsize>>20)); + else + downloadsize = Z_StrDup(va("%uK",totalfilesrequestedsize>>10)); +#endif + + if (serverisfull) + M_StartMessage(va(M_GetText( + "This server is full!\n" + "Download of %s additional content\nis required to join.\n" + "\n" + "You may download, load server addons,\nand wait for a slot.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + else + M_StartMessage(va(M_GetText( + "Download of %s additional content\nis required to join.\n" + "\n" + "Press ENTER to continue\nor ESC to cancel.\n" + ), downloadsize), M_ConfirmConnect, MM_EVENTHANDLER); + + Z_Free(downloadsize); + cl_mode = CL_CONFIRMCONNECT; + curfadevalue = 0; + } + return true; +} + +#ifndef NONET +static const char * InvalidServerReason (serverinfo_pak *info) +{ +#define EOT "\nPress ESC\n" + + /* 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 +} +#endif // ifndef NONET + /** 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. @@ -1868,88 +2173,46 @@ 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) { - D_ParseFileneeded(serverlist[i].info.fileneedednum, - serverlist[i].info.fileneeded); - CONS_Printf(M_GetText("Checking files...\n")); - i = CL_CheckFiles(); - if (i == 3) // too many files - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have too many WAD files loaded\n" - "to add ones the server is using.\n" - "Please restart SRB2 before connecting.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 2) // cannot join for some reason - { - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); - M_StartMessage(M_GetText( - "You have the wrong addons loaded.\n\n" - "To play on this server, restart\n" - "the game and don't load any addons.\n" - "SRB2 will automatically add\n" - "everything you need when you join.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); - return false; - } - else if (i == 1) - cl_mode = CL_ASKJOIN; + serverinfo_pak *info = &serverlist[i].info; + + if (info->refusereason == REFUSE_SLOTS_FULL) + serverisfull = true; else { - // must download something - // can we, though? - if (!CL_CheckDownloadable()) // nope! + const char *reason = InvalidServerReason(info); + + // 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(M_GetText( - "You cannot connect to this server\n" - "because you cannot download the files\n" - "that you are missing from the server.\n\n" - "See the console or log file for\n" - "more details.\n\n" - "Press ESC\n" - ), NULL, MM_NOTHING); + M_StartMessage(message, NULL, MM_NOTHING); + Z_Free(message); return false; } - // no problem if can't send packet, we will retry later - if (CL_SendFileRequest()) - { - cl_mode = CL_DOWNLOADFILES; -#ifndef NONET - Snake_Initialise(); -#endif - } } + + D_ParseFileneeded(info->fileneedednum, info->fileneeded, 0); + + if (info->flags & SV_LOTSOFADDONS) + { + cl_mode = CL_ASKFULLFILELIST; + cl_lastcheckedfilecount = 0; + return true; + } + + cl_mode = CL_CHECKFILES; } else + { cl_mode = CL_ASKJOIN; // files need not be checked for the server. + *asksent = 0; + } return true; } @@ -1995,6 +2258,22 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic return false; break; + case CL_ASKFULLFILELIST: + if (cl_lastcheckedfilecount == UINT16_MAX) // All files retrieved + cl_mode = CL_CHECKFILES; + else if (fileneedednum != cl_lastcheckedfilecount || I_GetTime() >= *asksent) + { + if (CL_AskFileList(fileneedednum)) + { + cl_lastcheckedfilecount = fileneedednum; + *asksent = I_GetTime() + NEWTICRATE; + } + } + break; + case CL_CHECKFILES: + if (!CL_FinishedFileList()) + return false; + break; case CL_DOWNLOADFILES: waitmore = false; for (i = 0; i < fileneedednum; i++) @@ -2015,21 +2294,51 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic } #endif - cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now - /* FALLTHRU */ - + cl_mode = CL_LOADFILES; + break; + case CL_LOADFILES: + if (CL_LoadServerFiles()) + { + FreeFileNeeded(); + *asksent = 0; //This ensure the first join ask is right away + firstconnectattempttime = I_GetTime(); + cl_mode = CL_ASKJOIN; + } + break; case CL_ASKJOIN: - CL_LoadServerFiles(); + if (firstconnectattempttime + NEWTICRATE*300 < I_GetTime() && !server) + { + CONS_Printf(M_GetText("5 minute wait time exceeded.\n")); + CONS_Printf(M_GetText("Network game synchronization aborted.\n")); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + M_StartMessage(M_GetText( + "5 minute wait time exceeded.\n" + "You may retry connection.\n" + "\n" + "Press ESC\n" + ), NULL, MM_NOTHING); + return false; + } #ifndef NONET // prepare structures to save the file // WARNING: this can be useless in case of server not in GS_LEVEL // but since the network layer doesn't provide ordered packets... CL_PrepareDownloadSaveGame(tmpsave); #endif - if (CL_SendJoin()) + if (I_GetTime() >= *asksent && CL_SendJoin()) + { + *asksent = I_GetTime() + NEWTICRATE*3; cl_mode = CL_WAITJOINRESPONSE; + } + break; + case CL_WAITJOINRESPONSE: + if (I_GetTime() >= *asksent) + { + cl_mode = CL_ASKJOIN; + } break; - #ifndef NONET case CL_DOWNLOADSAVEGAME: // At this state, the first (and only) needed file is the gamestate @@ -2043,8 +2352,8 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic break; #endif - case CL_WAITJOINRESPONSE: case CL_CONNECTED: + case CL_CONFIRMCONNECT: //logic is handled by M_ConfirmConnect default: break; @@ -2052,7 +2361,6 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic case CL_ABORTED: cl_mode = CL_SEARCHING; return false; - } GetPackets(); @@ -2062,13 +2370,19 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (*oldtic != I_GetTime()) { I_OsPolling(); - for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) - G_MapEventsToControls(&events[eventtail]); - if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1]) + if (cl_mode == CL_CONFIRMCONNECT) + D_ProcessEvents(); //needed for menu system to receive inputs + else + { + for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) + G_MapEventsToControls(&events[eventtail]); + } + + if (gamekeydown[KEY_ESCAPE] || gamekeydown[KEY_JOY1+1] || cl_mode == CL_ABORTED) { CONS_Printf(M_GetText("Network game synchronization aborted.\n")); -// M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); + M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING); #ifndef NONET if (snake) @@ -2101,13 +2415,20 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic #ifndef NONET if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED) { - if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_DOWNLOADSAVEGAME) + if (!snake) { F_MenuPresTicker(true); // title sky F_TitleScreenTicker(true); F_TitleScreenDrawer(); } CL_DrawConnectionStatus(); +#ifdef HAVE_THREADS + I_lock_mutex(&m_menu_mutex); +#endif + M_Drawer(); //Needed for drawing messageboxes on the connection screen +#ifdef HAVE_THREADS + I_unlock_mutex(m_menu_mutex); +#endif I_UpdateNoVsync(); // page flip or blit buffer if (moviemode) M_SaveFrame(); @@ -2169,8 +2490,10 @@ static void CL_ConnectToServer(void) ClearAdminPlayers(); pnumnodes = 1; oldtic = I_GetTime() - 1; + #ifndef NONET asksent = (tic_t) - TICRATE; + firstconnectattempttime = I_GetTime(); i = SL_SearchServer(servernode); @@ -2472,7 +2795,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. @@ -2545,14 +2868,14 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) } } - LUAh_PlayerQuit(&players[playernum], reason); // Lua hook for player quitting + LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting // don't look through someone's view who isn't there if (playernum == displayplayer) { // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); + LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -2608,11 +2931,18 @@ 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 + FreeFileNeeded(); fileneedednum = 0; - memset(fileneeded, 0, sizeof(fileneeded)); + +#ifndef NONET + totalfilesrequestednum = 0; + totalfilesrequestedsize = 0; +#endif + firstconnectattempttime = 0; + serverisfull = false; + connectiontimeout = (tic_t)cv_nettimeout.value; //reset this temporary hack // D_StartTitle should get done now, but the calling function will handle it } @@ -2867,6 +3197,34 @@ static void Command_Kick(void) else CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); } + +static void Command_ResendGamestate(void) +{ + SINT8 playernum; + + if (COM_Argc() == 1) + { + CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); + return; + } + else if (client) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + playernum = nametonum(COM_Argv(1)); + if (playernum == -1 || playernum == 0) + return; + + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) + { + CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); + return; + } +} #endif static void Got_KickCmd(UINT8 **p, INT32 playernum) @@ -2961,7 +3319,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) { case KICK_MSG_GO_AWAY: if (!players[pnum].quittime) - HU_AddChatText(va("\x82*%s has been kicked (Go away)", player_names[pnum]), false); + HU_AddChatText(va("\x82*%s has been kicked (No reason given)", player_names[pnum]), false); kickreason = KR_KICK; break; case KICK_MSG_PING_HIGH: @@ -2969,7 +3327,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) kickreason = KR_PINGLIMIT; break; case KICK_MSG_CON_FAIL: - HU_AddChatText(va("\x82*%s left the game (Synch Failure)", player_names[pnum]), false); + HU_AddChatText(va("\x82*%s left the game (Synch failure)", player_names[pnum]), false); kickreason = KR_SYNCH; if (M_CheckParm("-consisdump")) // Helps debugging some problems @@ -3015,7 +3373,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) kickreason = KR_LEAVE; break; case KICK_MSG_BANNED: - HU_AddChatText(va("\x82*%s has been banned (Don't come back)", player_names[pnum]), false); + HU_AddChatText(va("\x82*%s has been banned (No reason given)", player_names[pnum]), false); kickreason = KR_BAN; break; case KICK_MSG_CUSTOM_KICK: @@ -3032,7 +3390,7 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) if (pnum == consoleplayer) { - LUAh_GameQuit(false); + LUA_HookBool(false, HOOK(GameQuit)); #ifdef DUMPCONSISTENCY if (msg == KICK_MSG_CON_FAIL) SV_SavedGame(); #endif @@ -3074,34 +3432,6 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } -static void Command_ResendGamestate(void) -{ - SINT8 playernum; - - if (COM_Argc() == 1) - { - CONS_Printf(M_GetText("resendgamestate : resend the game state to a player\n")); - return; - } - else if (client) - { - CONS_Printf(M_GetText("Only the server can use this.\n")); - return; - } - - playernum = nametonum(COM_Argv(1)); - if (playernum == -1 || playernum == 0) - return; - - // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on - netbuffer->packettype = PT_WILLRESENDGAMESTATE; - if (!HSendPacket(playernode[playernum], true, 0, 0)) - { - CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); - return; - } -} - static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); @@ -3112,7 +3442,7 @@ consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR, maxpl static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}}; consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL); static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}}; -consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "Off", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL); +consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL); static CV_PossibleValue_t resynchattempts_cons_t[] = {{1, "MIN"}, {20, "MAX"}, {0, "No"}, {0, NULL}}; consvar_t cv_resynchattempts = CVAR_INIT ("resynchattempts", "10", CV_SAVE|CV_NETVAR, resynchattempts_cons_t, NULL); @@ -3124,7 +3454,7 @@ consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_ consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); // Speed of file downloading (in packets per tic) -static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}}; consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL); static void Got_AddPlayer(UINT8 **p, INT32 playernum); @@ -3240,6 +3570,8 @@ void SV_ResetServer(void) // clear server_context memset(server_context, '-', 8); + CV_RevertNetVars(); + DEBFILE("\n-=-=-=-=-=-=-= Server Reset =-=-=-=-=-=-=-\n\n"); } @@ -3265,6 +3597,9 @@ static inline void SV_GenContext(void) // void D_QuitNetGame(void) { + mousegrabbedbylua = true; + I_UpdateMouseGrab(); + if (!netgame || !netbuffer) return; @@ -3452,7 +3787,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); if (!rejoined) - LUAh_PlayerJoin(newplayernum); + LUA_HookInt(newplayernum, HOOK(PlayerJoin)); } static boolean SV_AddWaitingPlayers(const char *name, const char *name2) @@ -3629,6 +3964,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 @@ -3639,33 +4046,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 @@ -3732,7 +4120,7 @@ static void HandleConnect(SINT8 node) static void HandleShutdown(SINT8 node) { (void)node; - LUAh_GameQuit(false); + LUA_HookBool(false, HOOK(GameQuit)); D_QuitNetGame(); CL_Reset(); D_StartTitle(); @@ -3747,7 +4135,7 @@ static void HandleShutdown(SINT8 node) static void HandleTimeout(SINT8 node) { (void)node; - LUAh_GameQuit(false); + LUA_HookBool(false, HOOK(GameQuit)); D_QuitNetGame(); CL_Reset(); D_StartTitle(); @@ -3780,6 +4168,7 @@ static void HandleServerInfo(SINT8 node) static void PT_WillResendGamestate(void) { +#ifndef NONET char tmpsave[256]; if (server || cl_redownloadinggamestate) @@ -3802,10 +4191,12 @@ static void PT_WillResendGamestate(void) CL_PrepareDownloadSaveGame(tmpsave); cl_redownloadinggamestate = true; +#endif } static void PT_CanReceiveGamestate(SINT8 node) { +#ifndef NONET if (client || sendingsavegame[node]) return; @@ -3813,6 +4204,9 @@ static void PT_CanReceiveGamestate(SINT8 node) SV_SendSaveGame(node, true); // Resend a complete game state resendingsavegame[node] = true; +#else + (void)node; +#endif } /** Handles a packet received from a node that isn't in game @@ -3839,31 +4233,40 @@ static void HandlePacketFromAwayNode(SINT8 node) switch (netbuffer->packettype) { case PT_ASKINFOVIAMS: -#if 0 + Net_CloseConnection(node); + break; + + case PT_TELLFILESNEEDED: if (server && serverrunning) { - INT32 clientnode; - if (ms_RoomId < 0) // ignore if we're not actually on the MS right now - { - Net_CloseConnection(node); // and yes, close connection - return; - } - clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr); - if (clientnode != -1) - { - SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time)); - SV_SendPlayerInfo(clientnode); // Send extra info - Net_CloseConnection(clientnode); - // Don't close connection to MS... - } - else - Net_CloseConnection(node); // ...unless the IP address is not valid + UINT8 *p; + INT32 firstfile = netbuffer->u.filesneedednum; + + netbuffer->packettype = PT_MOREFILESNEEDED; + netbuffer->u.filesneededcfg.first = firstfile; + netbuffer->u.filesneededcfg.more = 0; + + p = PutFileNeeded(firstfile); + + HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u)); + } + else // Shouldn't get this if you aren't the server...? + Net_CloseConnection(node); + break; + + case PT_MOREFILESNEEDED: + if (server && serverrunning) + { // But wait I thought I'm the server? + Net_CloseConnection(node); + break; + } + SERVERONLY + if (cl_mode == CL_ASKFULLFILELIST && netbuffer->u.filesneededcfg.first == fileneedednum) + { + D_ParseFileneeded(netbuffer->u.filesneededcfg.num, netbuffer->u.filesneededcfg.files, netbuffer->u.filesneededcfg.first); + if (!netbuffer->u.filesneededcfg.more) + cl_lastcheckedfilecount = UINT16_MAX; // Got the whole file list } - else - Net_CloseConnection(node); // you're not supposed to get it, so ignore it -#else - Net_CloseConnection(node); -#endif break; case PT_ASKINFO: @@ -3889,13 +4292,24 @@ static void HandlePacketFromAwayNode(SINT8 node) if (!reason) I_Error("Out of memory!\n"); - D_QuitNetGame(); - CL_Reset(); - D_StartTitle(); + if (strstr(reason, "Maximum players reached")) + { + serverisfull = true; + //Special timeout for when refusing due to player cap. The client will wait 3 seconds between join requests when waiting for a slot, so we need this to be much longer + //We set it back to the value of cv_nettimeout.value in CL_Reset + connectiontimeout = NEWTICRATE*7; + cl_mode = CL_ASKJOIN; + free(reason); + break; + } M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"), reason), NULL, MM_NOTHING); + D_QuitNetGame(); + CL_Reset(); + D_StartTitle(); + free(reason); // Will be reset by caller. Signals refusal. @@ -4099,8 +4513,10 @@ static void HandlePacketFromPlayer(SINT8 node) // Check player consistancy during the level if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) - && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() - && !SV_ResendingSavegameToAnyone()) +#ifndef NONET + && !SV_ResendingSavegameToAnyone() +#endif + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime()) { if (cv_resynchattempts.value) { @@ -4268,7 +4684,7 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_RECEIVEDGAMESTATE: sendingsavegame[node] = false; resendingsavegame[node] = false; - savegameresendcooldown[node] = I_GetTime() + 15 * TICRATE; + savegameresendcooldown[node] = I_GetTime() + 5 * TICRATE; break; // -------------------------------------------- CLIENT RECEIVE ---------- case PT_SERVERTICS: @@ -4480,70 +4896,73 @@ static INT16 Consistancy(void) ret += P_GetRandSeed(); #ifdef MOBJCONSISTANCY - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + if (gamestate == GS_LEVEL) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo = (mobj_t *)th; - - if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY)) + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { - ret -= mo->type; - ret += mo->x; - ret -= mo->y; - ret += mo->z; - ret -= mo->momx; - ret += mo->momy; - ret -= mo->momz; - ret += mo->angle; - ret -= mo->flags; - ret += mo->flags2; - ret -= mo->eflags; - if (mo->target) + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo = (mobj_t *)th; + + if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY)) { - ret += mo->target->type; - ret -= mo->target->x; - ret += mo->target->y; - ret -= mo->target->z; - ret += mo->target->momx; - ret -= mo->target->momy; - ret += mo->target->momz; - ret -= mo->target->angle; - ret += mo->target->flags; - ret -= mo->target->flags2; - ret += mo->target->eflags; - ret -= mo->target->state - states; - ret += mo->target->tics; - ret -= mo->target->sprite; - ret += mo->target->frame; + ret -= mo->type; + ret += mo->x; + ret -= mo->y; + ret += mo->z; + ret -= mo->momx; + ret += mo->momy; + ret -= mo->momz; + ret += mo->angle; + ret -= mo->flags; + ret += mo->flags2; + ret -= mo->eflags; + if (mo->target) + { + ret += mo->target->type; + ret -= mo->target->x; + ret += mo->target->y; + ret -= mo->target->z; + ret += mo->target->momx; + ret -= mo->target->momy; + ret += mo->target->momz; + ret -= mo->target->angle; + ret += mo->target->flags; + ret -= mo->target->flags2; + ret += mo->target->eflags; + ret -= mo->target->state - states; + ret += mo->target->tics; + ret -= mo->target->sprite; + ret += mo->target->frame; + } + else + ret ^= 0x3333; + if (mo->tracer && mo->tracer->type != MT_OVERLAY) + { + ret += mo->tracer->type; + ret -= mo->tracer->x; + ret += mo->tracer->y; + ret -= mo->tracer->z; + ret += mo->tracer->momx; + ret -= mo->tracer->momy; + ret += mo->tracer->momz; + ret -= mo->tracer->angle; + ret += mo->tracer->flags; + ret -= mo->tracer->flags2; + ret += mo->tracer->eflags; + ret -= mo->tracer->state - states; + ret += mo->tracer->tics; + ret -= mo->tracer->sprite; + ret += mo->tracer->frame; + } + else + ret ^= 0xAAAA; + ret -= mo->state - states; + ret += mo->tics; + ret -= mo->sprite; + ret += mo->frame; } - else - ret ^= 0x3333; - if (mo->tracer && mo->tracer->type != MT_OVERLAY) - { - ret += mo->tracer->type; - ret -= mo->tracer->x; - ret += mo->tracer->y; - ret -= mo->tracer->z; - ret += mo->tracer->momx; - ret -= mo->tracer->momy; - ret += mo->tracer->momz; - ret -= mo->tracer->angle; - ret += mo->tracer->flags; - ret -= mo->tracer->flags2; - ret += mo->tracer->eflags; - ret -= mo->tracer->state - states; - ret += mo->tracer->tics; - ret -= mo->tracer->sprite; - ret += mo->tracer->frame; - } - else - ret ^= 0xAAAA; - ret -= mo->state - states; - ret += mo->tics; - ret -= mo->sprite; - ret += mo->frame; } } #endif @@ -4848,16 +5267,23 @@ void TryRunTics(tic_t realtics) // run the count * tics while (neededtic > gametic) { + boolean update_stats = !(paused || P_AutoPause()); + DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); - ps_tictime = I_GetPreciseTime(); + if (update_stats) + PS_START_TIMING(ps_tictime); G_Ticker((gametic % NEWTICRATERATIO) == 0); ExtraDataTicker(); gametic++; consistancy[gametic%BACKUPTICS] = Consistancy(); - ps_tictime = I_GetPreciseTime() - ps_tictime; + if (update_stats) + { + PS_STOP_TIMING(ps_tictime); + PS_UpdateTickStats(); + } // Leave a certain amount of tics present in the net buffer as long as we've ran at least one tic this frame. if (client && gamestate == GS_LEVEL && leveltime > 3 && neededtic <= gametic + cv_netticbuffer.value) @@ -5001,9 +5427,11 @@ void NetUpdate(void) if (client) { +#ifndef NONET // If the client just finished redownloading the game state, load it if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) CL_ReloadReceivedSavegame(); +#endif CL_SendClientCmd(); // Send tic cmd hu_redownloadinggamestate = cl_redownloadinggamestate; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 3d67525da..bf3f0b64f 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -22,11 +22,15 @@ #include "mserv.h" /* -The 'packet version' is used to distinguish packet formats. -This version is independent of VERSION and SUBVERSION. Different -applications may follow different packet versions. +The 'packet version' is used to distinguish packet +formats. This version is independent of VERSION and +SUBVERSION. Different applications may follow different +packet versions. + +If you change the struct or the meaning of a field +therein, increment this number. */ -#define PACKETVERSION 3 +#define PACKETVERSION 4 // Network play related stuff. // There is a data struct that stores network @@ -90,6 +94,9 @@ typedef enum PT_LOGIN, // Login attempt from the client. + PT_TELLFILESNEEDED, // Client, to server: "what other files do I need starting from this number?" + PT_MOREFILESNEEDED, // Server, to client: "you need these (+ more on top of those)" + PT_PING, // Packet sent to tell clients the other client's latency to server. NUMPACKETTYPE } packettype_t; @@ -141,9 +148,6 @@ typedef struct typedef struct { - UINT8 version; // Different versions don't work - UINT8 subversion; // Contains build version - // Server launch stuffs UINT8 serverplayer; UINT8 totalslotnum; // "Slots": highest player number in use plus one. @@ -190,16 +194,22 @@ typedef struct typedef struct { - UINT8 _255;/* see serverinfo_pak */ - UINT8 packetversion; + UINT8 modversion; char application[MAXAPPLICATION]; - UINT8 version; // Different versions don't work - UINT8 subversion; // Contains build version UINT8 localplayers; UINT8 mode; char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME]; } ATTRPACK clientconfig_pak; +#define SV_DEDICATED 0x40 // server is dedicated +#define SV_LOTSOFADDONS 0x20 // flag used to ask for full file list in d_netfil + +enum { + REFUSE_JOINS_DISABLED = 1, + REFUSE_SLOTS_FULL, + REFUSE_BANNED, +}; + #define MAXSERVERNAME 32 #define MAXFILENEEDED 915 // This packet is too large @@ -217,11 +227,11 @@ typedef struct UINT8 subversion; UINT8 numberofplayer; UINT8 maxplayer; - UINT8 refusereason; // 0: joinable, 1: joins disabled, 2: full + UINT8 refusereason; // 0: joinable, REFUSE enum char gametypename[24]; UINT8 modifiedgame; UINT8 cheatsenabled; - UINT8 isdedicated; + UINT8 flags; UINT8 fileneedednum; tic_t time; tic_t leveltime; @@ -275,6 +285,14 @@ typedef struct UINT8 ctfteam; } ATTRPACK plrconfig; +typedef struct +{ + INT32 first; + UINT8 num; + UINT8 more; + UINT8 files[MAXFILENEEDED]; // is filled with writexxx (byteptr.h) +} ATTRPACK filesneededconfig_pak; + // // Network packet data // @@ -304,6 +322,8 @@ typedef struct msaskinfo_pak msaskinfo; // 22 bytes plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) + INT32 filesneedednum; // 4 bytes + filesneededconfig_pak filesneededcfg; // ??? bytes UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes } u; // This is needed to pack diff packet types data together } ATTRPACK doomdata_t; @@ -401,6 +421,7 @@ void CL_Reset(void); void CL_ClearPlayer(INT32 playernum); void CL_QueryServerList(msg_server_t *list); void CL_UpdateServerList(boolean internetsearch, INT32 room); +void CL_RemovePlayer(INT32 playernum, kickreason_t reason); // Is there a game running boolean Playing(void); diff --git a/src/d_event.h b/src/d_event.h index 3cce8fad1..c0b9cef77 100644 --- a/src/d_event.h +++ b/src/d_event.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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 a89f4ed2d..fa9e21337 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,7 +15,7 @@ /// plus functions to parse command line parameters, configure game /// parameters, and call the startup functions. -#if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) +#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) #include #include #endif @@ -61,11 +61,11 @@ #include "p_local.h" // chasecam #include "mserv.h" // ms_RoomId #include "m_misc.h" // screenshot functionality -#include "dehacked.h" // Dehacked list test +#include "deh_tables.h" // Dehacked list test #include "m_cond.h" // condition initialization #include "fastcmp.h" #include "keys.h" -#include "filesrch.h" // refreshdirmenu, mainwadstally +#include "filesrch.h" // refreshdirmenu #include "g_input.h" // tutorial mode control scheming #include "m_perfstats.h" @@ -96,11 +96,8 @@ int SUBVERSION; // platform independant focus loss UINT8 window_notinfocus = false; -// -// DEMO LOOP -// -static char *startupwadfiles[MAX_WADFILES]; -static char *startuppwads[MAX_WADFILES]; +static addfilelist_t startupwadfiles; +static addfilelist_t startuppwads; boolean devparm = false; // started game with -devparm @@ -119,6 +116,9 @@ boolean midi_disabled = false; boolean sound_disabled = false; boolean digital_disabled = false; +// +// DEMO LOOP +// boolean advancedemo; #ifdef DEBUGFILE INT32 debugload = 0; @@ -175,10 +175,53 @@ void D_ProcessEvents(void) boolean eaten; + // Reset possibly stale mouse info + G_SetMouseDeltas(0, 0, 1); + G_SetMouseDeltas(0, 0, 2); + mouse.buttons &= ~(MB_SCROLLUP|MB_SCROLLDOWN); + mouse2.buttons &= ~(MB_SCROLLUP|MB_SCROLLDOWN); + for (; eventtail != eventhead; eventtail = (eventtail+1) & (MAXEVENTS-1)) { + boolean hooked = false; + ev = &events[eventtail]; + // Set mouse buttons early in case event is eaten later + if (ev->type == ev_keydown || ev->type == ev_keyup) + { + // Mouse buttons + if ((UINT32)(ev->key - KEY_MOUSE1) < MOUSEBUTTONS) + { + if (ev->type == ev_keydown) + mouse.buttons |= 1 << (ev->key - KEY_MOUSE1); + else + mouse.buttons &= ~(1 << (ev->key - KEY_MOUSE1)); + } + else if ((UINT32)(ev->key - KEY_2MOUSE1) < MOUSEBUTTONS) + { + if (ev->type == ev_keydown) + mouse2.buttons |= 1 << (ev->key - KEY_2MOUSE1); + else + mouse2.buttons &= ~(1 << (ev->key - KEY_2MOUSE1)); + } + // Scroll (has no keyup event) + else switch (ev->key) { + case KEY_MOUSEWHEELUP: + mouse.buttons |= MB_SCROLLUP; + break; + case KEY_MOUSEWHEELDOWN: + mouse.buttons |= MB_SCROLLDOWN; + break; + case KEY_2MOUSEWHEELUP: + mouse2.buttons |= MB_SCROLLUP; + break; + case KEY_2MOUSEWHEELDOWN: + mouse2.buttons |= MB_SCROLLDOWN; + break; + } + } + // Screenshots over everything so that they can be taken anywhere. if (M_ScreenshotResponder(ev)) continue; // ate the event @@ -189,6 +232,12 @@ void D_ProcessEvents(void) continue; } + if (!CON_Ready() && !menuactive) { + if (G_LuaResponder(ev)) + continue; + hooked = true; + } + // Menu input #ifdef HAVE_THREADS I_lock_mutex(&m_menu_mutex); @@ -203,6 +252,12 @@ void D_ProcessEvents(void) if (eaten) continue; // menu ate the event + if (!hooked && !CON_Ready()) { + if (G_LuaResponder(ev)) + continue; + hooked = true; + } + // console input #ifdef HAVE_THREADS I_lock_mutex(&con_mutex); @@ -217,8 +272,16 @@ void D_ProcessEvents(void) if (eaten) continue; // ate the event + if (!hooked && !CON_Ready() && G_LuaResponder(ev)) + continue; + G_Responder(ev); } + + if (mouse.rdx || mouse.rdy) + G_SetMouseDeltas(mouse.rdx, mouse.rdy, 1); + if (mouse2.rdx || mouse2.rdy) + G_SetMouseDeltas(mouse2.rdx, mouse2.rdy, 2); } // @@ -413,7 +476,7 @@ static void D_Display(void) if (!automapactive && !dedicated && cv_renderview.value) { - ps_rendercalltime = I_GetPreciseTime(); + PS_START_TIMING(ps_rendercalltime); if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { topleft = screens[0] + viewwindowy*vid.width + viewwindowx; @@ -460,7 +523,7 @@ static void D_Display(void) if (postimgtype2) V_DoPostProcessor(1, postimgtype2, postimgparam2); } - ps_rendercalltime = I_GetPreciseTime() - ps_rendercalltime; + PS_STOP_TIMING(ps_rendercalltime); } if (lastdraw) @@ -474,7 +537,7 @@ static void D_Display(void) lastdraw = false; } - ps_uitime = I_GetPreciseTime(); + PS_START_TIMING(ps_uitime); if (gamestate == GS_LEVEL) { @@ -487,7 +550,7 @@ static void D_Display(void) } else { - ps_uitime = I_GetPreciseTime(); + PS_START_TIMING(ps_uitime); } } @@ -529,7 +592,7 @@ static void D_Display(void) CON_Drawer(); - ps_uitime = I_GetPreciseTime() - ps_uitime; + PS_STOP_TIMING(ps_uitime); // // wipe update @@ -615,9 +678,9 @@ static void D_Display(void) M_DrawPerfStats(); } - ps_swaptime = I_GetPreciseTime(); + PS_START_TIMING(ps_swaptime); I_FinishUpdate(); // page flip or blit buffer - ps_swaptime = I_GetPreciseTime() - ps_swaptime; + PS_STOP_TIMING(ps_swaptime); } } @@ -860,35 +923,68 @@ void D_StartTitle(void) tutorialmode = false; } -// -// D_AddFile -// -static void D_AddFile(char **list, const char *file) -{ - size_t pnumwadfiles; - char *newfile; +#define REALLOC_FILE_LIST \ + if (list->files == NULL) \ + { \ + list->files = calloc(sizeof(list->files), 2); \ + list->numfiles = 1; \ + } \ + else \ + { \ + index = list->numfiles; \ + list->files = realloc(list->files, sizeof(list->files) * ((++list->numfiles) + 1)); \ + if (list->files == NULL) \ + I_Error("%s: No more free memory to add file %s", __FUNCTION__, file); \ + } - for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) - ; +static void D_AddFile(addfilelist_t *list, const char *file) +{ + char *newfile; + size_t index = 0; + + REALLOC_FILE_LIST newfile = malloc(strlen(file) + 1); if (!newfile) - { - I_Error("No more free memory to AddFile %s",file); - } - strcpy(newfile, file); + I_Error("D_AddFile: No more free memory to add file %s", file); - list[pnumwadfiles] = newfile; + strcpy(newfile, file); + list->files[index] = newfile; } -static inline void D_CleanFile(char **list) +static void D_AddFolder(addfilelist_t *list, const char *file) { - size_t pnumwadfiles; - for (pnumwadfiles = 0; list[pnumwadfiles]; pnumwadfiles++) + char *newfile; + size_t index = 0; + + REALLOC_FILE_LIST + + newfile = malloc(strlen(file) + 2); // Path delimiter + NULL terminator + if (!newfile) + I_Error("D_AddFolder: No more free memory to add folder %s", file); + + strcpy(newfile, file); + strcat(newfile, PATHSEP); + + list->files[index] = newfile; +} + +#undef REALLOC_FILE_LIST + +static inline void D_CleanFile(addfilelist_t *list) +{ + if (list->files) { - free(list[pnumwadfiles]); - list[pnumwadfiles] = NULL; + size_t pnumwadfiles = 0; + + for (; pnumwadfiles < list->numfiles; pnumwadfiles++) + free(list->files[pnumwadfiles]); + + free(list->files); + list->files = NULL; } + + list->numfiles = 0; } ///\brief Checks if a netgame URL is being handled, and changes working directory to the EXE's if so. @@ -934,7 +1030,7 @@ static void IdentifyVersion(void) char *srb2wad; const char *srb2waddir = NULL; -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) +#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) // change to the directory where 'srb2.pk3' is found srb2waddir = I_LocateWad(); #endif @@ -972,7 +1068,7 @@ static void IdentifyVersion(void) // Load the IWAD if (srb2wad != NULL && FIL_ReadFileOK(srb2wad)) - D_AddFile(startupwadfiles, srb2wad); + D_AddFile(&startupwadfiles, srb2wad); else I_Error("srb2.pk3 not found! Expected in %s, ss file: %s\n", srb2waddir, srb2wad); @@ -983,14 +1079,14 @@ static void IdentifyVersion(void) // checking in D_SRB2Main // Add the maps - D_AddFile(startupwadfiles, va(pandf,srb2waddir,"zones.pk3")); + D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "zones.pk3")); // Add the players - D_AddFile(startupwadfiles, va(pandf,srb2waddir, "player.dta")); + D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "player.dta")); #ifdef USE_PATCH_DTA // Add our crappy patches to fix our bugs - D_AddFile(startupwadfiles, va(pandf,srb2waddir,"patch.pk3")); + D_AddFile(&startupwadfiles, va(pandf,srb2waddir, "patch.pk3")); #endif #if !defined (HAVE_SDL) || defined (HAVE_MIXER) @@ -1000,16 +1096,13 @@ static void IdentifyVersion(void) const char *musicpath = va(pandf,srb2waddir,str);\ int ms = W_VerifyNMUSlumps(musicpath, false); \ if (ms == 1) \ - D_AddFile(startupwadfiles, musicpath); \ + D_AddFile(&startupwadfiles, musicpath); \ else if (ms == 0) \ I_Error("File "str" has been modified with non-music/sound lumps"); \ } MUSICTEST("music.dta") - MUSICTEST("patch_music.pk3") -#ifdef DEVELOP // remove when music_new.dta is merged into music.dta - MUSICTEST("music_new.dta") -#endif + //MUSICTEST("patch_music.pk3") } #endif } @@ -1045,7 +1138,7 @@ void D_SRB2Main(void) // Print GPL notice for our console users (Linux) CONS_Printf( "\n\nSonic Robo Blast 2\n" - "Copyright (C) 1998-2020 by Sonic Team Junior\n\n" + "Copyright (C) 1998-2022 by Sonic Team Junior\n\n" "This program comes with ABSOLUTELY NO WARRANTY.\n\n" "This is free software, and you are welcome to redistribute it\n" "and/or modify it under the terms of the GNU General Public License\n" @@ -1072,7 +1165,7 @@ void D_SRB2Main(void) G_LoadGameSettings(); // Test Dehacked lists - DEH_Check(); + DEH_TableCheck(); // Netgame URL special case: change working dir to EXE folder. ChangeDirForUrlHandler(); @@ -1107,7 +1200,7 @@ void D_SRB2Main(void) if (!userhome) { -#if ((defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON)) && !defined (__CYGWIN__) +#if (defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)) && !defined (__CYGWIN__) I_Error("Please set $HOME to your home directory\n"); #else if (dedicated) @@ -1174,21 +1267,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]); } } @@ -1227,8 +1324,8 @@ void D_SRB2Main(void) // load wad, including the main wad file CONS_Printf("W_InitMultipleFiles(): Adding IWAD and main PWADs.\n"); - W_InitMultipleFiles(startupwadfiles); - D_CleanFile(startupwadfiles); + W_InitMultipleFiles(&startupwadfiles); + D_CleanFile(&startupwadfiles); #ifndef DEVELOP // md5s last updated 22/02/20 (ddmmyy) @@ -1243,8 +1340,6 @@ void D_SRB2Main(void) // ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for. #endif //ifndef DEVELOP - mainwadstally = packetsizetally; // technically not accurate atm, remember to port the two-stage -file process from kart in 2.2.x - cht_Init(); //---------------------------------------------------- READY SCREEN @@ -1275,9 +1370,16 @@ void D_SRB2Main(void) I_RegisterSysCommands(); - CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n"); - W_InitMultipleFiles(startuppwads); - D_CleanFile(startuppwads); + CON_StopRefresh(); // Temporarily stop refreshing the screen for wad loading + + if (startuppwads.numfiles) + { + CONS_Printf("W_InitMultipleFiles(): Adding extra PWADs.\n"); + W_InitMultipleFiles(&startuppwads); + D_CleanFile(&startuppwads); + } + + CON_StartRefresh(); // Restart the refresh! CONS_Printf("HU_LoadGraphics()...\n"); HU_LoadGraphics(); @@ -1287,7 +1389,7 @@ void D_SRB2Main(void) G_LoadGameData(); -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) +#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) VID_PrepareModeList(); // Regenerate Modelist according to cv_fullscreen #endif @@ -1553,7 +1655,7 @@ const char *D_Home(void) userhome = M_GetNextParm(); else { -#if !((defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON)) && !defined (__APPLE__) +#if !(defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)) if (FIL_FileOK(CONFIGFILENAME)) usehome = false; // Let's NOT use home else diff --git a/src/d_main.h b/src/d_main.h index 81de0634d..8189a9f2b 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -40,10 +40,6 @@ void D_SRB2Main(void); // Called by IO functions when input is detected. void D_PostEvent(const event_t *ev); -#if defined (PC_DOS) && !defined (DOXYGEN) -void D_PostEvent_end(void); // delimiter for locking memory -#endif - void D_ProcessEvents(void); const char *D_Home(void); diff --git a/src/d_net.c b/src/d_net.c index d534b1b08..5e5c10889 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -815,6 +815,8 @@ static const char *packettypename[NUMPACKETTYPE] = "CLIENTJOIN", "NODETIMEOUT", "LOGIN", + "TELLFILESNEEDED", + "MOREFILESNEEDED", "PING" }; @@ -1142,8 +1144,9 @@ boolean HGetPacket(void) if (netbuffer->checksum != NetbufferChecksum()) { DEBFILE("Bad packet checksum\n"); - //Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode); - Net_CloseConnection(doomcom->remotenode); + // Do not disconnect or anything, just ignore the packet. + // Bad checksums with UDP tend to happen very scarcely + // so they are not normally an issue. continue; } diff --git a/src/d_net.h b/src/d_net.h index ea6b5d4d9..5baa593a0 100644 --- a/src/d_net.h +++ b/src/d_net.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0acbec928..1733d3324 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -47,6 +47,7 @@ #include "m_cond.h" #include "m_anigif.h" #include "md5.h" +#include "m_perfstats.h" #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR @@ -63,7 +64,9 @@ static void Got_WeaponPref(UINT8 **cp, INT32 playernum); static void Got_Mapcmd(UINT8 **cp, INT32 playernum); static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum); static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum); +static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum); static void Got_Addfilecmd(UINT8 **cp, INT32 playernum); +static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum); static void Got_Pause(UINT8 **cp, INT32 playernum); static void Got_Suicide(UINT8 **cp, INT32 playernum); static void Got_RandomSeed(UINT8 **cp, INT32 playernum); @@ -115,6 +118,7 @@ static void Command_Map_f(void); static void Command_ResetCamera_f(void); static void Command_Addfile(void); +static void Command_Addfolder(void); static void Command_ListWADS_f(void); static void Command_RunSOC(void); static void Command_Pause(void); @@ -168,7 +172,7 @@ void SendWeaponPref(void); void SendWeaponPref2(void); static CV_PossibleValue_t usemouse_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Force"}, {0, NULL}}; -#if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) +#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) static CV_PossibleValue_t mouse2port_cons_t[] = {{0, "/dev/gpmdata"}, {1, "/dev/ttyS0"}, {2, "/dev/ttyS1"}, {3, "/dev/ttyS2"}, {4, "/dev/ttyS3"}, {0, NULL}}; #else @@ -255,7 +259,7 @@ consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_CALL, NULL, I_J consvar_t cv_joyscale = CVAR_INIT ("padscale", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save consvar_t cv_joyscale2 = CVAR_INIT ("padscale2", "1", CV_SAVE|CV_HIDEN, NULL, NULL); //Alam: Dummy for save #endif -#if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) +#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) consvar_t cv_mouse2port = CVAR_INIT ("mouse2port", "/dev/gpmdata", CV_SAVE, mouse2port_cons_t, NULL); consvar_t cv_mouse2opt = CVAR_INIT ("mouse2opt", "0", CV_SAVE, NULL, NULL); #else @@ -284,7 +288,7 @@ consvar_t cv_gravity = CVAR_INIT ("gravity", "0.5", CV_RESTRICT|CV_FLOAT|CV_CALL consvar_t cv_soundtest = CVAR_INIT ("soundtest", "0", CV_CALL, NULL, SoundTest_OnChange); -static CV_PossibleValue_t minitimelimit_cons_t[] = {{15, "MIN"}, {9999, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t minitimelimit_cons_t[] = {{1, "MIN"}, {9999, "MAX"}, {0, NULL}}; consvar_t cv_countdowntime = CVAR_INIT ("countdowntime", "60", CV_SAVE|CV_NETVAR|CV_CHEAT, minitimelimit_cons_t, NULL); consvar_t cv_touchtag = CVAR_INIT ("touchtag", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL); @@ -371,7 +375,14 @@ consvar_t cv_sleep = CVAR_INIT ("cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL) static CV_PossibleValue_t perfstats_cons_t[] = { {0, "Off"}, {1, "Rendering"}, {2, "Logic"}, {3, "ThinkFrame"}, {0, NULL}}; -consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NULL); +consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", CV_CALL, perfstats_cons_t, PS_PerfStats_OnChange); +static CV_PossibleValue_t ps_samplesize_cons_t[] = { + {1, "MIN"}, {1000, "MAX"}, {0, NULL}}; +consvar_t cv_ps_samplesize = CVAR_INIT ("ps_samplesize", "1", CV_CALL, ps_samplesize_cons_t, PS_SampleSize_OnChange); +static CV_PossibleValue_t ps_descriptor_cons_t[] = { + {1, "Average"}, {2, "SD"}, {3, "Minimum"}, {4, "Maximum"}, {0, NULL}}; +consvar_t cv_ps_descriptor = CVAR_INIT ("ps_descriptor", "Average", 0, ps_descriptor_cons_t, NULL); + consvar_t cv_freedemocamera = CVAR_INIT("freedemocamera", "Off", CV_SAVE, CV_OnOff, NULL); char timedemo_name[256]; @@ -398,16 +409,16 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "MAP", "EXITLEVEL", "ADDFILE", + "ADDFOLDER", "PAUSE", "ADDPLAYER", "TEAMCHANGE", "CLEARSCORES", - "LOGIN", "VERIFIED", "RANDOMSEED", "RUNSOC", "REQADDFILE", - "DELFILE", // replace next time we add an XD + "REQADDFOLDER", "SETMOTD", "SUICIDE", "LUACMD", @@ -441,7 +452,9 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_MAP, Got_Mapcmd); RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd); RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd); + RegisterNetXCmd(XD_ADDFOLDER, Got_Addfoldercmd); RegisterNetXCmd(XD_REQADDFILE, Got_RequestAddfilecmd); + RegisterNetXCmd(XD_REQADDFOLDER, Got_RequestAddfoldercmd); RegisterNetXCmd(XD_PAUSE, Got_Pause); RegisterNetXCmd(XD_SUICIDE, Got_Suicide); RegisterNetXCmd(XD_RUNSOC, Got_RunSOCcmd); @@ -472,6 +485,7 @@ void D_RegisterServerCommands(void) COM_AddCommand("showmap", Command_Showmap_f); COM_AddCommand("mapmd5", Command_Mapmd5_f); + COM_AddCommand("addfolder", Command_Addfolder); COM_AddCommand("addfile", Command_Addfile); COM_AddCommand("listwad", Command_ListWADS_f); @@ -788,7 +802,7 @@ void D_RegisterClientCommands(void) // WARNING: the order is important when initialising mouse2 // we need the mouse2port CV_RegisterVar(&cv_mouse2port); -#if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) +#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) CV_RegisterVar(&cv_mouse2opt); #endif CV_RegisterVar(&cv_controlperkey); @@ -861,10 +875,12 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_soundtest); CV_RegisterVar(&cv_perfstats); + CV_RegisterVar(&cv_ps_samplesize); + CV_RegisterVar(&cv_ps_descriptor); // ingame object placing COM_AddCommand("objectplace", Command_ObjectPlace_f); - COM_AddCommand("writethings", Command_Writethings_f); + //COM_AddCommand("writethings", Command_Writethings_f); CV_RegisterVar(&cv_speed); CV_RegisterVar(&cv_opflags); CV_RegisterVar(&cv_ophoopflags); @@ -1313,8 +1329,9 @@ static void SendNameAndColor(void) cv_skin.value = R_SkinAvailable(cv_skin.string); if ((cv_skin.value < 0) || !R_SkinUsable(consoleplayer, cv_skin.value)) { - CV_StealthSet(&cv_skin, DEFAULTSKIN); - cv_skin.value = 0; + INT32 defaultSkinNum = GetPlayerDefaultSkin(consoleplayer); + CV_StealthSet(&cv_skin, skins[defaultSkinNum].name); + cv_skin.value = defaultSkinNum; } // Finally write out the complete packet and send it off. @@ -1475,7 +1492,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) if (server && (p != &players[consoleplayer] && p != &players[secondarydisplayplayer])) { boolean kick = false; - INT32 s; + UINT32 unlockShift = 0; + UINT32 i; // team colors if (G_GametypeHasTeams()) @@ -1491,12 +1509,29 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) kick = true; // availabilities - for (s = 0; s < MAXSKINS; s++) + for (i = 0; i < MAXUNLOCKABLES; i++) { - if (!skins[s].availability && (p->availabilities & (1 << s))) + if (unlockables[i].type != SECRET_SKIN) + { + continue; + } + + unlockShift++; + } + + // If they set an invalid bit to true, then likely a modified client + if (unlockShift < 32) // 32 is the max the data type allows + { + UINT32 illegalMask = UINT32_MAX; + + for (i = 0; i < unlockShift; i++) + { + illegalMask &= ~(1 << i); + } + + if ((p->availabilities & illegalMask) != 0) { kick = true; - break; } } @@ -2098,7 +2133,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) } mapnumber = M_MapNumber(mapname[3], mapname[4]); - LUAh_MapChange(mapnumber); + LUA_HookInt(mapnumber, HOOK(MapChange)); G_InitNew(ultimatemode, mapname, resetplayer, skipprecutscene, FLS); if (demoplayback && !timingdemo) @@ -2130,7 +2165,7 @@ static void Command_Pause(void) if (cv_pause.value || server || (IsPlayerAdmin(consoleplayer))) { - if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)) + if (modeattacking || !(gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) || (marathonmode && gamestate == GS_INTERMISSION)) { CONS_Printf(M_GetText("You can't pause here.\n")); return; @@ -2683,7 +2718,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } // Don't switch team, just go away, please, go awaayyyy, aaauuauugghhhghgh - if (!LUAh_TeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled)) + if (!LUA_HookTeamSwitch(&players[playernum], NetPacket.packet.newteam, players[playernum].spectator, NetPacket.packet.autobalance, NetPacket.packet.scrambled)) return; //no status changes after hidetime @@ -2844,7 +2879,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. if (displayplayer != consoleplayer) // You're already viewing yourself. No big deal. - LUAh_ViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); + LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -3198,7 +3233,7 @@ static void Command_RunSOC(void) static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum) { char filename[256]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; if (playernum != serverplayer && !IsPlayerAdmin(playernum)) { @@ -3322,10 +3357,9 @@ static void Command_Addfile(void) break; ++p; - // check total packet size and no of files currently loaded + // check no of files currently loaded // See W_LoadWadFile in w_wad.c - if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + nameonlylength(fn) + 22) > MAXFILENEEDED*sizeof(UINT8))) + if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); return; @@ -3354,6 +3388,9 @@ static void Command_Addfile(void) for (i = 0; i < numwadfiles; i++) { + if (wadfiles[i]->type == RET_FOLDER) + continue; + if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) { CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn); @@ -3373,10 +3410,142 @@ static void Command_Addfile(void) } } +static void Command_Addfolder(void) +{ + size_t argc = COM_Argc(); // amount of arguments total + size_t curarg; // current argument index + + const char *addedfolders[argc]; // list of filenames already processed + size_t numfoldersadded = 0; // the amount of filenames processed + + if (argc < 2) + { + CONS_Printf(M_GetText("addfolder [path2...] [...]: Load add-ons\n")); + return; + } + + // start at one to skip command name + for (curarg = 1; curarg < argc; curarg++) + { + const char *fn, *p; + char *fullpath; + char buf[256]; + char *buf_p = buf; + INT32 i, stat; + size_t ii; + boolean folderadded = false; + + fn = COM_Argv(curarg); + + // For the amount of filenames previously processed... + for (ii = 0; ii < numfoldersadded; ii++) + { + // If this is one of them, don't try to add it. + if (!strcmp(fn, addedfolders[ii])) + { + folderadded = true; + break; + } + } + + // If we've added this one, skip to the next one. + if (folderadded) + { + CONS_Alert(CONS_WARNING, M_GetText("Already processed %s, skipping\n"), fn); + continue; + } + + // Disallow non-printing characters and semicolons. + for (i = 0; fn[i] != '\0'; i++) + if (!isprint(fn[i]) || fn[i] == ';') + return; + + // Add file on your client directly if you aren't in a netgame. + if (!(netgame || multiplayer)) + { + P_AddFolder(fn); + addedfolders[numfoldersadded++] = fn; + continue; + } + + p = fn+strlen(fn); + while(--p >= fn) + if (*p == '\\' || *p == '/' || *p == ':') + break; + ++p; + + // Don't add an empty path. + if (M_IsStringEmpty(fn)) + { + CONS_Alert(CONS_WARNING, M_GetText("Folder name is empty, skipping\n")); + continue; + } + + // check no of files currently loaded + // See W_LoadWadFile in w_wad.c + if (numwadfiles >= MAX_WADFILES) + { + CONS_Alert(CONS_ERROR, M_GetText("Too many files loaded to add %s\n"), fn); + return; + } + + // Check if the path is valid. + stat = W_IsPathToFolderValid(fn); + + if (stat == 0) + { + CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn); + continue; + } + else if (stat < 0) + { +#ifndef AVOID_ERRNO + CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s (%s), skipping\n"), fn, strerror(direrror)); +#else + CONS_Alert(CONS_WARNING, M_GetText("Error accessing %s, skipping\n"), fn); +#endif + continue; + } + + // Get the full path for this folder. + fullpath = W_GetFullFolderPath(fn); + + if (fullpath == NULL) + { + CONS_Alert(CONS_WARNING, M_GetText("Path %s is invalid, skipping\n"), fn); + continue; + } + + // Check if the folder is already added. + for (i = 0; i < numwadfiles; i++) + { + if (wadfiles[i]->type != RET_FOLDER) + continue; + + if (samepaths(wadfiles[i]->path, fullpath) > 0) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn); + continue; + } + } + + Z_Free(fullpath); + + addedfolders[numfoldersadded++] = fn; + + WRITESTRINGN(buf_p,p,240); + + if (IsPlayerAdmin(consoleplayer) && (!server)) // Request to add file + SendNetXCmd(XD_REQADDFOLDER, buf, buf_p - buf); + else + SendNetXCmd(XD_ADDFOLDER, buf, buf_p - buf); + } +} + static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) { char filename[241]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; UINT8 md5sum[16]; boolean kick = false; boolean toomany = false; @@ -3401,9 +3570,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) return; } - // See W_LoadWadFile in w_wad.c - if ((numwadfiles >= MAX_WADFILES) - || ((packetsizetally + nameonlylength(filename) + 22) > MAXFILENEEDED*sizeof(UINT8))) + if (numwadfiles >= MAX_WADFILES) toomany = true; else ncs = findfile(filename,md5sum,true); @@ -3433,10 +3600,66 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum) COM_BufAddText(va("addfile %s\n", filename)); } +static void Got_RequestAddfoldercmd(UINT8 **cp, INT32 playernum) +{ + char path[241]; + filestatus_t ncs = FS_NOTCHECKED; + boolean kick = false; + boolean toomany = false; + INT32 i,j; + + READSTRINGN(*cp, path, 240); + + /// \todo Integrity checks. + + // Only the server processes this message. + if (client) + return; + + // Disallow non-printing characters and semicolons. + for (i = 0; path[i] != '\0'; i++) + if (!isprint(path[i]) || path[i] == ';') + kick = true; + + if ((playernum != serverplayer && !IsPlayerAdmin(playernum)) || kick) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]); + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + if (numwadfiles >= MAX_WADFILES) + toomany = true; + else + ncs = findfolder(path); + + if (ncs != FS_FOUND || toomany) + { + char message[256]; + + if (toomany) + sprintf(message, M_GetText("Too many files loaded to add %s\n"), path); + else if (ncs == FS_NOTFOUND) + sprintf(message, M_GetText("The server doesn't have %s\n"), path); + else + sprintf(message, M_GetText("Unknown error finding folder (%s)\n"), path); + + CONS_Printf("%s",message); + + for (j = 0; j < MAXPLAYERS; j++) + if (adminplayers[j]) + COM_BufAddText(va("sayto %d %s", adminplayers[j], message)); + + return; + } + + COM_BufAddText(va("addfolder \"%s\"\n", path)); +} + static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) { char filename[241]; - filestatus_t ncs = FS_NOTFOUND; + filestatus_t ncs = FS_NOTCHECKED; UINT8 md5sum[16]; READSTRINGN(*cp, filename, 240); @@ -3481,20 +3704,71 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum) G_SetGameModified(true); } +static void Got_Addfoldercmd(UINT8 **cp, INT32 playernum) +{ + char path[241]; + filestatus_t ncs = FS_NOTCHECKED; + + READSTRINGN(*cp, path, 240); + + /// \todo Integrity checks. + + if (playernum != serverplayer) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal addfolder command received from %s\n"), player_names[playernum]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + ncs = findfolder(path); + + if (ncs != FS_FOUND || !P_AddFolder(path)) + { + Command_ExitGame_f(); + if (ncs == FS_FOUND) + { + CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), path); + M_StartMessage(va("The server added a folder \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",path), NULL, MM_NOTHING); + } + else if (ncs == FS_NOTFOUND) + { + CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), path); + M_StartMessage(va("The server added a folder \n(%s)\nthat you do not have.\n\nPress ESC\n",path), NULL, MM_NOTHING); + } + else + { + CONS_Printf(M_GetText("Unknown error finding folder (%s) the server added.\n"), path); + M_StartMessage(va("Unknown error trying to load a folder\nthat the server added \n(%s).\n\nPress ESC\n",path), NULL, MM_NOTHING); + } + return; + } + + G_SetGameModified(true); +} + static void Command_ListWADS_f(void) { INT32 i = numwadfiles; char *tempname; - CONS_Printf(M_GetText("There are %d wads loaded:\n"),numwadfiles); + +#ifdef ENFORCE_WAD_LIMIT + CONS_Printf(M_GetText("There are %d/%d files loaded:\n"),numwadfiles,MAX_WADFILES); +#else + CONS_Printf(M_GetText("There are %d files loaded:\n"),numwadfiles); +#endif + for (i--; i >= 0; i--) { nameonly(tempname = va("%s", wadfiles[i]->filename)); if (!i) CONS_Printf("\x82 IWAD\x80: %s\n", tempname); - else if (i <= mainwads) + else if (i < mainwads) 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); } @@ -3607,7 +3881,7 @@ static void Command_Playintro_f(void) */ FUNCNORETURN static ATTRNORETURN void Command_Quit_f(void) { - LUAh_GameQuit(true); + LUA_HookBool(true, HOOK(GameQuit)); I_Quit(); } @@ -4269,7 +4543,7 @@ void Command_ExitGame_f(void) { INT32 i; - LUAh_GameQuit(false); + LUA_HookBool(false, HOOK(GameQuit)); D_QuitNetGame(); CL_Reset(); @@ -4301,7 +4575,7 @@ void Command_Retry_f(void) CONS_Printf(M_GetText("You must be in a level to use this.\n")); else if (netgame || multiplayer) CONS_Printf(M_GetText("This only works in single player.\n")); - else if (!&players[consoleplayer] || players[consoleplayer].lives <= 1) + else if (players[consoleplayer].lives <= 1) CONS_Printf(M_GetText("You can't retry without any lives remaining!\n")); else if (G_IsSpecialStage(gamemap)) CONS_Printf(M_GetText("You can't retry special stages!\n")); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index ac39626a4..0beeae154 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -45,7 +45,7 @@ extern consvar_t cv_joyscale2; // splitscreen with second mouse extern consvar_t cv_mouse2port; extern consvar_t cv_usemouse2; -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) +#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) extern consvar_t cv_mouse2opt; #endif @@ -73,6 +73,7 @@ extern consvar_t cv_teamscramble; extern consvar_t cv_scrambleonchange; extern consvar_t cv_netstat; +extern consvar_t cv_nettimeout; extern consvar_t cv_countdowntime; extern consvar_t cv_runscripts; @@ -110,6 +111,8 @@ extern consvar_t cv_skipmapcheck; extern consvar_t cv_sleep; extern consvar_t cv_perfstats; +extern consvar_t cv_ps_samplesize; +extern consvar_t cv_ps_descriptor; extern char timedemo_name[256]; extern boolean timedemo_csv; @@ -128,16 +131,16 @@ typedef enum XD_MAP, // 6 XD_EXITLEVEL, // 7 XD_ADDFILE, // 8 - XD_PAUSE, // 9 - XD_ADDPLAYER, // 10 - XD_TEAMCHANGE, // 11 - XD_CLEARSCORES, // 12 - // UNUSED 13 (Because I don't want to change these comments) - XD_VERIFIED = 14,//14 + XD_ADDFOLDER, // 9 + XD_PAUSE, // 10 + XD_ADDPLAYER, // 11 + XD_TEAMCHANGE, // 12 + XD_CLEARSCORES, // 13 + XD_VERIFIED, // 14 XD_RANDOMSEED, // 15 XD_RUNSOC, // 16 XD_REQADDFILE, // 17 - XD_DELFILE, // 18 - replace next time we add an XD + XD_REQADDFOLDER,// 18 XD_SETMOTD, // 19 XD_SUICIDE, // 20 XD_DEMOTED, // 21 diff --git a/src/d_netfil.c b/src/d_netfil.c index 8f661bb5f..37fb7265f 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,7 +15,7 @@ #include -#if defined (_WIN32) || defined (__DJGPP__) +#ifdef _WIN32 #include #include #else @@ -30,10 +30,6 @@ #elif defined (_WIN32) #include #endif -#ifdef __DJGPP__ -#include -#include -#endif #include "doomdef.h" #include "doomstat.h" @@ -56,7 +52,7 @@ #include // Prototypes -static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid); +static boolean AddFileToSendQueue(INT32 node, UINT8 fileid); // Sender structure typedef struct filetx_s @@ -91,7 +87,7 @@ static filetran_t transfer[MAXNETNODES]; // Receiver structure INT32 fileneedednum; // Number of files needed to join the server -fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files +fileneeded_t *fileneeded; // List of needed files static tic_t lasttimeackpacketsent = 0; char downloaddir[512] = "DOWNLOAD"; @@ -109,6 +105,10 @@ static pauseddownload_t *pauseddownload = NULL; #ifndef NONET // for cl loading screen INT32 lastfilenum = -1; +INT32 downloadcompletednum = 0; +UINT32 downloadcompletedsize = 0; +INT32 totalfilesrequestednum = 0; +UINT32 totalfilesrequestedsize = 0; #endif luafiletransfer_t *luafiletransfers = NULL; @@ -117,29 +117,67 @@ boolean waitingforluafilecommand = false; char luafiledir[256 + 16] = "luafiles"; +static UINT16 GetWadNumFromFileNeededId(UINT8 id) +{ + UINT16 wadnum; + + for (wadnum = mainwads; wadnum < numwadfiles; wadnum++) + { + if (!wadfiles[wadnum]->important) + continue; + if (id == 0) + return wadnum; + id--; + } + + return UINT16_MAX; +} + /** Fills a serverinfo packet with information about wad files loaded. * * \todo Give this function a better name since it is in global scope. - * Used to have size limiting built in - now handled via W_LoadWadFile in w_wad.c + * Used to have size limiting built in - now handled via W_InitFile in w_wad.c * */ -UINT8 *PutFileNeeded(void) +UINT8 *PutFileNeeded(UINT16 firstfile) { - size_t i, count = 0; - UINT8 *p = netbuffer->u.serverinfo.fileneeded; + size_t i; + UINT8 count = 0; + UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded; + UINT8 *p = p_start; char wadfilename[MAX_WADPATH] = ""; - UINT8 filestatus; + UINT8 filestatus, folder; - for (i = 0; i < numwadfiles; i++) + for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad { // If it has only music/sound lumps, don't put it in the list if (!wadfiles[i]->important) continue; + if (firstfile) + { // Skip files until we reach the first file. + firstfile--; + continue; + } + + nameonly(strcpy(wadfilename, wadfiles[i]->filename)); + + // Look below at the WRITE macros to understand what these numbers mean. + if (p + 1 + 4 + min(strlen(wadfilename) + 1, MAX_WADPATH) + 16 > p_start + MAXFILENEEDED) + { + // Too many files to send all at once + if (netbuffer->packettype == PT_MOREFILESNEEDED) + netbuffer->u.filesneededcfg.more = 1; + else + netbuffer->u.serverinfo.flags |= SV_LOTSOFADDONS; + break; + } + filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS + folder = (wadfiles[i]->type == RET_FOLDER); // Store in the upper four bits - if (!cv_downloading.value) + if (!cv_downloading.value || folder) /// \todo Implement folder downloading. filestatus += (2 << 4); // Won't send else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024)) filestatus += (1 << 4); // Will send if requested @@ -147,37 +185,60 @@ UINT8 *PutFileNeeded(void) // filestatus += (0 << 4); -- Won't send, too big WRITEUINT8(p, filestatus); + WRITEUINT8(p, folder); count++; WRITEUINT32(p, wadfiles[i]->filesize); - nameonly(strcpy(wadfilename, wadfiles[i]->filename)); WRITESTRINGN(p, wadfilename, MAX_WADPATH); WRITEMEM(p, wadfiles[i]->md5sum, 16); } - netbuffer->u.serverinfo.fileneedednum = (UINT8)count; + + if (netbuffer->packettype == PT_MOREFILESNEEDED) + netbuffer->u.filesneededcfg.num = count; + else + netbuffer->u.serverinfo.fileneedednum = count; return p; } +void AllocFileNeeded(INT32 size) +{ + if (fileneeded == NULL) + fileneeded = Z_Calloc(sizeof(fileneeded_t) * size, PU_STATIC, NULL); + else + fileneeded = Z_Realloc(fileneeded, sizeof(fileneeded_t) * size, PU_STATIC, NULL); +} + +void FreeFileNeeded(void) +{ + Z_Free(fileneeded); + fileneeded = NULL; +} + /** Parses the serverinfo packet and fills the fileneeded table on client * * \param fileneedednum_parm The number of files needed to join the server * \param fileneededstr The memory block containing the list of needed files * */ -void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr) +void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile) { INT32 i; UINT8 *p; UINT8 filestatus; - fileneedednum = fileneedednum_parm; + fileneedednum = firstfile + fileneedednum_parm; p = (UINT8 *)fileneededstr; - for (i = 0; i < fileneedednum; i++) + + AllocFileNeeded(fileneedednum); + + for (i = firstfile; i < fileneedednum; i++) { - fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet + fileneeded[i].type = FILENEEDED_WAD; + fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet fileneeded[i].justdownloaded = false; filestatus = READUINT8(p); // The first byte is the file status + fileneeded[i].folder = READUINT8(p); // The second byte is the folder flag fileneeded[i].willsend = (UINT8)(filestatus >> 4); fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size fileneeded[i].file = NULL; // The file isn't open yet @@ -192,7 +253,11 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave) lastfilenum = -1; #endif + FreeFileNeeded(); + AllocFileNeeded(1); + fileneedednum = 1; + fileneeded[0].type = FILENEEDED_SAVEGAME; fileneeded[0].status = FS_REQUESTED; fileneeded[0].justdownloaded = false; fileneeded[0].totalsize = UINT32_MAX; @@ -323,14 +388,18 @@ boolean CL_SendFileRequest(void) if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) { totalfreespaceneeded += fileneeded[i].totalsize; - nameonly(fileneeded[i].filename); + WRITEUINT8(p, i); // fileid - WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH); + // put it in download dir + nameonly(fileneeded[i].filename); strcatbf(fileneeded[i].filename, downloaddir, "/"); + fileneeded[i].status = FS_REQUESTED; } + WRITEUINT8(p, 0xFF); + I_GetDiskFreeSpace(&availablefreespace); if (totalfreespaceneeded > availablefreespace) I_Error("To play on this server you must download %s KB,\n" @@ -346,21 +415,22 @@ boolean CL_SendFileRequest(void) // returns false if a requested file was not found or cannot be sent boolean PT_RequestFile(INT32 node) { - char wad[MAX_WADPATH+1]; UINT8 *p = netbuffer->u.textcmd; UINT8 id; + while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow { id = READUINT8(p); if (id == 0xFF) break; - READSTRINGN(p, wad, MAX_WADPATH); - if (!AddFileToSendQueue(node, wad, id)) + + if (!AddFileToSendQueue(node, id)) { SV_AbortSendFiles(node); return false; // don't read the rest of the files } } + return true; // no problems with any files } @@ -369,23 +439,16 @@ boolean PT_RequestFile(INT32 node) * \return 0 if some files are missing * 1 if all files exist * 2 if some already loaded files are not requested or are in a different order + * 3 too many files, over WADLIMIT + * 4 still checking, continuing next tic * */ INT32 CL_CheckFiles(void) { INT32 i, j; char wadfilename[MAX_WADPATH]; - INT32 ret = 1; - size_t packetsize = 0; - size_t filestoget = 0; - -// if (M_CheckParm("-nofiles")) -// return 1; - - // the first is the iwad (the main wad file) - // we don't care if it's called srb2.pk3 or not. - // Never download the IWAD, just assume it's there and identical - fileneeded[0].status = FS_OPEN; + size_t filestoload = 0; + boolean downloadrequired = false; // Modified game handling -- check for an identical file list // must be identical in files loaded AND in order @@ -393,7 +456,7 @@ INT32 CL_CheckFiles(void) if (modifiedgame) { CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n"); - for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;) + for (i = 0, j = mainwads; i < fileneedednum || j < numwadfiles;) { if (j < numwadfiles && !wadfiles[j]->important) { @@ -420,15 +483,21 @@ INT32 CL_CheckFiles(void) return 1; } - // See W_LoadWadFile in w_wad.c - packetsize = packetsizetally; - - for (i = 1; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) { + if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD) + downloadrequired = true; + + if (fileneeded[i].status != FS_OPEN) + filestoload++; + + if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics + continue; + CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename); // Check in already loaded files - for (j = 1; wadfiles[j]; j++) + for (j = mainwads; wadfiles[j]; j++) { nameonly(strcpy(wadfilename, wadfiles[j]->filename)); if (!stricmp(wadfilename, fileneeded[i].filename) && @@ -436,45 +505,46 @@ INT32 CL_CheckFiles(void) { CONS_Debug(DBG_NETPLAY, "already loaded\n"); fileneeded[i].status = FS_OPEN; - break; + return 4; } } - if (fileneeded[i].status != FS_NOTFOUND) - continue; - packetsize += nameonlylength(fileneeded[i].filename) + 22; + if (fileneeded[i].folder) + fileneeded[i].status = findfolder(fileneeded[i].filename); + else + fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); - if ((numwadfiles+filestoget >= MAX_WADFILES) - || (packetsize > MAXFILENEEDED*sizeof(UINT8))) - return 3; - - filestoget++; - - fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true); CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status); - if (fileneeded[i].status != FS_FOUND) - ret = 0; + return 4; } - return ret; + + //now making it here means we've checked the entire list and no FS_NOTCHECKED files remain + if (numwadfiles+filestoload > MAX_WADFILES) + return 3; + else if (downloadrequired) + return 0; //some stuff is FS_NOTFOUND, needs download + else + return 1; //everything is FS_OPEN or FS_FOUND, proceed to loading } // Load it now -void CL_LoadServerFiles(void) +boolean CL_LoadServerFiles(void) { INT32 i; -// if (M_CheckParm("-nofiles")) -// return; - - for (i = 1; i < fileneedednum; i++) + for (i = 0; i < fileneedednum; i++) { if (fileneeded[i].status == FS_OPEN) continue; // Already loaded else if (fileneeded[i].status == FS_FOUND) { - P_AddWadFile(fileneeded[i].filename); + if (fileneeded[i].folder) + P_AddFolder(fileneeded[i].filename); + else + P_AddWadFile(fileneeded[i].filename); G_SetGameModified(true); fileneeded[i].status = FS_OPEN; + return false; } else if (fileneeded[i].status == FS_MD5SUMBAD) I_Error("Wrong version of file %s", fileneeded[i].filename); @@ -500,6 +570,7 @@ void CL_LoadServerFiles(void) fileneeded[i].status, s); } } + return true; } void AddLuaFileTransfer(const char *filename, const char *mode) @@ -562,7 +633,7 @@ static void SV_PrepareSendLuaFileToNextNode(void) // Find a client to send the file to for (i = 1; i < MAXNETNODES; i++) - if (nodeingame[i] && luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting + if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting { // Tell the client we're about to send them the file netbuffer->packettype = PT_SENDINGLUAFILE; @@ -570,6 +641,7 @@ static void SV_PrepareSendLuaFileToNextNode(void) I_Error("Failed to send a PT_SENDINGLUAFILE packet\n"); // !!! Todo: Handle failure a bit better lol luafiletransfers->nodestatus[i] = LFTNS_ASKED; + luafiletransfers->nodetimeouts[i] = I_GetTime() + 30 * TICRATE; return; } @@ -588,7 +660,7 @@ void SV_PrepareSendLuaFile(void) // Set status to "waiting" for everyone for (i = 0; i < MAXNETNODES; i++) - luafiletransfers->nodestatus[i] = LFTNS_WAITING; + luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE); if (FIL_ReadFileOK(luafiletransfers->realfilename)) { @@ -649,12 +721,14 @@ void RemoveAllLuaFileTransfers(void) void SV_AbortLuaFileTransfer(INT32 node) { - if (luafiletransfers - && (luafiletransfers->nodestatus[node] == LFTNS_ASKED - || luafiletransfers->nodestatus[node] == LFTNS_SENDING)) + if (luafiletransfers) { - luafiletransfers->nodestatus[node] = LFTNS_WAITING; - SV_PrepareSendLuaFileToNextNode(); + if (luafiletransfers->nodestatus[node] == LFTNS_ASKED + || luafiletransfers->nodestatus[node] == LFTNS_SENDING) + { + SV_PrepareSendLuaFileToNextNode(); + } + luafiletransfers->nodestatus[node] = LFTNS_NONE; } } @@ -678,7 +752,11 @@ void CL_PrepareDownloadLuaFile(void) netbuffer->packettype = PT_ASKLUAFILE; HSendPacket(servernode, true, 0, 0); + FreeFileNeeded(); + AllocFileNeeded(1); + fileneedednum = 1; + fileneeded[0].type = FILENEEDED_LUAFILE; fileneeded[0].status = FS_REQUESTED; fileneeded[0].justdownloaded = false; fileneeded[0].totalsize = UINT32_MAX; @@ -705,15 +783,11 @@ static INT32 filestosend = 0; * \sa AddLuaFileToSendQueue * */ -static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid) +static boolean AddFileToSendQueue(INT32 node, UINT8 fileid) { filetx_t **q; // A pointer to the "next" field of the last file in the list filetx_t *p; // The new file request - INT32 i; - char wadfilename[MAX_WADPATH]; - - if (cv_noticedownload.value) - CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node)); + UINT16 wadnum; // Find the last file in the list and set a pointer to its "next" field q = &transfer[node].txlist; @@ -733,51 +807,43 @@ static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid if (!p->id.filename) I_Error("AddFileToSendQueue: No more memory\n"); - // Set the file name and get rid of the path - strlcpy(p->id.filename, filename, MAX_WADPATH); - nameonly(p->id.filename); - - // Look for the requested file through all loaded files - for (i = 0; wadfiles[i]; i++) - { - strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH); - nameonly(wadfilename); - if (!stricmp(wadfilename, p->id.filename)) - { - // Copy file name with full path - strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH); - break; - } - } + // Find the wad the ID refers to + wadnum = GetWadNumFromFileNeededId(fileid); // Handle non-loaded file requests - if (!wadfiles[i]) + if (wadnum == UINT16_MAX) { - DEBFILE(va("%s not found in wadfiles\n", filename)); + DEBFILE(va("fileneeded %d not found in wadfiles\n", fileid)); // This formerly checked if (!findfile(p->id.filename, NULL, true)) // Not found - // Don't inform client (probably someone who thought they could leak 2.2 ACZ) - DEBFILE(va("Client %d request %s: not found\n", node, filename)); + // Don't inform client + DEBFILE(va("Client %d request fileneeded %d: not found\n", node, fileid)); free(p->id.filename); free(p); *q = NULL; return false; // cancel the rest of the requests } + // Set the file name and get rid of the path + strlcpy(p->id.filename, wadfiles[wadnum]->filename, MAX_WADPATH); + // Handle huge file requests (i.e. bigger than cv_maxsend.value KB) - if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024) + if (wadfiles[wadnum]->filesize > (UINT32)cv_maxsend.value * 1024) { // Too big // Don't inform client (client sucks, man) - DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename)); + DEBFILE(va("Client %d request %s: file too big, not sending\n", node, p->id.filename)); free(p->id.filename); free(p); *q = NULL; return false; // cancel the rest of the requests } - DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node)); + if (cv_noticedownload.value) + CONS_Printf("Sending file \"%s\" to node %d (%s)\n", p->id.filename, node, I_GetNodeAddress(node)); + + DEBFILE(va("Sending file %s (id=%d) to %d\n", p->id.filename, fileid, node)); p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it p->fileid = fileid; p->next = NULL; // End of list @@ -914,7 +980,6 @@ static void SV_EndFileSend(INT32 node) filestosend--; } -#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH) #define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE)) /** Handles file transmission @@ -928,17 +993,26 @@ void FileSendTicker(void) filetx_t *f; INT32 packetsent, ram, i, j; + // If someone is taking too long to download, kick them with a timeout + // to prevent blocking the rest of the server... + if (luafiletransfers) + { + for (i = 1; i < MAXNETNODES; i++) + { + luafiletransfernodestatus_t status = luafiletransfers->nodestatus[i]; + + if (status != LFTNS_NONE && status != LFTNS_WAITING && status != LFTNS_SENT + && I_GetTime() > luafiletransfers->nodetimeouts[i]) + { + Net_ConnectionTimeout(i); + } + } + } + if (!filestosend) // No file to send return; - if (cv_downloadspeed.value) // New behavior - packetsent = cv_downloadspeed.value; - else // Old behavior - { - packetsent = PACKETPERTIC; - if (!packetsent) - packetsent = 1; - } + packetsent = cv_downloadspeed.value; netbuffer->packettype = PT_FILEFRAGMENT; @@ -1215,6 +1289,9 @@ void PT_FileFragment(void) UINT16 boundedfragmentsize = doomcom->datalength - BASEPACKETSIZE - sizeof(netbuffer->u.filetxpak); char *filename; + if (!file) + return; + filename = va("%s", file->filename); nameonly(filename); @@ -1326,6 +1403,7 @@ void PT_FileFragment(void) // Tell the server we have received the file netbuffer->packettype = PT_HASLUAFILE; HSendPacket(servernode, true, 0, 0); + FreeFileNeeded(); } } } @@ -1396,32 +1474,37 @@ void CloseNetFile(void) SV_AbortSendFiles(i); // Receiving a file? - for (i = 0; i < MAX_WADFILES; i++) - if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) - { - fclose(fileneeded[i].file); - free(fileneeded[i].ackpacket); - - if (!pauseddownload && i != 0) // 0 is either srb2.srb or the gamestate... + if (fileneeded) + { + for (i = 0; i < fileneedednum; i++) + if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) { - // Don't remove the file, save it for later in case we resume the download - pauseddownload = malloc(sizeof(*pauseddownload)); - if (!pauseddownload) - I_Error("CloseNetFile: No more memory\n"); + fclose(fileneeded[i].file); + free(fileneeded[i].ackpacket); - strcpy(pauseddownload->filename, fileneeded[i].filename); - memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16); - pauseddownload->currentsize = fileneeded[i].currentsize; - pauseddownload->receivedfragments = fileneeded[i].receivedfragments; - pauseddownload->fragmentsize = fileneeded[i].fragmentsize; + if (!pauseddownload && (fileneeded[i].type == FILENEEDED_WAD || i != 0)) // 0 is the gamestate... + { + // Don't remove the file, save it for later in case we resume the download + pauseddownload = malloc(sizeof(*pauseddownload)); + if (!pauseddownload) + I_Error("CloseNetFile: No more memory\n"); + + strcpy(pauseddownload->filename, fileneeded[i].filename); + memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16); + pauseddownload->currentsize = fileneeded[i].currentsize; + pauseddownload->receivedfragments = fileneeded[i].receivedfragments; + pauseddownload->fragmentsize = fileneeded[i].fragmentsize; + } + else + { + // File is not complete, delete it. + free(fileneeded[i].receivedfragments); + remove(fileneeded[i].filename); + } } - else - { - free(fileneeded[i].receivedfragments); - // File is not complete delete it - remove(fileneeded[i].filename); - } - } + } + + FreeFileNeeded(); } void Command_Downloads_f(void) @@ -1556,3 +1639,26 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found } + +// Searches for a folder. +// This can be used with a full path, or an incomplete path. +// In the latter case, the function will try to find folders in +// srb2home, srb2path, and the current directory. +filestatus_t findfolder(const char *path) +{ + // Check the path by itself first. + if (concatpaths(path, NULL) == 1) + return FS_FOUND; + +#define checkpath(startpath) \ + if (concatpaths(path, startpath) == 1) \ + return FS_FOUND + + checkpath(srb2home); // Then, look in srb2home. + checkpath(srb2path); // Now, look in srb2path. + checkpath("."); // Finally, look in the current directory. + +#undef checkpath + + return FS_NOTFOUND; +} diff --git a/src/d_netfil.h b/src/d_netfil.h index 1b399be75..f778a518f 100644 --- a/src/d_netfil.h +++ b/src/d_netfil.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -27,6 +27,7 @@ typedef enum typedef enum { + FS_NOTCHECKED, FS_NOTFOUND, FS_FOUND, FS_REQUESTED, @@ -35,12 +36,21 @@ typedef enum FS_MD5SUMBAD } filestatus_t; +typedef enum +{ + FILENEEDED_WAD, + FILENEEDED_SAVEGAME, + FILENEEDED_LUAFILE +} fileneededtype_t; + typedef struct { - UINT8 willsend; // Is the server willing to send it? char filename[MAX_WADPATH]; UINT8 md5sum[16]; filestatus_t status; // The value returned by recsearch + UINT8 willsend; // Is the server willing to send it? + UINT8 folder; // File is a folder + fileneededtype_t type; boolean justdownloaded; // To prevent late fragments from causing an I_Error // Used only for download @@ -54,20 +64,28 @@ typedef struct UINT32 ackresendposition; // Used when resuming downloads } fileneeded_t; +#define FILENEEDEDSIZE 23 + extern INT32 fileneedednum; -extern fileneeded_t fileneeded[MAX_WADFILES]; +extern fileneeded_t *fileneeded; extern char downloaddir[512]; #ifndef NONET extern INT32 lastfilenum; +extern INT32 downloadcompletednum; +extern UINT32 downloadcompletedsize; +extern INT32 totalfilesrequestednum; +extern UINT32 totalfilesrequestedsize; #endif -UINT8 *PutFileNeeded(void); -void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr); +void AllocFileNeeded(INT32 size); +void FreeFileNeeded(void); +UINT8 *PutFileNeeded(UINT16 firstfile); +void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile); void CL_PrepareDownloadSaveGame(const char *tmpsave); INT32 CL_CheckFiles(void); -void CL_LoadServerFiles(void); +boolean CL_LoadServerFiles(void); void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid); @@ -85,10 +103,11 @@ boolean PT_RequestFile(INT32 node); typedef enum { + LFTNS_NONE, // This node is not connected LFTNS_WAITING, // This node is waiting for the server to send the file - LFTNS_ASKED, // The server has told the node they're ready to send the file + LFTNS_ASKED, // The server has told the node they're ready to send the file LFTNS_SENDING, // The server is sending the file to this node - LFTNS_SENT // The node already has the file + LFTNS_SENT // The node already has the file } luafiletransfernodestatus_t; typedef struct luafiletransfer_s @@ -99,6 +118,7 @@ typedef struct luafiletransfer_s INT32 id; // Callback ID boolean ongoing; luafiletransfernodestatus_t nodestatus[MAXNETNODES]; + tic_t nodetimeouts[MAXNETNODES]; struct luafiletransfer_s *next; } luafiletransfer_t; @@ -133,6 +153,9 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath); filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum); +// Searches for a folder +filestatus_t findfolder(const char *path); + void nameonly(char *s); size_t nameonlylength(const char *s); diff --git a/src/d_player.h b/src/d_player.h index 7193ce591..6df6689c5 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -52,6 +52,8 @@ typedef enum SF_NOSUPERSPRITES = 1<<16, // Don't use super sprites while super SF_NOSUPERJUMPBOOST = 1<<17, // Disable the jump boost given while super (i.e. Knuckles) SF_CANBUSTWALLS = 1<<18, // Can naturally bust walls on contact? (i.e. Knuckles) + SF_NOSHIELDABILITY = 1<<19, // Disable shield abilities + // free up to and including 1<<31 } skinflags_t; @@ -312,9 +314,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; @@ -524,8 +560,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/d_think.h b/src/d_think.h index 4bdac4627..90a58ab68 100644 --- a/src/d_think.h +++ b/src/d_think.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/d_ticcmd.h b/src/d_ticcmd.h index 2a5ef0981..e632a74a8 100644 --- a/src/d_ticcmd.h +++ b/src/d_ticcmd.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -21,6 +21,8 @@ #pragma interface #endif +#define MAXPREDICTTICS 12 + // Button/action code definitions. typedef enum { @@ -63,6 +65,7 @@ typedef struct INT16 angleturn; // <<16 for angle delta - saved as 1 byte into demos INT16 aiming; // vertical aiming, see G_BuildTicCmd UINT16 buttons; + UINT8 latency; // Netgames: how many tics ago was this ticcmd generated from this player's end? } ATTRPACK ticcmd_t; #if defined(_MSC_VER) diff --git a/src/deh_lua.c b/src/deh_lua.c index e6a436421..09dc155cf 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -25,10 +25,6 @@ #include "deh_lua.h" #include "deh_tables.h" -#ifdef MUSICSLOT_COMPATIBILITY -#include "deh_soc.h" // for get_mus -#endif - // freeslot takes a name (string only!) // and allocates it to the appropriate free slot. // Returns the slot number allocated for it or nil if failed. @@ -264,6 +260,11 @@ static inline int lib_getenum(lua_State *L) lua_pushinteger(L, ((lua_Integer)1<musname), va("Level header %d: music", num)); } } -#ifdef MUSICSLOT_COMPATIBILITY else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(mapheaderinfo[num-1]->musname, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(mapheaderinfo[num-1]->musname, compat_special_music_slots[i - 1036], 7); - else - mapheaderinfo[num-1]->musname[0] = 0; // becomes empty string - mapheaderinfo[num-1]->musname[6] = 0; - } -#endif + deh_warning("Level header %d: MusicSlot parameter is deprecated and will be removed.\nUse \"Music\" instead.", num); else if (fastcmp(word, "MUSICTRACK")) mapheaderinfo[num-1]->mustrack = ((UINT16)i - 1); else if (fastcmp(word, "MUSICPOS")) @@ -1964,19 +1987,6 @@ static void readcutscenescene(MYFILE *f, INT32 num, INT32 scenenum) strncpy(cutscenes[num]->scene[scenenum].musswitch, word2, 7); cutscenes[num]->scene[scenenum].musswitch[6] = 0; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(cutscenes[num]->scene[scenenum].musswitch, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(cutscenes[num]->scene[scenenum].musswitch, compat_special_music_slots[i - 1036], 7); - else - cutscenes[num]->scene[scenenum].musswitch[0] = 0; // becomes empty string - cutscenes[num]->scene[scenenum].musswitch[6] = 0; - } -#endif else if (fastcmp(word, "MUSICTRACK")) { cutscenes[num]->scene[scenenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; @@ -2239,19 +2249,6 @@ static void readtextpromptpage(MYFILE *f, INT32 num, INT32 pagenum) strncpy(textprompts[num]->page[pagenum].musswitch, word2, 7); textprompts[num]->page[pagenum].musswitch[6] = 0; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - i = get_mus(word2, true); - if (i && i <= 1035) - snprintf(textprompts[num]->page[pagenum].musswitch, 7, "%sM", G_BuildMapName(i)); - else if (i && i <= 1050) - strncpy(textprompts[num]->page[pagenum].musswitch, compat_special_music_slots[i - 1036], 7); - else - textprompts[num]->page[pagenum].musswitch[0] = 0; // becomes empty string - textprompts[num]->page[pagenum].musswitch[6] = 0; - } -#endif else if (fastcmp(word, "MUSICTRACK")) { textprompts[num]->page[pagenum].musswitchflags = ((UINT16)i) & MUSIC_TRACKMASK; @@ -2577,20 +2574,6 @@ void readmenu(MYFILE *f, INT32 num) menupres[num].musname[6] = 0; titlechanged = true; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastcmp(word, "MUSICSLOT")) - { - value = get_mus(word2, true); - if (value && value <= 1035) - snprintf(menupres[num].musname, 7, "%sM", G_BuildMapName(value)); - else if (value && value <= 1050) - strncpy(menupres[num].musname, compat_special_music_slots[value - 1036], 7); - else - menupres[num].musname[0] = 0; // becomes empty string - menupres[num].musname[6] = 0; - titlechanged = true; - } -#endif else if (fastcmp(word, "MUSICTRACK")) { menupres[num].mustrack = ((UINT16)value - 1); @@ -2839,26 +2822,31 @@ void readsound(MYFILE *f, INT32 num) if (s[0] == '\n') break; + // First remove trailing newline, if there is one + tmp = strchr(s, '\n'); + if (tmp) + *tmp = '\0'; + tmp = strchr(s, '#'); if (tmp) *tmp = '\0'; if (s == tmp) continue; // Skip comment lines, but don't break. - word = strtok(s, " "); - if (word) - strupr(word); + // Set / reset word + word = s; + + // Get the part before the " = " + tmp = strchr(s, '='); + if (tmp) + *(tmp-1) = '\0'; else break; + strupr(word); - word2 = strtok(NULL, " "); - if (word2) - value = atoi(word2); - else - { - deh_warning("No value for token %s", word); - continue; - } + // Now get the part after + word2 = tmp += 2; + value = atoi(word2); // used for numerical settings if (fastcmp(word, "SINGULAR")) { @@ -3017,7 +3005,12 @@ void reademblemdata(MYFILE *f, INT32 num) else if (fastcmp(word, "COLOR")) emblemlocations[num-1].color = get_number(word2); else if (fastcmp(word, "VAR")) + { + Z_Free(emblemlocations[num-1].stringVar); + emblemlocations[num-1].stringVar = Z_StrDup(word2); + emblemlocations[num-1].var = get_number(word2); + } else deh_warning("Emblem %d: unknown word '%s'", num, word); } @@ -3219,11 +3212,16 @@ void readunlockable(MYFILE *f, INT32 num) unlockables[num].type = SECRET_WARP; else if (fastcmp(word2, "SOUNDTEST")) unlockables[num].type = SECRET_SOUNDTEST; + else if (fastcmp(word2, "SKIN")) + unlockables[num].type = SECRET_SKIN; else unlockables[num].type = (INT16)i; } else if (fastcmp(word, "VAR")) { + Z_Free(unlockables[num].stringVar); + unlockables[num].stringVar = Z_StrDup(word2); + // Support using the actual map name, // i.e., Level AB, Level FZ, etc. @@ -3309,7 +3307,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) else re = atoi(params[1]); - if (re < 0 || re >= NUMMAPS) + if (re <= 0 || re > NUMMAPS) { deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); return; @@ -3329,7 +3327,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) else x1 = (INT16)atoi(params[1]); - if (x1 < 0 || x1 >= NUMMAPS) + if (x1 <= 0 || x1 > NUMMAPS) { deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); return; @@ -3364,7 +3362,7 @@ static void readcondition(UINT8 set, UINT32 id, char *word2) else x1 = (INT16)atoi(params[1]); - if (x1 < 0 || x1 >= NUMMAPS) + if (x1 <= 0 || x1 > NUMMAPS) { deh_warning("Level number %d out of range (1 - %d)", re, NUMMAPS); return; @@ -4178,46 +4176,6 @@ sfxenum_t get_sfx(const char *word) return sfx_None; } -#ifdef MUSICSLOT_COMPATIBILITY -UINT16 get_mus(const char *word, UINT8 dehacked_mode) -{ // Returns the value of MUS_ enumerations - UINT16 i; - char lumptmp[4]; - - if (*word >= '0' && *word <= '9') - return atoi(word); - if (!word[2] && toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') - return (UINT16)M_MapNumber(word[0], word[1]); - - if (fastncmp("MUS_",word,4)) - word += 4; // take off the MUS_ - else if (fastncmp("O_",word,2) || fastncmp("D_",word,2)) - word += 2; // take off the O_ or D_ - - strncpy(lumptmp, word, 4); - lumptmp[3] = 0; - if (fasticmp("MAP",lumptmp)) - { - word += 3; - if (toupper(word[0]) >= 'A' && toupper(word[0]) <= 'Z') - return (UINT16)M_MapNumber(word[0], word[1]); - else if ((i = atoi(word))) - return i; - - word -= 3; - if (dehacked_mode) - deh_warning("Couldn't find music named 'MUS_%s'",word); - return 0; - } - for (i = 0; compat_special_music_slots[i][0]; ++i) - if (fasticmp(word, compat_special_music_slots[i])) - return i + 1036; - if (dehacked_mode) - deh_warning("Couldn't find music named 'MUS_%s'",word); - return 0; -} -#endif - hudnum_t get_huditem(const char *word) { // Returns the value of HUD_ enumerations hudnum_t i; @@ -4448,13 +4406,6 @@ static fixed_t find_const(const char **rword) free(word); return r; } -#ifdef MUSICSLOT_COMPATIBILITY - else if (fastncmp("MUS_",word,4) || fastncmp("O_",word,2)) { - r = get_mus(word, true); - free(word); - return r; - } -#endif else if (fastncmp("PW_",word,3)) { r = get_power(word); free(word); diff --git a/src/deh_soc.h b/src/deh_soc.h index 2bcb52e70..f972ec26e 100644 --- a/src/deh_soc.h +++ b/src/deh_soc.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -43,7 +43,7 @@ #include "info.h" #include "dehacked.h" -#include "doomdef.h" // MUSICSLOT_COMPATIBILITY, HWRENDER +#include "doomdef.h" // HWRENDER // Crazy word-reading stuff /// \todo Put these in a seperate file or something. @@ -52,9 +52,6 @@ statenum_t get_state(const char *word); spritenum_t get_sprite(const char *word); playersprite_t get_sprite2(const char *word); sfxenum_t get_sfx(const char *word); -#ifdef MUSICSLOT_COMPATIBILITY -UINT16 get_mus(const char *word, UINT8 dehacked_mode); -#endif hudnum_t get_huditem(const char *word); menutype_t get_menutype(const char *word); //INT16 get_gametype(const char *word); @@ -84,6 +81,8 @@ void readskincolor(MYFILE *f, INT32 num); void readthing(MYFILE *f, INT32 num); void readfreeslots(MYFILE *f); void readPlayer(MYFILE *f, INT32 num); +void clear_emblems(void); +void clear_unlockables(void); void clear_levels(void); void clear_conditionsets(void); #endif diff --git a/src/deh_tables.c b/src/deh_tables.c index 54f3288f0..49f446766 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -22,6 +22,9 @@ #include "v_video.h" // video flags (for lua) #include "i_sound.h" // musictype_t (for lua) #include "g_state.h" // gamestate_t (for lua) +#include "g_game.h" // Joystick axes (for lua) +#include "i_joy.h" +#include "g_input.h" // Game controls (for lua) #include "deh_tables.h" @@ -88,6 +91,8 @@ actionpointer_t actionpointers[] = {{A_FaceTracer}, "A_FACETRACER"}, {{A_Scream}, "A_SCREAM"}, {{A_BossDeath}, "A_BOSSDEATH"}, + {{A_SetShadowScale}, "A_SETSHADOWSCALE"}, + {{A_ShadowScream}, "A_SHADOWSCREAM"}, {{A_CustomPower}, "A_CUSTOMPOWER"}, {{A_GiveWeapon}, "A_GIVEWEAPON"}, {{A_RingBox}, "A_RINGBOX"}, @@ -194,6 +199,7 @@ actionpointer_t actionpointers[] = {{A_Boss3Path}, "A_BOSS3PATH"}, {{A_Boss3ShockThink}, "A_BOSS3SHOCKTHINK"}, {{A_LinedefExecute}, "A_LINEDEFEXECUTE"}, + {{A_LinedefExecuteFromArg}, "A_LINEDEFEXECUTEFROMARG"}, {{A_PlaySeeSound}, "A_PLAYSEESOUND"}, {{A_PlayAttackSound}, "A_PLAYATTACKSOUND"}, {{A_PlayActiveSound}, "A_PLAYACTIVESOUND"}, @@ -221,6 +227,8 @@ actionpointer_t actionpointers[] = {{A_SetObjectFlags2}, "A_SETOBJECTFLAGS2"}, {{A_RandomState}, "A_RANDOMSTATE"}, {{A_RandomStateRange}, "A_RANDOMSTATERANGE"}, + {{A_StateRangeByAngle}, "A_STATERANGEBYANGLE"}, + {{A_StateRangeByParameter}, "A_STATERANGEBYPARAMETER"}, {{A_DualAction}, "A_DUALACTION"}, {{A_RemoteAction}, "A_REMOTEACTION"}, {{A_ToggleFlameJet}, "A_TOGGLEFLAMEJET"}, @@ -1522,6 +1530,13 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_SPINFIRE5", "S_SPINFIRE6", + "S_TEAM_SPINFIRE1", + "S_TEAM_SPINFIRE2", + "S_TEAM_SPINFIRE3", + "S_TEAM_SPINFIRE4", + "S_TEAM_SPINFIRE5", + "S_TEAM_SPINFIRE6", + // Spikes "S_SPIKE1", "S_SPIKE2", @@ -1741,6 +1756,56 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi // The letter "S_LETTER", + // Tutorial Scenery + "S_TUTORIALLEAF1", + "S_TUTORIALLEAF2", + "S_TUTORIALLEAF3", + "S_TUTORIALLEAF4", + "S_TUTORIALLEAF5", + "S_TUTORIALLEAF6", + "S_TUTORIALLEAF7", + "S_TUTORIALLEAF8", + "S_TUTORIALLEAF9", + "S_TUTORIALLEAF10", + "S_TUTORIALLEAF11", + "S_TUTORIALLEAF12", + "S_TUTORIALLEAF13", + "S_TUTORIALLEAF14", + "S_TUTORIALLEAF15", + "S_TUTORIALLEAF16", + "S_TUTORIALFLOWER1", + "S_TUTORIALFLOWER2", + "S_TUTORIALFLOWER3", + "S_TUTORIALFLOWER4", + "S_TUTORIALFLOWER5", + "S_TUTORIALFLOWER6", + "S_TUTORIALFLOWER7", + "S_TUTORIALFLOWER8", + "S_TUTORIALFLOWER9", + "S_TUTORIALFLOWER10", + "S_TUTORIALFLOWER11", + "S_TUTORIALFLOWER12", + "S_TUTORIALFLOWER13", + "S_TUTORIALFLOWER14", + "S_TUTORIALFLOWER15", + "S_TUTORIALFLOWER16", + "S_TUTORIALFLOWERF1", + "S_TUTORIALFLOWERF2", + "S_TUTORIALFLOWERF3", + "S_TUTORIALFLOWERF4", + "S_TUTORIALFLOWERF5", + "S_TUTORIALFLOWERF6", + "S_TUTORIALFLOWERF7", + "S_TUTORIALFLOWERF8", + "S_TUTORIALFLOWERF9", + "S_TUTORIALFLOWERF10", + "S_TUTORIALFLOWERF11", + "S_TUTORIALFLOWERF12", + "S_TUTORIALFLOWERF13", + "S_TUTORIALFLOWERF14", + "S_TUTORIALFLOWERF15", + "S_TUTORIALFLOWERF16", + // GFZ flowers "S_GFZFLOWERA", "S_GFZFLOWERB", @@ -3283,14 +3348,13 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_NIGHTOPIANHELPER9", // Nightopian - "S_PIAN0", - "S_PIAN1", - "S_PIAN2", - "S_PIAN3", - "S_PIAN4", - "S_PIAN5", - "S_PIAN6", - "S_PIANSING", + "S_PIAN_LOOK1", + "S_PIAN_LOOK2", + "S_PIAN_LOOK3", + "S_PIAN_FLY1", + "S_PIAN_FLY2", + "S_PIAN_FLY3", + "S_PIAN_SING", // Shleep "S_SHLEEP1", @@ -3753,6 +3817,12 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t // The letter "MT_LETTER", + // Tutorial Scenery + "MT_TUTORIALPLANT", + "MT_TUTORIALLEAF", + "MT_TUTORIALFLOWER", + "MT_TUTORIALFLOWERF", + // Greenflower Scenery "MT_GFZFLOWER1", "MT_GFZFLOWER2", @@ -4102,17 +4172,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_FINISHFLAG", // Finish flag // Ambient Sounds - "MT_AWATERA", // Ambient Water Sound 1 - "MT_AWATERB", // Ambient Water Sound 2 - "MT_AWATERC", // Ambient Water Sound 3 - "MT_AWATERD", // Ambient Water Sound 4 - "MT_AWATERE", // Ambient Water Sound 5 - "MT_AWATERF", // Ambient Water Sound 6 - "MT_AWATERG", // Ambient Water Sound 7 - "MT_AWATERH", // Ambient Water Sound 8 - "MT_RANDOMAMBIENT", - "MT_RANDOMAMBIENT2", - "MT_MACHINEAMBIENCE", + "MT_AMBIENT", "MT_CORK", "MT_LHRT", @@ -4216,7 +4276,6 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_CRUMBLEOBJ", // Sound generator for crumbling platform "MT_TUBEWAYPOINT", "MT_PUSH", - "MT_PULL", "MT_GHOST", "MT_OVERLAY", "MT_ANGLEMAN", @@ -4259,6 +4318,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_YELLOWBRICKDEBRIS", "MT_NAMECHECK", + "MT_RAY", }; const char *const MOBJFLAG_LIST[] = { @@ -4344,6 +4404,8 @@ const char *const MOBJEFLAG_LIST[] = { "SPRUNG", // Mobj was already sprung this tic "APPLYPMOMZ", // Platform movement "TRACERANGLE", // Compute and trigger on mobj angle relative to tracer + "FORCESUPER", // Forces an object to use super sprites with SPR_PLAY. + "FORCENOSUPER", // Forces an object to NOT use super sprites with SPR_PLAY. NULL }; @@ -4450,23 +4512,85 @@ const char *const GAMETYPERULE_LIST[] = { }; // Linedef flags -const char *const ML_LIST[16] = { +const char *const ML_LIST[] = { "IMPASSIBLE", "BLOCKMONSTERS", "TWOSIDED", "DONTPEGTOP", "DONTPEGBOTTOM", - "EFFECT1", + "SKEWTD", "NOCLIMB", - "EFFECT2", - "EFFECT3", - "EFFECT4", - "EFFECT5", - "NOSONIC", - "NOTAILS", - "NOKNUX", + "NOSKEW", + "MIDPEG", + "MIDSOLID", + "WRAPMIDTEX", + "NETONLY", + "NONET", + "EFFECT6", "BOUNCY", - "TFERLINE" + "TFERLINE", + NULL +}; + +// Sector flags +const char *const MSF_LIST[] = { + "FLIPSPECIAL_FLOOR", + "FLIPSPECIAL_CEILING", + "TRIGGERSPECIAL_TOUCH", + "TRIGGERSPECIAL_HEADBUMP", + "TRIGGERLINE_PLANE", + "TRIGGERLINE_MOBJ", + "GRAVITYFLIP", + "HEATWAVE", + "NOCLIPCAMERA", + NULL +}; + +// Sector special flags +const char *const SSF_LIST[] = { + "OUTERSPACE", + "DOUBLESTEPUP", + "WINDCURRENT", + "CONVEYOR", + "SPEEDPAD", + "STARPOSTACTIVATOR", + "EXIT", + "SPECIALSTAGEPIT", + "RETURNFLAG", + "REDTEAMBASE", + "BLUETEAMBASE", + "FAN", + "SUPERTRANSFORM", + "FORCESPIN", + "ZOOMTUBESTART", + "ZOOMTUBEEND", + "FINISHLINE", + "ROPEHANG", + NULL +}; + +// Sector damagetypes +const char *const SD_LIST[] = { + "NONE", + "GENERIC", + "WATER", + "FIRE", + "LAVA", + "ELECTRIC", + "SPIKE", + "DEATHPITTILT", + "DEATHPITNOTILT", + "INSTAKILL", + "SPECIALSTAGE", + NULL +}; + +// Sector triggerer +const char *const TO_LIST[] = { + "PLAYER", + "ALLPLAYERS", + "MOBJ", + NULL }; const char *COLOR_ENUMS[] = { @@ -4831,9 +4955,18 @@ struct int_const_s const INT_CONST[] = { {"FF_RANDOMANIM",FF_RANDOMANIM}, {"FF_GLOBALANIM",FF_GLOBALANIM}, {"FF_FULLBRIGHT",FF_FULLBRIGHT}, + {"FF_SEMIBRIGHT",FF_SEMIBRIGHT}, + {"FF_FULLDARK",FF_FULLDARK}, {"FF_VERTICALFLIP",FF_VERTICALFLIP}, {"FF_HORIZONTALFLIP",FF_HORIZONTALFLIP}, {"FF_PAPERSPRITE",FF_PAPERSPRITE}, + {"FF_FLOORSPRITE",FF_FLOORSPRITE}, + {"FF_BLENDMASK",FF_BLENDMASK}, + {"FF_BLENDSHIFT",FF_BLENDSHIFT}, + {"FF_ADD",FF_ADD}, + {"FF_SUBTRACT",FF_SUBTRACT}, + {"FF_REVERSESUBTRACT",FF_REVERSESUBTRACT}, + {"FF_MODULATE",FF_MODULATE}, {"FF_TRANSMASK",FF_TRANSMASK}, {"FF_TRANSSHIFT",FF_TRANSSHIFT}, // new preshifted translucency (used in source) @@ -4877,6 +5010,7 @@ struct int_const_s const INT_CONST[] = { {"AST_REVERSESUBTRACT",AST_REVERSESUBTRACT}, {"AST_MODULATE",AST_MODULATE}, {"AST_OVERLAY",AST_OVERLAY}, + {"AST_FOG",AST_FOG}, // Render flags {"RF_HORIZONTALFLIP",RF_HORIZONTALFLIP}, @@ -4888,9 +5022,10 @@ struct int_const_s const INT_CONST[] = { {"RF_OBJECTSLOPESPLAT",RF_OBJECTSLOPESPLAT}, {"RF_NOSPLATBILLBOARD",RF_NOSPLATBILLBOARD}, {"RF_NOSPLATROLLANGLE",RF_NOSPLATROLLANGLE}, - {"RF_BLENDMASK",RF_BLENDMASK}, + {"RF_BRIGHTMASK",RF_BRIGHTMASK}, {"RF_FULLBRIGHT",RF_FULLBRIGHT}, {"RF_FULLDARK",RF_FULLDARK}, + {"RF_SEMIBRIGHT",RF_SEMIBRIGHT}, {"RF_NOCOLORMAPS",RF_NOCOLORMAPS}, {"RF_SPRITETYPEMASK",RF_SPRITETYPEMASK}, {"RF_PAPERSPRITE",RF_PAPERSPRITE}, @@ -5016,6 +5151,7 @@ struct int_const_s const INT_CONST[] = { {"SF_NOSUPERSPRITES",SF_NOSUPERSPRITES}, {"SF_NOSUPERJUMPBOOST",SF_NOSUPERJUMPBOOST}, {"SF_CANBUSTWALLS",SF_CANBUSTWALLS}, + {"SF_NOSHIELDABILITY",SF_NOSHIELDABILITY}, // Dashmode constants {"DASHMODE_THRESHOLD",DASHMODE_THRESHOLD}, @@ -5076,6 +5212,7 @@ struct int_const_s const INT_CONST[] = { {"PAL_MIXUP",PAL_MIXUP}, {"PAL_RECYCLE",PAL_RECYCLE}, {"PAL_NUKE",PAL_NUKE}, + {"PAL_INVERT",PAL_INVERT}, // for P_DamageMobj //// Damage types {"DMG_WATER",DMG_WATER}, @@ -5160,6 +5297,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}, @@ -5208,7 +5351,7 @@ struct int_const_s const INT_CONST[] = { {"FF_FLOATBOB",FF_FLOATBOB}, ///< Floats on water and bobs if you step on it. {"FF_NORETURN",FF_NORETURN}, ///< Used with ::FF_CRUMBLE. Will not return to its original position after falling. {"FF_CRUMBLE",FF_CRUMBLE}, ///< Falls 2 seconds after being stepped on, and randomly brings all touching crumbling 3dfloors down with it, providing their master sectors share the same tag (allows crumble platforms above or below, to also exist). - {"FF_SHATTERBOTTOM",FF_SHATTERBOTTOM}, ///< Used with ::FF_BUSTUP. Like FF_SHATTER, but only breaks from the bottom. Good for springing up through rubble. + {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. {"FF_MARIO",FF_MARIO}, ///< Acts like a question block when hit from underneath. Goodie spawned at top is determined by master sector. {"FF_BUSTUP",FF_BUSTUP}, ///< You can spin through/punch this block and it will crumble! {"FF_QUICKSAND",FF_QUICKSAND}, ///< Quicksand! @@ -5216,12 +5359,21 @@ struct int_const_s const INT_CONST[] = { {"FF_REVERSEPLATFORM",FF_REVERSEPLATFORM}, ///< A fall-through floor in normal gravity, a platform in reverse gravity. {"FF_INTANGIBLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangible, but the sides are still solid. {"FF_INTANGABLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangable, but the sides are still solid. - {"FF_SHATTER",FF_SHATTER}, ///< Used with ::FF_BUSTUP. Bustable on mere touch. - {"FF_SPINBUST",FF_SPINBUST}, ///< Used with ::FF_BUSTUP. Also bustable if you're in your spinning frames. - {"FF_STRONGBUST",FF_STRONGBUST}, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee). {"FF_RIPPLE",FF_RIPPLE}, ///< Ripple the flats {"FF_COLORMAPONLY",FF_COLORMAPONLY}, ///< Only copy the colormap, not the lightlevel - {"FF_GOOWATER",FF_GOOWATER}, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. + {"FF_BOUNCY",FF_BOUNCY}, ///< Bounces players + {"FF_SPLAT",FF_SPLAT}, ///< Use splat flat renderer (treat cyan pixels as invisible) + + // FOF bustable flags + {"FB_PUSHABLES",FB_PUSHABLES}, + {"FB_EXECUTOR",FB_EXECUTOR}, + {"FB_ONLYBOTTOM",FB_ONLYBOTTOM}, + + // Bustable FOF type + {"BT_TOUCH",BT_TOUCH}, + {"BT_SPINBUST",BT_SPINBUST}, + {"BT_REGULAR",BT_REGULAR}, + {"BT_STRONG",BT_STRONG}, // PolyObject flags {"POF_CLIPLINES",POF_CLIPLINES}, ///< Test against lines for collision @@ -5373,9 +5525,12 @@ struct int_const_s const INT_CONST[] = { {"V_HUDTRANSHALF",V_HUDTRANSHALF}, {"V_HUDTRANS",V_HUDTRANS}, {"V_HUDTRANSDOUBLE",V_HUDTRANSDOUBLE}, - {"V_AUTOFADEOUT",V_AUTOFADEOUT}, - {"V_RETURN8",V_RETURN8}, - {"V_OFFSET",V_OFFSET}, + {"V_BLENDSHIFT",V_BLENDSHIFT}, + {"V_BLENDMASK",V_BLENDMASK}, + {"V_ADD",V_ADD}, + {"V_SUBTRACT",V_SUBTRACT}, + {"V_REVERSESUBTRACT",V_REVERSESUBTRACT}, + {"V_MODULATE",V_MODULATE}, {"V_ALLOWLOWERCASE",V_ALLOWLOWERCASE}, {"V_FLIP",V_FLIP}, {"V_CENTERNAMETAG",V_CENTERNAMETAG}, @@ -5383,8 +5538,8 @@ struct int_const_s const INT_CONST[] = { {"V_SNAPTOBOTTOM",V_SNAPTOBOTTOM}, {"V_SNAPTOLEFT",V_SNAPTOLEFT}, {"V_SNAPTORIGHT",V_SNAPTORIGHT}, - {"V_WRAPX",V_WRAPX}, - {"V_WRAPY",V_WRAPY}, + {"V_AUTOFADEOUT",V_AUTOFADEOUT}, + {"V_RETURN8",V_RETURN8}, {"V_NOSCALESTART",V_NOSCALESTART}, {"V_PERPLAYER",V_PERPLAYER}, @@ -5448,5 +5603,99 @@ struct int_const_s const INT_CONST[] = { {"GS_DEDICATEDSERVER",GS_DEDICATEDSERVER}, {"GS_WAITINGPLAYERS",GS_WAITINGPLAYERS}, + // Joystick axes + {"JA_NONE",JA_NONE}, + {"JA_TURN",JA_TURN}, + {"JA_MOVE",JA_MOVE}, + {"JA_LOOK",JA_LOOK}, + {"JA_STRAFE",JA_STRAFE}, + {"JA_DIGITAL",JA_DIGITAL}, + {"JA_JUMP",JA_JUMP}, + {"JA_SPIN",JA_SPIN}, + {"JA_FIRE",JA_FIRE}, + {"JA_FIRENORMAL",JA_FIRENORMAL}, + {"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}, + + // Mouse buttons + {"MB_BUTTON1",MB_BUTTON1}, + {"MB_BUTTON2",MB_BUTTON2}, + {"MB_BUTTON3",MB_BUTTON3}, + {"MB_BUTTON4",MB_BUTTON4}, + {"MB_BUTTON5",MB_BUTTON5}, + {"MB_BUTTON6",MB_BUTTON6}, + {"MB_BUTTON7",MB_BUTTON7}, + {"MB_BUTTON8",MB_BUTTON8}, + {"MB_SCROLLUP",MB_SCROLLUP}, + {"MB_SCROLLDOWN",MB_SCROLLDOWN}, + {NULL,0} }; + +// For this to work compile-time without being in this file, +// this function would need to check sizes at runtime, without sizeof +void DEH_TableCheck(void) +{ +#if defined(_DEBUG) || defined(PARANOIA) + const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*); + const size_t dehmobjs = sizeof(MOBJTYPE_LIST)/sizeof(const char*); + const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*); + const size_t dehcolors = sizeof(COLOR_ENUMS)/sizeof(const char*); + + if (dehstates != S_FIRSTFREESLOT) + I_Error("You forgot to update the Dehacked states list, you dolt!\n(%d states defined, versus %s in the Dehacked list)\n", S_FIRSTFREESLOT, sizeu1(dehstates)); + + if (dehmobjs != MT_FIRSTFREESLOT) + I_Error("You forgot to update the Dehacked mobjtype list, you dolt!\n(%d mobj types defined, versus %s in the Dehacked list)\n", MT_FIRSTFREESLOT, sizeu1(dehmobjs)); + + if (dehpowers != NUMPOWERS) + I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers)); + + if (dehcolors != SKINCOLOR_FIRSTFREESLOT) + I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors)); +#endif +} diff --git a/src/deh_tables.h b/src/deh_tables.h index 2c6b3e204..850194a96 100644 --- a/src/deh_tables.h +++ b/src/deh_tables.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -64,7 +64,11 @@ extern const char *const MOBJEFLAG_LIST[]; extern const char *const MAPTHINGFLAG_LIST[4]; extern const char *const PLAYERFLAG_LIST[]; extern const char *const GAMETYPERULE_LIST[]; -extern const char *const ML_LIST[16]; // Linedef flags +extern const char *const ML_LIST[]; // Linedef flags +extern const char *const MSF_LIST[]; // Sector flags +extern const char *const SSF_LIST[]; // Sector special flags +extern const char *const SD_LIST[]; // Sector damagetype +extern const char *const TO_LIST[]; // Sector triggerer extern const char *COLOR_ENUMS[]; extern const char *const POWERS_LIST[]; extern const char *const HUDITEMS_LIST[]; @@ -72,4 +76,7 @@ extern const char *const MENUTYPES_LIST[]; extern struct int_const_s const INT_CONST[]; +// Moved to this file because it can't work compile-time otherwise +void DEH_TableCheck(void); + #endif diff --git a/src/dehacked.c b/src/dehacked.c index b42663267..3f339e477 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -188,26 +188,11 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) dbg_line = -1; // start at -1 so the first line is 0. while (!myfeof(f)) { - char origpos[128]; - INT32 size = 0; - char *traverse; - myfgets(s, MAXLINELEN, f); memcpy(textline, s, MAXLINELEN); if (s[0] == '\n' || s[0] == '#') continue; - traverse = s; - - while (traverse[0] != '\n') - { - traverse++; - size++; - } - - strncpy(origpos, s, size); - origpos[size] = '\0'; - if (NULL != (word = strtok(s, " "))) { strupr(word); if (word[strlen(word)-1] == '\n') @@ -562,13 +547,10 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) } if (clearall || fastcmp(word2, "UNLOCKABLES")) - memset(&unlockables, 0, sizeof(unlockables)); + clear_unlockables(); if (clearall || fastcmp(word2, "EMBLEMS")) - { - memset(&emblemlocations, 0, sizeof(emblemlocations)); - numemblems = 0; - } + clear_emblems(); if (clearall || fastcmp(word2, "EXTRAEMBLEMS")) { @@ -645,25 +627,3 @@ void DEH_LoadDehackedLump(lumpnum_t lumpnum) { DEH_LoadDehackedLumpPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum), false); } - -void DEH_Check(void) -{ -#if defined(_DEBUG) || defined(PARANOIA) - const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*); - const size_t dehmobjs = sizeof(MOBJTYPE_LIST)/sizeof(const char*); - const size_t dehpowers = sizeof(POWERS_LIST)/sizeof(const char*); - const size_t dehcolors = sizeof(COLOR_ENUMS)/sizeof(const char*); - - if (dehstates != S_FIRSTFREESLOT) - I_Error("You forgot to update the Dehacked states list, you dolt!\n(%d states defined, versus %s in the Dehacked list)\n", S_FIRSTFREESLOT, sizeu1(dehstates)); - - if (dehmobjs != MT_FIRSTFREESLOT) - I_Error("You forgot to update the Dehacked mobjtype list, you dolt!\n(%d mobj types defined, versus %s in the Dehacked list)\n", MT_FIRSTFREESLOT, sizeu1(dehmobjs)); - - if (dehpowers != NUMPOWERS) - I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers)); - - if (dehcolors != SKINCOLOR_FIRSTFREESLOT) - I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", SKINCOLOR_FIRSTFREESLOT, sizeu1(dehcolors)); -#endif -} diff --git a/src/dehacked.h b/src/dehacked.h index d5256be23..b4651c66a 100644 --- a/src/dehacked.h +++ b/src/dehacked.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -30,8 +30,6 @@ typedef enum void DEH_LoadDehackedLump(lumpnum_t lumpnum); void DEH_LoadDehackedLumpPwad(UINT16 wad, UINT16 lump, boolean mainfile); -void DEH_Check(void); - fixed_t get_number(const char *word); FUNCPRINTF void deh_warning(const char *first, ...); void deh_strlcpy(char *dst, const char *src, size_t size, const char *warntext); diff --git a/src/doomdata.h b/src/doomdata.h index b3f7f5c4d..56fb5e9e9 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -123,15 +123,15 @@ typedef struct // lower texture unpegged #define ML_DONTPEGBOTTOM 16 -#define ML_EFFECT1 32 +#define ML_SKEWTD 32 // Don't let Knuckles climb on this line #define ML_NOCLIMB 64 -#define ML_EFFECT2 128 -#define ML_EFFECT3 256 -#define ML_EFFECT4 512 -#define ML_EFFECT5 1024 +#define ML_NOSKEW 128 +#define ML_MIDPEG 256 +#define ML_MIDSOLID 512 +#define ML_WRAPMIDTEX 1024 #define ML_NETONLY 2048 // Apply effect only in netgames #define ML_NONET 4096 // Apply effect only in single player games @@ -196,7 +196,7 @@ typedef struct #pragma pack() #endif -#define NUMMAPTHINGARGS 6 +#define NUMMAPTHINGARGS 10 #define NUMMAPTHINGSTRINGARGS 2 // Thing definition, position, orientation and type, diff --git a/src/doomdef.h b/src/doomdef.h index 52abc9597..2b62bcd6e 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -100,7 +100,7 @@ #include #include -#if defined (_WIN32) || defined (__DJGPP__) +#ifdef _WIN32 #include #endif @@ -112,7 +112,7 @@ //#define PARANOIA // do some tests that never fail but maybe // turn this on by make etc.. DEBUGMODE = 1 or use the Debug profile in the VC++ projects //#endif -#if defined (_WIN32) || (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) || defined (macintosh) +#if defined (_WIN32) || defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) || defined (macintosh) #define LOGMESSAGES // write message in log.txt #endif @@ -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 @@ -149,7 +150,10 @@ extern char logfilename[1024]; // Does this version require an added patch file? // Comment or uncomment this as necessary. -#define USE_PATCH_DTA +// #define USE_PATCH_DTA + +// Enforce a limit of loaded WAD files. +//#define ENFORCE_WAD_LIMIT // Use .kart extension addons //#define USE_KART @@ -397,7 +401,7 @@ extern skincolor_t skincolors[MAXSKINCOLORS]; #define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items. -// Special linedef executor tag numbers! +// Special linedef executor tag numbers! Binary map format only (UDMF has other ways of doing these things). enum { LE_PINCHPHASE = -2, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!) LE_ALLBOSSESDEAD = -3, // All bosses in the map are dead (Egg capsule raise) @@ -415,7 +419,7 @@ enum { }; // Name of local directory for config files and savegames -#if (((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON)) && !defined (__CYGWIN__)) && !defined (__APPLE__) +#if (defined (__unix__) || defined (UNIXCOMMON)) && !defined (__CYGWIN__) && !defined (__APPLE__) #define DEFAULTDIR ".srb2" #else #define DEFAULTDIR "srb2" @@ -479,8 +483,11 @@ extern void *(*M_Memcpy)(void* dest, const void* src, size_t n) FUNCNONNULL; char *va(const char *format, ...) FUNCPRINTF; char *M_GetToken(const char *inputString); void M_UnGetToken(void); -UINT32 M_GetTokenPos(void); -void M_SetTokenPos(UINT32 newPos); +void M_TokenizerOpen(const char *inputString); +void M_TokenizerClose(void); +const char *M_TokenizerRead(UINT32 i); +UINT32 M_TokenizerGetEndPos(void); +void M_TokenizerSetEndPos(UINT32 newPos); char *sizeu1(size_t num); char *sizeu2(size_t num); char *sizeu3(size_t num); @@ -526,6 +533,22 @@ extern boolean capslock; // i_system.c, replace getchar() once the keyboard has been appropriated INT32 I_GetKey(void); +/* http://www.cse.yorku.ca/~oz/hash.html */ +static inline +UINT32 quickncasehash (const char *p, size_t n) +{ + size_t i = 0; + UINT32 x = 5381; + + while (i < n && p[i]) + { + x = (x * 33) ^ tolower(p[i]); + i++; + } + + return x; +} + #ifndef min // Double-Check with WATTCP-32's cdefs.h #define min(x, y) (((x) < (y)) ? (x) : (y)) #endif @@ -604,10 +627,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// Experimental tweaks to analog mode. (Needs a lot of work before it's ready for primetime.) //#define REDSANALOG -/// Backwards compatibility with musicslots. -/// \note You should leave this enabled unless you're working with a future SRB2 version. -#define MUSICSLOT_COMPATIBILITY - /// Experimental attempts at preventing MF_PAPERCOLLISION objects from getting stuck in walls. //#define PAPER_COLLISIONCORRECTION diff --git a/src/doomstat.h b/src/doomstat.h index 2d28b81af..bce43416b 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -337,9 +337,9 @@ typedef struct fixed_t gravity; ///< Map-wide gravity. // Title card. - char ltzzpatch[8]; ///< Zig zag patch. - char ltzztext[8]; ///< Zig zag text. - char ltactdiamond[8]; ///< Act diamond. + char ltzzpatch[9]; ///< Zig zag patch. + char ltzztext[9]; ///< Zig zag text. + char ltactdiamond[9]; ///< Act diamond. // Freed animals stuff. UINT8 numFlickies; ///< Internal. For freed flicky support. @@ -496,7 +496,7 @@ extern UINT32 lastcustomtol; extern tic_t totalplaytime; -extern UINT8 stagefailed; +extern boolean stagefailed; // Emeralds stored as bits to throw savegame hackers off. extern UINT16 emeralds; diff --git a/src/doomtype.h b/src/doomtype.h index c239c7b8e..5ddd9ae44 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -54,17 +54,6 @@ typedef long ssize_t; #define PDWORD_PTR PDWORD #endif #endif -#elif defined (__DJGPP__) -#define UINT8 unsigned char -#define SINT8 signed char - -#define UINT16 unsigned short int -#define INT16 signed short int - -#define INT32 signed long -#define UINT32 unsigned long -#define INT64 signed long long -#define UINT64 unsigned long long #else #define __STDC_LIMIT_MACROS #include @@ -108,7 +97,7 @@ typedef long ssize_t; #define strncasecmp strnicmp #define strcasecmp strcmpi #endif -#if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) +#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) #undef stricmp #define stricmp(x,y) strcasecmp(x,y) #undef strnicmp @@ -136,7 +125,7 @@ char *strcasestr(const char *in, const char *what); #endif #endif //macintosh -#if defined (PC_DOS) || defined (_WIN32) || defined (__HAIKU__) +#if defined (_WIN32) || defined (__HAIKU__) #define HAVE_DOSSTR_FUNCS #endif @@ -367,6 +356,8 @@ typedef UINT32 tic_t; #define UINT2RGBA(a) (UINT32)((a&0xff)<<24)|((a&0xff00)<<8)|((a&0xff0000)>>8)|(((UINT32)a&0xff000000)>>24) #endif +#define TOSTR(x) #x + /* preprocessor dumb and needs second macro to expand input */ #define WSTRING2(s) L ## s #define WSTRING(s) WSTRING2 (s) @@ -379,6 +370,28 @@ Needed for some lua shenanigans. #define FIELDFROM( type, field, have, want ) \ (void *)((intptr_t)(field) - offsetof (type, have) + offsetof (type, want)) +typedef UINT8 bitarray_t; + +#define BIT_ARRAY_SIZE(n) (((n) + 7) >> 3) + +static inline int +in_bit_array (const bitarray_t * const array, const int value) +{ + return (array[value >> 3] & (1<<(value & 7))); +} + +static inline void +set_bit_array (bitarray_t * const array, const int value) +{ + array[value >> 3] |= (1<<(value & 7)); +} + +static inline void +unset_bit_array (bitarray_t * const array, const int value) +{ + array[value >> 3] &= ~(1<<(value & 7)); +} + #ifdef HAVE_SDL typedef UINT64 precise_t; #endif diff --git a/src/endian.h b/src/endian.h index 24d8e35cd..86297f0cb 100644 --- a/src/endian.h +++ b/src/endian.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/f_finale.c b/src/f_finale.c index b23ab4f7a..b5715b863 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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) @@ -1063,7 +1064,7 @@ boolean F_IntroResponder(event_t *event) // CREDITS // ========= static const char *credits[] = { - "\1Sonic Robo Blast II", + "\1Sonic Robo Blast 2", "\1Credits", "", "\1Game Design", @@ -1089,19 +1090,19 @@ static const char *credits[] = { "\"Hannu_Hanhi\"", // For many OpenGL performance improvements! "Kepa \"Nev3r\" Iceta", "Thomas \"Shadow Hog\" Igoe", - "\"james\"", "Iestyn \"Monster Iestyn\" Jealous", - "\"Jimita\"", "\"Kaito Sinclaire\"", "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "Ronald \"Furyhunter\" Kinard", // The SDL2 port "\"Lat'\"", // SRB2-CHAT, the chat window from Kart + "\"LZA\"", "Matthew \"Shuffle\" Marsalko", "Steven \"StroggOnMeth\" McGranahan", "\"Morph\"", // For SRB2Morphed stuff "Louis-Antoine \"LJ Sonic\" de Moulins", // de Rochefort doesn't quite fit on the screen sorry lol "John \"JTE\" Muniz", "Colin \"Sonict\" Pfaff", + "James \"james\" Robert Roman", "Sean \"Sryder13\" Ryder", "Ehab \"Wolfy\" Saeed", "Tasos \"tatokis\" Sahanidis", // Corrected C FixedMul, making 64-bit builds netplay compatible @@ -1138,6 +1139,7 @@ static const char *credits[] = { "Iestyn \"Monster Iestyn\" Jealous", "William \"GuyWithThePie\" Kloppenberg", "Alice \"Alacroix\" de Lemos", + "Logan \"Hyperchaotix\" McCloud", "Alexander \"DrTapeworm\" Moench-Ford", "Andrew \"Senku Niola\" Moran", "\"MotorRoach\"", @@ -1165,9 +1167,8 @@ static const char *credits[] = { "Alexander \"DrTapeworm\" Moench-Ford", "Stefan \"Stuf\" Rimalia", "Shane Mychal Sexton", - "\"Spazzo\"", - "David \"Big Wave Dave\" Spencer Sr.", - "David \"Instant Sonic\" Spencer Jr.", + "Dave \"Big Wave Dave\" Spencer", + "David \"instantSonic\" Spencer", "\"SSNTails\"", "", "\1Level Design", @@ -1190,7 +1191,6 @@ static const char *credits[] = { "\"Revan\"", "Anna \"QueenDelta\" Sandlin", "Wessel \"sphere\" Smit", - "\"Spazzo\"", "\"SSNTails\"", "Rob Tisdell", "\"Torgo\"", @@ -1219,7 +1219,7 @@ static const char *credits[] = { "Bill \"Tets\" Reed", "", "\1Special Thanks", - "iD Software", + "id Software", "Doom Legacy Project", "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "Kart Krew", @@ -1398,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) @@ -2545,28 +2545,28 @@ static void F_UnloadAlacroixGraphics(SINT8 oldttscale) oldttscale--; // zero-based index for (i = 0; i < TTMAX_ALACROIX; i++) { - if(ttembl[oldttscale][i]) { Z_Free(ttembl[oldttscale][i]); ttembl[oldttscale][i] = 0; } - if(ttribb[oldttscale][i]) { Z_Free(ttribb[oldttscale][i]); ttribb[oldttscale][i] = 0; } - if(ttsont[oldttscale][i]) { Z_Free(ttsont[oldttscale][i]); ttsont[oldttscale][i] = 0; } - if(ttrobo[oldttscale][i]) { Z_Free(ttrobo[oldttscale][i]); ttrobo[oldttscale][i] = 0; } - if(tttwot[oldttscale][i]) { Z_Free(tttwot[oldttscale][i]); tttwot[oldttscale][i] = 0; } - if(ttrbtx[oldttscale][i]) { Z_Free(ttrbtx[oldttscale][i]); ttrbtx[oldttscale][i] = 0; } - if(ttsoib[oldttscale][i]) { Z_Free(ttsoib[oldttscale][i]); ttsoib[oldttscale][i] = 0; } - if(ttsoif[oldttscale][i]) { Z_Free(ttsoif[oldttscale][i]); ttsoif[oldttscale][i] = 0; } - if(ttsoba[oldttscale][i]) { Z_Free(ttsoba[oldttscale][i]); ttsoba[oldttscale][i] = 0; } - if(ttsobk[oldttscale][i]) { Z_Free(ttsobk[oldttscale][i]); ttsobk[oldttscale][i] = 0; } - if(ttsodh[oldttscale][i]) { Z_Free(ttsodh[oldttscale][i]); ttsodh[oldttscale][i] = 0; } - if(tttaib[oldttscale][i]) { Z_Free(tttaib[oldttscale][i]); tttaib[oldttscale][i] = 0; } - if(tttaif[oldttscale][i]) { Z_Free(tttaif[oldttscale][i]); tttaif[oldttscale][i] = 0; } - if(tttaba[oldttscale][i]) { Z_Free(tttaba[oldttscale][i]); tttaba[oldttscale][i] = 0; } - if(tttabk[oldttscale][i]) { Z_Free(tttabk[oldttscale][i]); tttabk[oldttscale][i] = 0; } - if(tttabt[oldttscale][i]) { Z_Free(tttabt[oldttscale][i]); tttabt[oldttscale][i] = 0; } - if(tttaft[oldttscale][i]) { Z_Free(tttaft[oldttscale][i]); tttaft[oldttscale][i] = 0; } - if(ttknib[oldttscale][i]) { Z_Free(ttknib[oldttscale][i]); ttknib[oldttscale][i] = 0; } - if(ttknif[oldttscale][i]) { Z_Free(ttknif[oldttscale][i]); ttknif[oldttscale][i] = 0; } - if(ttknba[oldttscale][i]) { Z_Free(ttknba[oldttscale][i]); ttknba[oldttscale][i] = 0; } - if(ttknbk[oldttscale][i]) { Z_Free(ttknbk[oldttscale][i]); ttknbk[oldttscale][i] = 0; } - if(ttkndh[oldttscale][i]) { Z_Free(ttkndh[oldttscale][i]); ttkndh[oldttscale][i] = 0; } + if(ttembl[oldttscale][i]) { Patch_Free(ttembl[oldttscale][i]); ttembl[oldttscale][i] = 0; } + if(ttribb[oldttscale][i]) { Patch_Free(ttribb[oldttscale][i]); ttribb[oldttscale][i] = 0; } + if(ttsont[oldttscale][i]) { Patch_Free(ttsont[oldttscale][i]); ttsont[oldttscale][i] = 0; } + if(ttrobo[oldttscale][i]) { Patch_Free(ttrobo[oldttscale][i]); ttrobo[oldttscale][i] = 0; } + if(tttwot[oldttscale][i]) { Patch_Free(tttwot[oldttscale][i]); tttwot[oldttscale][i] = 0; } + if(ttrbtx[oldttscale][i]) { Patch_Free(ttrbtx[oldttscale][i]); ttrbtx[oldttscale][i] = 0; } + if(ttsoib[oldttscale][i]) { Patch_Free(ttsoib[oldttscale][i]); ttsoib[oldttscale][i] = 0; } + if(ttsoif[oldttscale][i]) { Patch_Free(ttsoif[oldttscale][i]); ttsoif[oldttscale][i] = 0; } + if(ttsoba[oldttscale][i]) { Patch_Free(ttsoba[oldttscale][i]); ttsoba[oldttscale][i] = 0; } + if(ttsobk[oldttscale][i]) { Patch_Free(ttsobk[oldttscale][i]); ttsobk[oldttscale][i] = 0; } + if(ttsodh[oldttscale][i]) { Patch_Free(ttsodh[oldttscale][i]); ttsodh[oldttscale][i] = 0; } + if(tttaib[oldttscale][i]) { Patch_Free(tttaib[oldttscale][i]); tttaib[oldttscale][i] = 0; } + if(tttaif[oldttscale][i]) { Patch_Free(tttaif[oldttscale][i]); tttaif[oldttscale][i] = 0; } + if(tttaba[oldttscale][i]) { Patch_Free(tttaba[oldttscale][i]); tttaba[oldttscale][i] = 0; } + if(tttabk[oldttscale][i]) { Patch_Free(tttabk[oldttscale][i]); tttabk[oldttscale][i] = 0; } + if(tttabt[oldttscale][i]) { Patch_Free(tttabt[oldttscale][i]); tttabt[oldttscale][i] = 0; } + if(tttaft[oldttscale][i]) { Patch_Free(tttaft[oldttscale][i]); tttaft[oldttscale][i] = 0; } + if(ttknib[oldttscale][i]) { Patch_Free(ttknib[oldttscale][i]); ttknib[oldttscale][i] = 0; } + if(ttknif[oldttscale][i]) { Patch_Free(ttknif[oldttscale][i]); ttknif[oldttscale][i] = 0; } + if(ttknba[oldttscale][i]) { Patch_Free(ttknba[oldttscale][i]); ttknba[oldttscale][i] = 0; } + if(ttknbk[oldttscale][i]) { Patch_Free(ttknbk[oldttscale][i]); ttknbk[oldttscale][i] = 0; } + if(ttkndh[oldttscale][i]) { Patch_Free(ttkndh[oldttscale][i]); ttkndh[oldttscale][i] = 0; } } ttloaded[oldttscale] = false; } @@ -3422,7 +3422,7 @@ void F_TitleScreenDrawer(void) } luahook: - LUAh_TitleHUD(); + LUA_HUDHOOK(title); } // separate animation timer for backgrounds, since we also count @@ -3822,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/f_finale.h b/src/f_finale.h index b3abf1778..efdc9d4ad 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/f_wipe.c b/src/f_wipe.c index 6afb8a6a7..43b7180b7 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/filesrch.c b/src/filesrch.c index cb53d07be..3f901b695 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 @@ -337,8 +338,10 @@ size_t dir_on[menudepth]; UINT8 refreshdirmenu = 0; char *refreshdirname = NULL; -size_t packetsizetally = 0; -size_t mainwadstally = 0; +#define dirpathlen 1024 +#define maxdirdepth 48 + +#define isuptree(dirent) ((dirent)[0]=='.' && ((dirent)[1]=='\0' || ((dirent)[1]=='.' && (dirent)[2]=='\0'))) filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) { @@ -387,10 +390,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want continue; } - if (dent->d_name[0]=='.' && - (dent->d_name[1]=='\0' || - (dent->d_name[1]=='.' && - dent->d_name[2]=='\0'))) + if (isuptree(dent->d_name)) { // we don't want to scan uptree continue; @@ -445,6 +445,380 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want return retval; } +#ifndef AVOID_ERRNO +int direrror = 0; +#endif + +// Checks if the specified path is a directory. +// Returns 1 if so, 0 if not, and -1 if an error occurred. +// direrror is set if there was an error. +INT32 pathisdirectory(const char *path) +{ + struct stat fsstat; + + if (stat(path, &fsstat) < 0) + { +#ifndef AVOID_ERRNO + direrror = errno; +#endif + return -1; + } + else if (S_ISDIR(fsstat.st_mode)) + return 1; + + return 0; +} + +// Concatenates two paths, and checks if it is a directory that can be opened. +// Returns 1 if so, 0 if not, and -1 if an error occurred. +INT32 concatpaths(const char *path, const char *startpath) +{ + char dirpath[dirpathlen]; + DIR *dirhandle; + INT32 stat; + + if (startpath) + { + char basepath[dirpathlen]; + + snprintf(basepath, sizeof basepath, "%s" PATHSEP, startpath); + snprintf(dirpath, sizeof dirpath, "%s%s", basepath, path); + + // Base path and directory path are the same? Not valid. + stat = samepaths(basepath, dirpath); + + if (stat == 1) + return 0; + else if (stat < 0) + return -1; + } + else + snprintf(dirpath, sizeof dirpath, "%s", path); + + // Check if the path is a directory. + // Will return -1 if there was an error. + stat = pathisdirectory(dirpath); + if (stat == 0) + return 0; + else if (stat < 0) + { + // The path doesn't exist, so it can't be a directory. + if (direrror == ENOENT) + return 0; + + return -1; + } + + // Open the directory. + // Will return 0 if it couldn't be opened. + dirhandle = opendir(dirpath); + if (dirhandle == NULL) + return 0; + else + closedir(dirhandle); + + return 1; +} + +// Checks if two paths are the same. Returns 1 if so, and 0 if not. +// Returns -1 if an error occurred with the first path, +// and returns -2 if an error occurred with the second path. +// direrror is set if there was an error. +INT32 samepaths(const char *path1, const char *path2) +{ + struct stat stat1; + struct stat stat2; + + if (stat(path1, &stat1) < 0) + { +#ifndef AVOID_ERRNO + direrror = errno; +#endif + return -1; + } + if (stat(path2, &stat2) < 0) + { +#ifndef AVOID_ERRNO + direrror = errno; +#endif + return -2; + } + + if (stat1.st_dev == stat2.st_dev) + { +#if !defined(_WIN32) + return (stat1.st_ino == stat2.st_ino); +#else + // The above doesn't work on NTFS or FAT. + HANDLE file1 = CreateFileA(path1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + HANDLE file2 = CreateFileA(path2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + BY_HANDLE_FILE_INFORMATION file1info, file2info; + + if (file1 == INVALID_HANDLE_VALUE) + { +#ifndef AVOID_ERRNO + direrror = ENOENT; +#endif + return -1; + } + else if (file2 == INVALID_HANDLE_VALUE) + { + CloseHandle(file1); +#ifndef AVOID_ERRNO + direrror = ENOENT; +#endif + return -2; + } + + // I have no idea why GetFileInformationByHandle would fail. + // Microsoft's documentation doesn't tell me. + // I'll just use EIO... + if (!GetFileInformationByHandle(file1, &file1info)) + { +#ifndef AVOID_ERRNO + direrror = EIO; +#endif + return -1; + } + else if (!GetFileInformationByHandle(file2, &file2info)) + { + CloseHandle(file1); + CloseHandle(file2); +#ifndef AVOID_ERRNO + direrror = EIO; +#endif + return -2; + } + + if (file1info.dwVolumeSerialNumber == file2info.dwVolumeSerialNumber + && file1info.nFileIndexLow == file2info.nFileIndexLow + && file1info.nFileIndexHigh == file2info.nFileIndexHigh) + { + CloseHandle(file1); + CloseHandle(file2); + return 1; + } + + return 0; +#endif + } + + return 0; +} + +// +// Directory loading +// + +static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft) +{ + dirpathindex[depthleft] = strlen(dirpath) + 1; + + if (dirpath[dirpathindex[depthleft]-2] != PATHSEP[0]) + { + dirpath[dirpathindex[depthleft]-1] = PATHSEP[0]; + dirpath[dirpathindex[depthleft]] = 0; + } + else + dirpathindex[depthleft]--; +} + +lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders) +{ + DIR **dirhandle; + struct dirent *dent; + struct stat fsstat; + + int rootdir = (maxdirdepth - 1); + int depthleft = rootdir; + + char dirpath[dirpathlen]; + size_t *dirpathindex; + + lumpinfo_t *lumpinfo, *lump_p; + UINT16 i = 0, numlumps = 0; + + boolean failure = false; + + dirhandle = (DIR **)malloc(maxdirdepth * sizeof (DIR*)); + dirpathindex = (size_t *)malloc(maxdirdepth * sizeof(size_t)); + + // Open the root directory + strlcpy(dirpath, path, dirpathlen); + dirhandle[depthleft] = opendir(dirpath); + + if (dirhandle[depthleft] == NULL) + { + free(dirhandle); + free(dirpathindex); + return NULL; + } + + initdirpath(dirpath, dirpathindex, depthleft); + (*nfolders) = 0; + + // Count files and directories + while (depthleft < maxdirdepth) + { + dirpath[dirpathindex[depthleft]] = 0; + dent = readdir(dirhandle[depthleft]); + + if (!dent) + { + if (depthleft != rootdir) // Don't close the root directory + closedir(dirhandle[depthleft]); + depthleft++; + continue; + } + else if (isuptree(dent->d_name)) + continue; + + strcpy(&dirpath[dirpathindex[depthleft]], dent->d_name); + + if (stat(dirpath, &fsstat) < 0) + ; + else if (S_ISDIR(fsstat.st_mode) && depthleft) + { + dirpathindex[--depthleft] = strlen(dirpath) + 1; + dirhandle[depthleft] = opendir(dirpath); + + if (dirhandle[depthleft]) + (*nfolders)++; + else + depthleft++; + + dirpath[dirpathindex[depthleft]-1] = '/'; + dirpath[dirpathindex[depthleft]] = 0; + } + else + numlumps++; + + // Failure: Too many files. + if (numlumps == UINT16_MAX) + { + (*nlmp) = UINT16_MAX; + failure = true; + break; + } + } + + // Failure: No files have been found. + if (!numlumps) + { + (*nlmp) = 0; + failure = true; + } + + // Close any open directories and return if something went wrong. + if (failure) + { + for (; depthleft < maxdirdepth; closedir(dirhandle[depthleft++])); + free(dirpathindex); + free(dirhandle); + return NULL; + } + + // Create the files and directories as lump entries + // It's possible to create lumps and count files at the same time, + // but I didn't want to have to reallocate memory for every lump. + rewinddir(dirhandle[rootdir]); + depthleft = rootdir; + + strlcpy(dirpath, path, dirpathlen); + initdirpath(dirpath, dirpathindex, depthleft); + + lump_p = lumpinfo = Z_Calloc(numlumps * sizeof(lumpinfo_t), PU_STATIC, NULL); + + while (depthleft < maxdirdepth) + { + char *fullname, *trimname; + + dirpath[dirpathindex[depthleft]] = 0; + dent = readdir(dirhandle[depthleft]); + + if (!dent) + { + closedir(dirhandle[depthleft++]); + continue; + } + else if (isuptree(dent->d_name)) + continue; + + strcpy(&dirpath[dirpathindex[depthleft]], dent->d_name); + + if (stat(dirpath, &fsstat) < 0) + continue; + else if (S_ISDIR(fsstat.st_mode) && depthleft) + { + dirpathindex[--depthleft] = strlen(dirpath) + 1; + dirhandle[depthleft] = opendir(dirpath); + + if (dirhandle[depthleft]) + { + dirpath[dirpathindex[depthleft]-1] = '/'; + dirpath[dirpathindex[depthleft]] = 0; + } + else + depthleft++; + + continue; + } + + lump_p->diskpath = Z_StrDup(dirpath); // Path in the filesystem to the file + lump_p->compression = CM_NOCOMPRESSION; // Lump is uncompressed + + // Remove the directory's path. + fullname = lump_p->diskpath; + if (strstr(fullname, path)) + fullname += strlen(path) + 1; + + // Get the 8-character long lump name. + trimname = strrchr(fullname, '/'); + if (trimname) + trimname++; + else + trimname = fullname; + + if (trimname[0]) + { + char *dotpos = strrchr(trimname, '.'); + if (dotpos == NULL) + dotpos = fullname + strlen(fullname); + + strncpy(lump_p->name, trimname, min(8, dotpos - trimname)); + + // The name of the file, without the extension. + lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL); + strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); + } + else + lump_p->longname = Z_Calloc(1, PU_STATIC, NULL); + + // The complete name of the file, with its extension, + // excluding the path of the directory where it resides. + lump_p->fullname = Z_StrDup(fullname); + + lump_p++; + i++; + + if (i > numlumps || i == (UINT16_MAX-1)) + { + for (; depthleft < maxdirdepth; closedir(dirhandle[depthleft++])); // Close any open directories. + break; + } + } + + free(dirpathindex); + free(dirhandle); + + (*nlmp) = numlumps; + return lumpinfo; +} + +// +// Addons menu +// + char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two) "\5.txt", "\5.cfg", // exec "\5.wad", @@ -453,8 +827,7 @@ char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) pl #endif "\5.pk3", "\5.soc", "\5.lua"}; // addfile -char filenamebuf[MAX_WADFILES][MAX_WADPATH]; - +static char (*filenamebuf)[MAX_WADPATH]; static boolean filemenucmp(char *haystack, char *needle) { @@ -640,10 +1013,7 @@ boolean preparefilemenu(boolean samedepth) if (!dent) break; - else if (dent->d_name[0]=='.' && - (dent->d_name[1]=='\0' || - (dent->d_name[1]=='.' && - dent->d_name[2]=='\0'))) + else if (isuptree(dent->d_name)) continue; // we don't want to scan uptree strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); @@ -704,10 +1074,7 @@ boolean preparefilemenu(boolean samedepth) if (!dent) break; - else if (dent->d_name[0]=='.' && - (dent->d_name[1]=='\0' || - (dent->d_name[1]=='.' && - dent->d_name[2]=='\0'))) + else if (isuptree(dent->d_name)) continue; // we don't want to scan uptree strcpy(&menupath[menupathindex[menudepthleft]],dent->d_name); @@ -732,6 +1099,10 @@ boolean preparefilemenu(boolean samedepth) if (ext >= EXT_LOADSTART) { size_t i; + + if (filenamebuf == NULL) + filenamebuf = calloc(sizeof(char) * MAX_WADPATH, numwadfiles); + for (i = 0; i < numwadfiles; i++) { if (!filenamebuf[i][0]) @@ -781,6 +1152,12 @@ boolean preparefilemenu(boolean samedepth) } } + if (filenamebuf) + { + free(filenamebuf); + filenamebuf = NULL; + } + closedir(dirhandle); if ((menudepthleft != menudepth-1) // now for UP... entry diff --git a/src/filesrch.h b/src/filesrch.h index dfea8979e..59ef5269b 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]; @@ -42,9 +53,6 @@ extern size_t dir_on[menudepth]; extern UINT8 refreshdirmenu; extern char *refreshdirname; -extern size_t packetsizetally; -extern size_t mainwadstally; - typedef enum { EXT_FOLDER = 0, @@ -94,5 +102,4 @@ typedef enum void closefilemenu(boolean validsize); void searchfilemenu(char *tempname); boolean preparefilemenu(boolean samedepth); - #endif // __FILESRCH_H__ diff --git a/src/g_demo.c b/src/g_demo.c index 593fd7723..77c9ab10b 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -94,7 +94,7 @@ demoghost *ghosts = NULL; // DEMO RECORDING // -#define DEMOVERSION 0x000e +#define DEMOVERSION 0x000f #define DEMOHEADER "\xF0" "SRB2Replay" "\x0F" #define DF_GHOST 0x01 // This demo contains ghost data too! @@ -109,6 +109,7 @@ demoghost *ghosts = NULL; #define ZT_ANGLE 0x04 #define ZT_BUTTONS 0x08 #define ZT_AIMING 0x10 +#define ZT_LATENCY 0x20 #define DEMOMARKER 0x80 // demoend #define METALDEATH 0x44 #define METALSNICE 0x69 @@ -181,6 +182,8 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) oldcmd.buttons = (oldcmd.buttons & (BT_CAMLEFT|BT_CAMRIGHT)) | (READUINT16(demo_p) & ~(BT_CAMLEFT|BT_CAMRIGHT)); if (ziptic & ZT_AIMING) oldcmd.aiming = READINT16(demo_p); + if (ziptic & ZT_LATENCY) + oldcmd.latency = READUINT8(demo_p); G_CopyTiccmd(cmd, &oldcmd, 1); players[playernum].angleturn = cmd->angleturn; @@ -238,6 +241,13 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) ziptic |= ZT_AIMING; } + if (cmd->latency != oldcmd.latency) + { + WRITEUINT8(demo_p,cmd->latency); + oldcmd.latency = cmd->latency; + ziptic |= ZT_LATENCY; + } + *ziptic_p = ziptic; // attention here for the ticcmd size! @@ -679,6 +689,8 @@ void G_GhostTicker(void) g->p += 2; if (ziptic & ZT_AIMING) g->p += 2; + if (ziptic & ZT_LATENCY) + g->p++; // Grab ghost data. ziptic = READUINT8(g->p); @@ -1017,7 +1029,11 @@ void G_ReadMetalTic(mobj_t *metal) if (ziptic & GZT_ANGLE) metal->angle = READUINT8(metal_p)<<24; if (ziptic & GZT_FRAME) + { oldmetal.frame = READUINT32(metal_p); + if (metalversion < 0x000f) + oldmetal.frame = G_ConvertOldFrameFlags(oldmetal.frame); + } if (ziptic & GZT_SPR2) oldmetal.sprite2 = READUINT8(metal_p); @@ -1157,6 +1173,8 @@ void G_ReadMetalTic(mobj_t *metal) follow->sprite2 = 0; follow->sprite = READUINT16(metal_p); follow->frame = READUINT32(metal_p); // NOT & FF_FRAMEMASK here, so 32 bits + if (metalversion < 0x000f) + follow->frame = G_ConvertOldFrameFlags(follow->frame); follow->angle = metal->angle; follow->color = (metalversion==0x000c) ? READUINT8(metal_p) : READUINT16(metal_p); @@ -1668,7 +1686,9 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname) switch(oldversion) // demoversion { case DEMOVERSION: // latest always supported - case 0x000c: // all that changed between then and now was longer color name + case 0x000e: // The previous demoversions also supported + case 0x000d: // all that changed between then and now was longer color name + case 0x000c: break; // too old, cannot support. default: @@ -1811,6 +1831,7 @@ void G_DoPlayDemo(char *defdemoname) switch(demoversion) { case 0x000d: + case 0x000e: case DEMOVERSION: // latest always supported cnamelen = MAXCOLORNAME; break; @@ -1956,7 +1977,7 @@ void G_DoPlayDemo(char *defdemoname) // Set skin SetPlayerSkin(0, skin); - LUAh_MapChange(gamemap); + LUA_HookInt(gamemap, HOOK(MapChange)); displayplayer = consoleplayer = 0; memset(playeringame,0,sizeof(playeringame)); playeringame[0] = true; @@ -2011,7 +2032,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; @@ -2059,11 +2080,12 @@ void G_AddGhost(char *defdemoname) return; } p += 12; // DEMOHEADER p++; // VERSION - p++; // SUBVERSION + subversion = READUINT8(p); // SUBVERSION ghostversion = READUINT16(p); switch(ghostversion) { case 0x000d: + case 0x000e: case DEMOVERSION: // latest always supported cnamelen = MAXCOLORNAME; break; @@ -2158,9 +2180,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) @@ -2189,7 +2221,7 @@ void G_AddGhost(char *defdemoname) gh->mo->angle = FixedAngle(mthing->angle << FRACBITS); f = gh->mo->floorz; c = gh->mo->ceilingz - mobjinfo[MT_PLAYER].height; - if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) + if (!!(mthing->args[0]) ^ !!(mthing->options & MTF_OBJECTFLIP)) { z = c - offset; if (z < f) @@ -2314,8 +2346,9 @@ void G_DoPlayMetal(void) switch(metalversion) { case DEMOVERSION: // latest always supported - case 0x000d: // There are checks wheter the momentum is from older demo versions or not - case 0x000c: // all that changed between then and now was longer color name + case 0x000e: // There are checks wheter the momentum is from older demo versions or not + case 0x000d: // all that changed between then and now was longer color name + case 0x000c: break; // too old, cannot support. default: @@ -2410,12 +2443,13 @@ ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) { WRITEUINT8(demo_p, (kill) ? METALDEATH : DEMOMARKER); // add the demo end (or metal death) marker WriteDemoChecksum(); - saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file. + sprintf(demoname, "%sMS.LMP", G_BuildMapName(gamemap)); + saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file. } free(demobuffer); metalrecording = false; if (saved) - I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); + I_Error("Saved to %s", demoname); I_Error("Failed to save demo!"); } @@ -2530,3 +2564,45 @@ boolean G_CheckDemoStatus(void) return false; } + +// 2.2.10 shifted some frame flags around, this function converts frame flags from older versions to their 2.2.10 equivalents. +INT32 G_ConvertOldFrameFlags(INT32 frame) +{ + if (frame & 0x01000000) // was FF_ANIMATE, is now FF_VERTICALFLIP + { + frame &= ~0x01000000; + frame |= FF_ANIMATE; + } + + if (frame & 0x02000000) // was FF_RANDOMANIM, is now FF_HORIZONTALFLIP + { + frame &= ~0x02000000; + frame |= FF_RANDOMANIM; + } + + if (frame & 0x04000000) // was FF_GLOBALANIM, is now empty + { + frame &= ~0x04000000; + frame |= FF_GLOBALANIM; + } + + if (frame & 0x00200000) // was FF_VERTICALFLIP, is now FF_FULLDARK + { + frame &= ~0x00200000; + frame |= FF_VERTICALFLIP; + } + + if (frame & 0x00400000) // was FF_HORIZONTALFLIP, is now FF_PAPERSPRITE + { + frame &= ~0x00400000; + frame |= FF_HORIZONTALFLIP; + } + + if (frame & 0x00800000) // was FF_PAPERSPRITE, is now FF_FLOORSPRITE + { + frame &= ~0x00800000; + frame |= FF_PAPERSPRITE; + } + + return frame; +} diff --git a/src/g_demo.h b/src/g_demo.h index df25042c4..37664dc71 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -82,5 +82,6 @@ void G_StopMetalDemo(void); ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill); void G_StopDemo(void); boolean G_CheckDemoStatus(void); +INT32 G_ConvertOldFrameFlags(INT32 frame); #endif // __G_DEMO__ diff --git a/src/g_game.c b/src/g_game.c index 6171c7b72..39d003056 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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" @@ -169,7 +170,7 @@ static boolean exitgame = false; static boolean retrying = false; static boolean retryingmodeattack = false; -UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage. +boolean stagefailed = false; // Used for GEMS BONUS? Also to see if you beat the stage. UINT16 emeralds; INT32 luabanks[NUM_LUABANKS]; @@ -345,8 +346,8 @@ consvar_t cv_analog[2] = { CVAR_INIT ("sessionanalog2", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog2_OnChange), }; consvar_t cv_useranalog[2] = { - CVAR_INIT ("configanalog", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog_OnChange), - CVAR_INIT ("configanalog2", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog2_OnChange), + CVAR_INIT ("configanalog", "On", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog_OnChange), + CVAR_INIT ("configanalog2", "On", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog2_OnChange), }; // deez New User eXperiences @@ -361,8 +362,8 @@ consvar_t cv_autobrake2 = CVAR_INIT ("autobrake2", "On", CV_SAVE|CV_CALL, CV_OnO // hi here's some new controls static CV_PossibleValue_t zerotoone_cons_t[] = {{0, "MIN"}, {FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_cam_shiftfacing[2] = { - CVAR_INIT ("cam_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), - CVAR_INIT ("cam2_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), + CVAR_INIT ("cam_shiftfacingchar", "0.375", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), + CVAR_INIT ("cam2_shiftfacingchar", "0.375", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), }; consvar_t cv_cam_turnfacing[2] = { CVAR_INIT ("cam_turnfacingchar", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), @@ -373,12 +374,12 @@ consvar_t cv_cam_turnfacingability[2] = { CVAR_INIT ("cam2_turnfacingability", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), }; consvar_t cv_cam_turnfacingspindash[2] = { - CVAR_INIT ("cam_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), - CVAR_INIT ("cam2_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), + CVAR_INIT ("cam_turnfacingspindash", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), + CVAR_INIT ("cam2_turnfacingspindash", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), }; consvar_t cv_cam_turnfacinginput[2] = { - CVAR_INIT ("cam_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), - CVAR_INIT ("cam2_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), + CVAR_INIT ("cam_turnfacinginput", "0.375", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), + CVAR_INIT ("cam2_turnfacinginput", "0.375", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL), }; static CV_PossibleValue_t centertoggle_cons_t[] = {{0, "Hold"}, {1, "Toggle"}, {2, "Sticky Hold"}, {0, NULL}}; @@ -402,44 +403,28 @@ static CV_PossibleValue_t lockedassist_cons_t[] = { {0, NULL} }; consvar_t cv_cam_lockonboss[2] = { - CVAR_INIT ("cam_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL), - CVAR_INIT ("cam2_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL), + CVAR_INIT ("cam_lockaimassist", "Full", CV_SAVE, lockedassist_cons_t, NULL), + CVAR_INIT ("cam2_lockaimassist", "Full", CV_SAVE, lockedassist_cons_t, NULL), }; -typedef enum -{ - AXISNONE = 0, - AXISTURN, - AXISMOVE, - AXISLOOK, - AXISSTRAFE, - - AXISDIGITAL, // axes below this use digital deadzone - - AXISJUMP, - AXISSPIN, - AXISFIRE, - AXISFIRENORMAL, -} axis_input_e; - -consvar_t cv_turnaxis = CVAR_INIT ("joyaxis_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_moveaxis = CVAR_INIT ("joyaxis_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_sideaxis = CVAR_INIT ("joyaxis_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_lookaxis = CVAR_INIT ("joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_turnaxis = CVAR_INIT ("joyaxis_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_jumpaxis = CVAR_INIT ("joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_spinaxis = CVAR_INIT ("joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL); -consvar_t cv_fireaxis = CVAR_INIT ("joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_fireaxis = CVAR_INIT ("joyaxis_fire", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_firenaxis = CVAR_INIT ("joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_deadzone = CVAR_INIT ("joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); consvar_t cv_digitaldeadzone = CVAR_INIT ("joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); -consvar_t cv_turnaxis2 = CVAR_INIT ("joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_moveaxis2 = CVAR_INIT ("joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_sideaxis2 = CVAR_INIT ("joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_lookaxis2 = CVAR_INIT ("joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_turnaxis2 = CVAR_INIT ("joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_jumpaxis2 = CVAR_INIT ("joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_spinaxis2 = CVAR_INIT ("joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL); -consvar_t cv_fireaxis2 = CVAR_INIT ("joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL); +consvar_t cv_fireaxis2 = CVAR_INIT ("joyaxis2_fire", "Z-Rudder", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_firenaxis2 = CVAR_INIT ("joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL); consvar_t cv_deadzone2 = CVAR_INIT ("joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); consvar_t cv_digitaldeadzone2 = CVAR_INIT ("joy_digdeadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL); @@ -841,7 +826,7 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming) return (INT16)((*aiming)>>16); } -static INT32 JoyAxis(axis_input_e axissel) +INT32 JoyAxis(joyaxis_e axissel) { INT32 retaxis; INT32 axisval; @@ -850,28 +835,28 @@ static INT32 JoyAxis(axis_input_e axissel) //find what axis to get switch (axissel) { - case AXISTURN: + case JA_TURN: axisval = cv_turnaxis.value; break; - case AXISMOVE: + case JA_MOVE: axisval = cv_moveaxis.value; break; - case AXISLOOK: + case JA_LOOK: axisval = cv_lookaxis.value; break; - case AXISSTRAFE: + case JA_STRAFE: axisval = cv_sideaxis.value; break; - case AXISJUMP: + case JA_JUMP: axisval = cv_jumpaxis.value; break; - case AXISSPIN: + case JA_SPIN: axisval = cv_spinaxis.value; break; - case AXISFIRE: + case JA_FIRE: axisval = cv_fireaxis.value; break; - case AXISFIRENORMAL: + case JA_FIRENORMAL: axisval = cv_firenaxis.value; break; default: @@ -903,7 +888,7 @@ static INT32 JoyAxis(axis_input_e axissel) if (retaxis > (+JOYAXISRANGE)) retaxis = +JOYAXISRANGE; - if (!Joystick.bGamepadStyle && axissel > AXISDIGITAL) + if (!Joystick.bGamepadStyle && axissel >= JA_DIGITAL) { const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_digitaldeadzone.value) >> FRACBITS; if (-jdeadzone < retaxis && retaxis < jdeadzone) @@ -914,7 +899,7 @@ static INT32 JoyAxis(axis_input_e axissel) return retaxis; } -static INT32 Joy2Axis(axis_input_e axissel) +INT32 Joy2Axis(joyaxis_e axissel) { INT32 retaxis; INT32 axisval; @@ -923,28 +908,28 @@ static INT32 Joy2Axis(axis_input_e axissel) //find what axis to get switch (axissel) { - case AXISTURN: + case JA_TURN: axisval = cv_turnaxis2.value; break; - case AXISMOVE: + case JA_MOVE: axisval = cv_moveaxis2.value; break; - case AXISLOOK: + case JA_LOOK: axisval = cv_lookaxis2.value; break; - case AXISSTRAFE: + case JA_STRAFE: axisval = cv_sideaxis2.value; break; - case AXISJUMP: + case JA_JUMP: axisval = cv_jumpaxis2.value; break; - case AXISSPIN: + case JA_SPIN: axisval = cv_spinaxis2.value; break; - case AXISFIRE: + case JA_FIRE: axisval = cv_fireaxis2.value; break; - case AXISFIRENORMAL: + case JA_FIRENORMAL: axisval = cv_firenaxis2.value; break; default: @@ -978,7 +963,7 @@ static INT32 Joy2Axis(axis_input_e axissel) if (retaxis > (+JOYAXISRANGE)) retaxis = +JOYAXISRANGE; - if (!Joystick2.bGamepadStyle && axissel > AXISDIGITAL) + if (!Joystick2.bGamepadStyle && axissel >= JA_DIGITAL) { const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_digitaldeadzone2.value) >> FRACBITS; if (-jdeadzone < retaxis && retaxis < jdeadzone) @@ -1087,14 +1072,14 @@ 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); angle_t drawangleoffset = (player->powers[pw_carry] == CR_ROLLOUT) ? ANGLE_180 : 0; INT32 chasecam, chasefreelook, alwaysfreelook, usejoystick, invertmouse, turnmultiplier, mousemove; controlstyle_e controlstyle = G_ControlStyle(ssplayer); - INT32 *mx; INT32 *my; INT32 *mly; + INT32 mdx, mdy, mldy; static INT32 turnheld[2]; // for accelerative turning static boolean keyboard_look[2]; // true if lookup/down using keyboard @@ -1117,9 +1102,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) invertmouse = cv_invertmouse.value; turnmultiplier = cv_cam_turnmultiplier.value; mousemove = cv_mousemove.value; - mx = &mousex; - my = &mousey; - mly = &mlooky; + mdx = mouse.dx; + mdy = -mouse.dy; + mldy = -mouse.mlookdy; G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver } else @@ -1131,12 +1116,15 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) invertmouse = cv_invertmouse2.value; turnmultiplier = cv_cam2_turnmultiplier.value; mousemove = cv_mousemove2.value; - mx = &mouse2x; - my = &mouse2y; - mly = &mlook2y; + mdx = mouse2.dx; + mdy = -mouse2.dy; + mldy = -mouse2.mlookdy; G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver } + if (menuactive || CON_Ready() || chat_on) + mdx = mdy = mldy = 0; + strafeisturn = controlstyle == CS_SIMPLE && ticcmd_centerviewdown[forplayer] && ((cv_cam_lockedinput[forplayer].value && !ticcmd_ztargetfocus[forplayer]) || (player->pflags & PF_STARTDASH)) && !player->climbing && player->powers[pw_carry] != CR_MINECART; @@ -1152,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) { @@ -1167,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; @@ -1179,10 +1167,10 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) *myaiming = 0; joyaiming[forplayer] = thisjoyaiming; - turnaxis = PlayerJoyAxis(ssplayer, AXISTURN); + turnaxis = PlayerJoyAxis(ssplayer, JA_TURN); if (strafeisturn) - turnaxis += PlayerJoyAxis(ssplayer, AXISSTRAFE); - lookaxis = PlayerJoyAxis(ssplayer, AXISLOOK); + turnaxis += PlayerJoyAxis(ssplayer, JA_STRAFE); + lookaxis = PlayerJoyAxis(ssplayer, JA_LOOK); lookjoystickvector.xaxis = turnaxis; lookjoystickvector.yaxis = lookaxis; G_HandleAxisDeadZone(forplayer, &lookjoystickvector); @@ -1261,8 +1249,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) tta_factor[forplayer] = 0; // suspend turn to angle } - strafeaxis = strafeisturn ? 0 : PlayerJoyAxis(ssplayer, AXISSTRAFE); - moveaxis = PlayerJoyAxis(ssplayer, AXISMOVE); + strafeaxis = strafeisturn ? 0 : PlayerJoyAxis(ssplayer, JA_STRAFE); + moveaxis = PlayerJoyAxis(ssplayer, JA_MOVE); movejoystickvector.xaxis = strafeaxis; movejoystickvector.yaxis = moveaxis; G_HandleAxisDeadZone(forplayer, &movejoystickvector); @@ -1283,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) @@ -1300,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 @@ -1311,42 +1299,42 @@ 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; } // fire with any button/key - axis = PlayerJoyAxis(ssplayer, AXISFIRE); - if (PLAYERINPUTDOWN(ssplayer, gc_fire) || (usejoystick && axis > 0)) + axis = PlayerJoyAxis(ssplayer, JA_FIRE); + if (PLAYERINPUTDOWN(ssplayer, GC_FIRE) || (usejoystick && axis > 0)) cmd->buttons |= BT_ATTACK; // fire normal with any button/key - axis = PlayerJoyAxis(ssplayer, AXISFIRENORMAL); - if (PLAYERINPUTDOWN(ssplayer, gc_firenormal) || (usejoystick && axis > 0)) + axis = PlayerJoyAxis(ssplayer, JA_FIRENORMAL); + 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, AXISSPIN); - if (PLAYERINPUTDOWN(ssplayer, gc_spin) || (usejoystick && axis > 0)) + axis = PlayerJoyAxis(ssplayer, JA_SPIN); + 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; @@ -1423,7 +1411,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) newtarget = P_SpawnMobj(ticcmd_ztargetfocus[forplayer]->x, ticcmd_ztargetfocus[forplayer]->y, ticcmd_ztargetfocus[forplayer]->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]); - if (P_AproxDistance( + if (player->mo && P_AproxDistance( player->mo->x - ticcmd_ztargetfocus[forplayer]->x, player->mo->y - ticcmd_ztargetfocus[forplayer]->y ) > 50*player->mo->scale) @@ -1445,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); @@ -1457,8 +1445,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // jump button - axis = PlayerJoyAxis(ssplayer, AXISJUMP); - if (PLAYERINPUTDOWN(ssplayer, gc_jump) || (usejoystick && axis > 0)) + axis = PlayerJoyAxis(ssplayer, JA_JUMP); + if (PLAYERINPUTDOWN(ssplayer, GC_JUMP) || (usejoystick && axis > 0)) cmd->buttons |= BT_JUMP; // player aiming shit, ahhhh... @@ -1476,7 +1464,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) keyboard_look[forplayer] = false; // looking up/down - *myaiming += (*mly<<19)*player_invert*screen_invert; + *myaiming += (mldy<<19)*player_invert*screen_invert; } if (analogjoystickmove && joyaiming[forplayer] && lookjoystickvector.yaxis != 0 && configlookaxis != 0) @@ -1488,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; @@ -1510,24 +1498,22 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) } if (!mouseaiming && mousemove) - forward += *my; + forward += mdy; if ((!demoplayback && (player->pflags & PF_SLIDING))) // Analog for mouse - side += *mx*2; + side += mdx*2; else if (controlstyle == CS_LMAOGALOG) { - if (*mx) + if (mdx) { - if (*mx > 0) + if (mdx > 0) cmd->buttons |= BT_CAMRIGHT; else cmd->buttons |= BT_CAMLEFT; } } else - cmd->angleturn = (INT16)(cmd->angleturn - (*mx*8)); - - *mx = *my = *mly = 0; + cmd->angleturn = (INT16)(cmd->angleturn - (mdx*8)); if (forward > MAXPLMOVE) forward = MAXPLMOVE; @@ -1560,21 +1546,16 @@ 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); + // Note: Majority of botstuffs are handled in G_Ticker now. + if (player->bot == BOT_2PAI + && !player->powers[pw_tailsfly] + && (cmd->forwardmove || cmd->sidemove || cmd->buttons)) + { + player->bot = BOT_2PHUMAN; // A player-controlled bot. Returns to AI when it respawns. + CV_SetValue(&cv_analog[1], true); } - else if (player->bot == 2) - // Fix offset angle for P2-controlled Tailsbot when P2's controls are set to non-Legacy + + if (player->bot == BOT_2PHUMAN) cmd->angleturn = (INT16)((localangle - *myangle) >> 16); *myangle += (cmd->angleturn<<16); @@ -1678,7 +1659,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) // At this point, cmd doesn't contain the final angle yet, // So we need to temporarily transform it so Lua scripters // don't need to handle it differently than in other hooks. - if (gamestate == GS_LEVEL) + if (addedtogame && gamestate == GS_LEVEL) { INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn; INT16 origangle = cmd->angleturn; @@ -1687,12 +1668,16 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) cmd->angleturn = orighookangle; - LUAh_PlayerCmd(player, cmd); + LUA_HookTiccmd(player, cmd, HOOK(PlayerCmd)); extra = cmd->angleturn - orighookangle; cmd->angleturn = origangle + extra; *myangle += extra << 16; *myaiming += (cmd->aiming - origaiming) << 16; + + // Send leveltime when this tic was generated to the server for control lag calculations. + // Only do this when in a level. Also do this after the hook, so that it can't overwrite this. + cmd->latency = (leveltime & 0xFF); } //Reset away view if a command is given. @@ -1701,7 +1686,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(player, &players[consoleplayer], true); + LUA_HookViewpointSwitch(player, &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -1724,6 +1709,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n) dest[i].angleturn = SHORT(src[i].angleturn); dest[i].aiming = (INT16)SHORT(src[i].aiming); dest[i].buttons = (UINT16)SHORT(src[i].buttons); + dest[i].latency = src[i].latency; } return dest; } @@ -1873,8 +1859,8 @@ void G_DoLoadLevel(boolean resetplayer) joyxmove[i] = joyymove[i] = 0; joy2xmove[i] = joy2ymove[i] = 0; } - mousex = mousey = 0; - mouse2x = mouse2y = 0; + G_SetMouseDeltas(0, 0, 1); + G_SetMouseDeltas(0, 0, 2); // clear hud messages remains (usually from game startup) CON_ClearHUD(); @@ -1978,7 +1964,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; @@ -2054,7 +2040,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; @@ -2074,7 +2060,7 @@ boolean G_Responder(event_t *ev) continue; // Call ViewpointSwitch hooks here. - canSwitchView = LUAh_ViewpointSwitch(&players[consoleplayer], &players[displayplayer], false); + canSwitchView = LUA_HookViewpointSwitch(&players[consoleplayer], &players[displayplayer], false); if (canSwitchView == 1) // Set viewpoint to this player break; else if (canSwitchView == 2) // Skip this player @@ -2127,13 +2113,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; @@ -2158,8 +2144,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) { @@ -2167,8 +2153,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) { @@ -2198,6 +2184,28 @@ boolean G_Responder(event_t *ev) return false; } +// +// G_LuaResponder +// Let Lua handle key events. +// +boolean G_LuaResponder(event_t *ev) +{ + 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; +} + // // G_Ticker // Make ticcmd_ts for the players. @@ -2207,6 +2215,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++; @@ -2287,20 +2312,44 @@ void G_Ticker(boolean run) buf = gametic % BACKUPTICS; + // Generate ticcmds for bots FIRST, then copy received ticcmds for players. + // This emulates pre-2.2.10 behaviour where the bot referenced their leader's last copied ticcmd, + // which is desirable because P_PlayerThink can override inputs (e.g. while PF_STASIS is applied or in a waterslide), + // and the bot AI needs to respect that. +#define ISHUMAN (players[i].bot == BOT_NONE || players[i].bot == BOT_2PHUMAN) for (i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i]) + if (playeringame[i] && !ISHUMAN) // Less work is required if we're building a bot ticcmd. { + players[i].lastbuttons = players[i].cmd.buttons; // Save last frame's button readings + B_BuildTiccmd(&players[i], &players[i].cmd); + + // Since bot TicCmd is pre-determined for both the client and server, the latency and packet checks are simplified. + players[i].cmd.latency = 0; + P_SetPlayerAngle(&players[i], players[i].cmd.angleturn << 16); + } + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && ISHUMAN) + { + players[i].lastbuttons = players[i].cmd.buttons; // Save last frame's button readings G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); + // 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); + + // Do angle adjustments. 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 = (players[i].angleturn & ~TICCMD_RECEIVED) | (players[i].cmd.angleturn & TICCMD_RECEIVED); } } +#undef ISHUMAN // do main actions switch (gamestate) @@ -2484,6 +2533,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps) tic_t quittime; boolean spectator; boolean outofcoop; + boolean removing; INT16 bot; SINT8 pity; INT16 rings; @@ -2500,6 +2550,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; @@ -2576,6 +2627,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; @@ -2620,8 +2672,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; @@ -2738,7 +2792,7 @@ void G_SpawnPlayer(INT32 playernum) P_SpawnPlayer(playernum); G_MovePlayerToSpawnOrStarpost(playernum); - LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :) + LUA_HookPlayer(&players[playernum], HOOK(PlayerSpawn)); // Lua hook for player spawning :) } void G_MovePlayerToSpawnOrStarpost(INT32 playernum) @@ -2967,7 +3021,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; @@ -2986,6 +3041,28 @@ void G_DoReborn(INT32 playernum) return; } + // Additional players (e.g. independent bots) in Single Player + if (playernum != consoleplayer && !(netgame || multiplayer)) + { + mobj_t *oldmo = NULL; + // Do nothing if out of lives + if (player->lives <= 0) + return; + + // Otherwise do respawn, starting by removing the player object + if (player->mo) + { + oldmo = player->mo; + P_RemoveMobj(player->mo); + } + // Do spawning + G_SpawnPlayer(playernum); + if (oldmo) + G_ChangePlayerReferences(oldmo, players[playernum].mo); + + return; //Exit function to avoid proccing other SP related mechanics + } + if (countdowntimeup || (!(netgame || multiplayer) && (gametyperules & GTR_CAMPAIGN))) resetlevel = true; else if ((G_GametypeUsesCoopLives() || G_GametypeUsesCoopStarposts()) && (netgame || multiplayer) && !G_IsSpecialStage(gamemap)) @@ -3088,8 +3165,8 @@ void G_DoReborn(INT32 playernum) joyxmove[i] = joyymove[i] = 0; joy2xmove[i] = joy2ymove[i] = 0; } - mousex = mousey = 0; - mouse2x = mouse2y = 0; + G_SetMouseDeltas(0, 0, 1); + G_SetMouseDeltas(0, 0, 2); // clear hud messages remains (usually from game startup) CON_ClearHUD(); @@ -3117,7 +3194,7 @@ void G_DoReborn(INT32 playernum) } else { - LUAh_MapChange(gamemap); + LUA_HookInt(gamemap, HOOK(MapChange)); titlecardforreload = true; G_DoLoadLevel(true); titlecardforreload = false; @@ -3166,7 +3243,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++; @@ -3500,6 +3577,7 @@ tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = { {"MARIO",TOL_MARIO}, {"NIGHTS",TOL_NIGHTS}, {"OLDBRAK",TOL_ERZ3}, + {"ERZ3",TOL_ERZ3}, {"XMAS",TOL_XMAS}, {"CHRISTMAS",TOL_XMAS}, @@ -3735,7 +3813,7 @@ static void G_UpdateVisited(void) // Update visitation flags? if ((!modifiedgame || savemoddata) // Not modified && !multiplayer && !demoplayback && (gametype == GT_COOP) // SP/RA/NiGHTS mode - && !(spec && stagefailed)) // Not failed the special stage + && !stagefailed) // Did not fail the stage { UINT8 earnedEmblems; @@ -3832,6 +3910,9 @@ static void G_DoCompleted(void) if (metalrecording) G_StopMetalRecording(false); + G_SetGamestate(GS_NULL); + wipegamestate = GS_NULL; + for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i]) G_PlayerFinishLevel(i); // take away cards and stuff @@ -3920,12 +4001,13 @@ static void G_DoCompleted(void) { token--; - for (i = 0; i < 7; i++) - if (!(emeralds & (1<cutscenenum && !modeattacking && skipstats <= 1 && (gamecomplete || !(marathonmode & MA_NOCUTSCENES))) // Start a custom cutscene. + if ((gametyperules & GTR_CUTSCENES) && mapheaderinfo[gamemap-1]->cutscenenum + && !modeattacking + && skipstats <= 1 + && (gamecomplete || !(marathonmode & MA_NOCUTSCENES)) + && stagefailed == false) + { + // Start a custom cutscene. F_StartCustomCutscene(mapheaderinfo[gamemap-1]->cutscenenum-1, false, false); + } else { if (nextmap < 1100-1) @@ -4610,6 +4700,9 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) UINT8 *end_p = savebuffer + length; UINT8 *lives_p; SINT8 pllives; +#ifdef NEWSKINSAVES + INT16 backwardsCompat = 0; +#endif save_p = savebuffer; // Version check @@ -4628,9 +4721,23 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) // P_UnArchivePlayer() CHECKPOS - (void)READUINT16(save_p); +#ifdef NEWSKINSAVES + backwardsCompat = READUINT16(save_p); CHECKPOS + if (backwardsCompat == NEWSKINSAVES) // New save, read skin names +#endif + { + char ourSkinName[SKINNAMESIZE+1]; + char botSkinName[SKINNAMESIZE+1]; + + READSTRINGN(save_p, ourSkinName, SKINNAMESIZE); + CHECKPOS + + READSTRINGN(save_p, botSkinName, SKINNAMESIZE); + CHECKPOS + } + WRITEUINT8(save_p, numgameovers); CHECKPOS @@ -5203,4 +5310,3 @@ INT32 G_TicsToMilliseconds(tic_t tics) { return (INT32)((tics%TICRATE) * (1000.00f/TICRATE)); } - diff --git a/src/g_game.h b/src/g_game.h index 744d6755a..dca043f2e 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -85,6 +85,25 @@ typedef enum } lockassist_e; +typedef enum +{ + JA_NONE = 0, + JA_TURN, + JA_MOVE, + JA_LOOK, + JA_STRAFE, + + JA_DIGITAL, // axes henceforth use digital deadzone + + JA_JUMP = JA_DIGITAL, + JA_SPIN, + JA_FIRE, + JA_FIRENORMAL, +} joyaxis_e; + +INT32 JoyAxis(joyaxis_e axissel); +INT32 Joy2Axis(joyaxis_e axissel); + // mouseaiming (looking up/down with the mouse or keyboard) #define KB_LOOKSPEED (1<<25) #define MAXPLMOVE (50) @@ -204,6 +223,7 @@ void G_EndGame(void); // moved from y_inter.c/h and renamed void G_Ticker(boolean run); boolean G_Responder(event_t *ev); +boolean G_LuaResponder(event_t *ev); void G_AddPlayer(INT32 playernum); diff --git a/src/g_input.c b/src/g_input.c index d3c21e774..7bb2e799d 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -31,10 +31,8 @@ consvar_t cv_mouseysens = CVAR_INIT ("mouseysens", "20", CV_SAVE, mousesens_cons consvar_t cv_mouseysens2 = CVAR_INIT ("mouseysens2", "20", CV_SAVE, mousesens_cons_t, NULL); consvar_t cv_controlperkey = CVAR_INIT ("controlperkey", "One", CV_SAVE, onecontrolperkey_cons_t, NULL); -INT32 mousex, mousey; -INT32 mlooky; // like mousey but with a custom sensitivity for mlook - -INT32 mouse2x, mouse2y, mlook2y; +mouse_t mouse; +mouse_t mouse2; // joystick values are repeated INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET]; @@ -43,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 @@ -117,58 +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 - if (menuactive || CON_Ready() || chat_on) - break; - mousex = (INT32)(ev->data2*((cv_mousesens.value*cv_mousesens.value)/110.0f + 0.1f)); - mousey = (INT32)(ev->data3*((cv_mousesens.value*cv_mousesens.value)/110.0f + 0.1f)); - mlooky = (INT32)(ev->data3*((cv_mouseysens.value*cv_mousesens.value)/110.0f + 0.1f)); + 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; - mouse2x = (INT32)(ev->data2*((cv_mousesens2.value*cv_mousesens2.value)/110.0f + 0.1f)); - mouse2y = (INT32)(ev->data3*((cv_mousesens2.value*cv_mousesens2.value)/110.0f + 0.1f)); - mlook2y = (INT32)(ev->data3*((cv_mouseysens2.value*cv_mousesens2.value)/110.0f + 0.1f)); + mouse2.rdx = ev->x; + mouse2.rdy = ev->y; break; default: @@ -239,329 +233,329 @@ typedef struct static keyname_t keynames[] = { - {KEY_SPACE, "SPACE"}, - {KEY_CAPSLOCK, "CAPS LOCK"}, - {KEY_ENTER, "ENTER"}, - {KEY_TAB, "TAB"}, - {KEY_ESCAPE, "ESCAPE"}, - {KEY_BACKSPACE, "BACKSPACE"}, + {KEY_SPACE, "space"}, + {KEY_CAPSLOCK, "caps lock"}, + {KEY_ENTER, "enter"}, + {KEY_TAB, "tab"}, + {KEY_ESCAPE, "escape"}, + {KEY_BACKSPACE, "backspace"}, - {KEY_NUMLOCK, "NUMLOCK"}, - {KEY_SCROLLLOCK, "SCROLLLOCK"}, + {KEY_NUMLOCK, "numlock"}, + {KEY_SCROLLLOCK, "scrolllock"}, // bill gates keys - {KEY_LEFTWIN, "LEFTWIN"}, - {KEY_RIGHTWIN, "RIGHTWIN"}, - {KEY_MENU, "MENU"}, + {KEY_LEFTWIN, "leftwin"}, + {KEY_RIGHTWIN, "rightwin"}, + {KEY_MENU, "menu"}, - {KEY_LSHIFT, "LSHIFT"}, - {KEY_RSHIFT, "RSHIFT"}, - {KEY_LSHIFT, "SHIFT"}, - {KEY_LCTRL, "LCTRL"}, - {KEY_RCTRL, "RCTRL"}, - {KEY_LCTRL, "CTRL"}, - {KEY_LALT, "LALT"}, - {KEY_RALT, "RALT"}, - {KEY_LALT, "ALT"}, + {KEY_LSHIFT, "lshift"}, + {KEY_RSHIFT, "rshift"}, + {KEY_LSHIFT, "shift"}, + {KEY_LCTRL, "lctrl"}, + {KEY_RCTRL, "rctrl"}, + {KEY_LCTRL, "ctrl"}, + {KEY_LALT, "lalt"}, + {KEY_RALT, "ralt"}, + {KEY_LALT, "alt"}, // keypad keys - {KEY_KPADSLASH, "KEYPAD /"}, - {KEY_KEYPAD7, "KEYPAD 7"}, - {KEY_KEYPAD8, "KEYPAD 8"}, - {KEY_KEYPAD9, "KEYPAD 9"}, - {KEY_MINUSPAD, "KEYPAD -"}, - {KEY_KEYPAD4, "KEYPAD 4"}, - {KEY_KEYPAD5, "KEYPAD 5"}, - {KEY_KEYPAD6, "KEYPAD 6"}, - {KEY_PLUSPAD, "KEYPAD +"}, - {KEY_KEYPAD1, "KEYPAD 1"}, - {KEY_KEYPAD2, "KEYPAD 2"}, - {KEY_KEYPAD3, "KEYPAD 3"}, - {KEY_KEYPAD0, "KEYPAD 0"}, - {KEY_KPADDEL, "KEYPAD ."}, + {KEY_KPADSLASH, "keypad /"}, + {KEY_KEYPAD7, "keypad 7"}, + {KEY_KEYPAD8, "keypad 8"}, + {KEY_KEYPAD9, "keypad 9"}, + {KEY_MINUSPAD, "keypad -"}, + {KEY_KEYPAD4, "keypad 4"}, + {KEY_KEYPAD5, "keypad 5"}, + {KEY_KEYPAD6, "keypad 6"}, + {KEY_PLUSPAD, "keypad +"}, + {KEY_KEYPAD1, "keypad 1"}, + {KEY_KEYPAD2, "keypad 2"}, + {KEY_KEYPAD3, "keypad 3"}, + {KEY_KEYPAD0, "keypad 0"}, + {KEY_KPADDEL, "keypad ."}, // extended keys (not keypad) - {KEY_HOME, "HOME"}, - {KEY_UPARROW, "UP ARROW"}, - {KEY_PGUP, "PGUP"}, - {KEY_LEFTARROW, "LEFT ARROW"}, - {KEY_RIGHTARROW, "RIGHT ARROW"}, - {KEY_END, "END"}, - {KEY_DOWNARROW, "DOWN ARROW"}, - {KEY_PGDN, "PGDN"}, - {KEY_INS, "INS"}, - {KEY_DEL, "DEL"}, + {KEY_HOME, "home"}, + {KEY_UPARROW, "up arrow"}, + {KEY_PGUP, "pgup"}, + {KEY_LEFTARROW, "left arrow"}, + {KEY_RIGHTARROW, "right arrow"}, + {KEY_END, "end"}, + {KEY_DOWNARROW, "down arrow"}, + {KEY_PGDN, "pgdn"}, + {KEY_INS, "ins"}, + {KEY_DEL, "del"}, // other keys - {KEY_F1, "F1"}, - {KEY_F2, "F2"}, - {KEY_F3, "F3"}, - {KEY_F4, "F4"}, - {KEY_F5, "F5"}, - {KEY_F6, "F6"}, - {KEY_F7, "F7"}, - {KEY_F8, "F8"}, - {KEY_F9, "F9"}, - {KEY_F10, "F10"}, - {KEY_F11, "F11"}, - {KEY_F12, "F12"}, + {KEY_F1, "f1"}, + {KEY_F2, "f2"}, + {KEY_F3, "f3"}, + {KEY_F4, "f4"}, + {KEY_F5, "f5"}, + {KEY_F6, "f6"}, + {KEY_F7, "f7"}, + {KEY_F8, "f8"}, + {KEY_F9, "f9"}, + {KEY_F10, "f10"}, + {KEY_F11, "f11"}, + {KEY_F12, "f12"}, // KEY_CONSOLE has an exception in the keyname code {'`', "TILDE"}, - {KEY_PAUSE, "PAUSE/BREAK"}, + {KEY_PAUSE, "pause/break"}, // virtual keys for mouse buttons and joystick buttons - {KEY_MOUSE1+0,"MOUSE1"}, - {KEY_MOUSE1+1,"MOUSE2"}, - {KEY_MOUSE1+2,"MOUSE3"}, - {KEY_MOUSE1+3,"MOUSE4"}, - {KEY_MOUSE1+4,"MOUSE5"}, - {KEY_MOUSE1+5,"MOUSE6"}, - {KEY_MOUSE1+6,"MOUSE7"}, - {KEY_MOUSE1+7,"MOUSE8"}, - {KEY_2MOUSE1+0,"SEC_MOUSE2"}, // BP: sorry my mouse handler swap button 1 and 2 - {KEY_2MOUSE1+1,"SEC_MOUSE1"}, - {KEY_2MOUSE1+2,"SEC_MOUSE3"}, - {KEY_2MOUSE1+3,"SEC_MOUSE4"}, - {KEY_2MOUSE1+4,"SEC_MOUSE5"}, - {KEY_2MOUSE1+5,"SEC_MOUSE6"}, - {KEY_2MOUSE1+6,"SEC_MOUSE7"}, - {KEY_2MOUSE1+7,"SEC_MOUSE8"}, - {KEY_MOUSEWHEELUP, "Wheel 1 UP"}, - {KEY_MOUSEWHEELDOWN, "Wheel 1 Down"}, - {KEY_2MOUSEWHEELUP, "Wheel 2 UP"}, - {KEY_2MOUSEWHEELDOWN, "Wheel 2 Down"}, + {KEY_MOUSE1+0,"mouse1"}, + {KEY_MOUSE1+1,"mouse2"}, + {KEY_MOUSE1+2,"mouse3"}, + {KEY_MOUSE1+3,"mouse4"}, + {KEY_MOUSE1+4,"mouse5"}, + {KEY_MOUSE1+5,"mouse6"}, + {KEY_MOUSE1+6,"mouse7"}, + {KEY_MOUSE1+7,"mouse8"}, + {KEY_2MOUSE1+0,"sec_mouse2"}, // BP: sorry my mouse handler swap button 1 and 2 + {KEY_2MOUSE1+1,"sec_mouse1"}, + {KEY_2MOUSE1+2,"sec_mouse3"}, + {KEY_2MOUSE1+3,"sec_mouse4"}, + {KEY_2MOUSE1+4,"sec_mouse5"}, + {KEY_2MOUSE1+5,"sec_mouse6"}, + {KEY_2MOUSE1+6,"sec_mouse7"}, + {KEY_2MOUSE1+7,"sec_mouse8"}, + {KEY_MOUSEWHEELUP, "wheel 1 up"}, + {KEY_MOUSEWHEELDOWN, "wheel 1 down"}, + {KEY_2MOUSEWHEELUP, "wheel 2 up"}, + {KEY_2MOUSEWHEELDOWN, "wheel 2 down"}, - {KEY_JOY1+0, "JOY1"}, - {KEY_JOY1+1, "JOY2"}, - {KEY_JOY1+2, "JOY3"}, - {KEY_JOY1+3, "JOY4"}, - {KEY_JOY1+4, "JOY5"}, - {KEY_JOY1+5, "JOY6"}, - {KEY_JOY1+6, "JOY7"}, - {KEY_JOY1+7, "JOY8"}, - {KEY_JOY1+8, "JOY9"}, + {KEY_JOY1+0, "joy1"}, + {KEY_JOY1+1, "joy2"}, + {KEY_JOY1+2, "joy3"}, + {KEY_JOY1+3, "joy4"}, + {KEY_JOY1+4, "joy5"}, + {KEY_JOY1+5, "joy6"}, + {KEY_JOY1+6, "joy7"}, + {KEY_JOY1+7, "joy8"}, + {KEY_JOY1+8, "joy9"}, #if !defined (NOMOREJOYBTN_1S) // we use up to 32 buttons in DirectInput - {KEY_JOY1+9, "JOY10"}, - {KEY_JOY1+10, "JOY11"}, - {KEY_JOY1+11, "JOY12"}, - {KEY_JOY1+12, "JOY13"}, - {KEY_JOY1+13, "JOY14"}, - {KEY_JOY1+14, "JOY15"}, - {KEY_JOY1+15, "JOY16"}, - {KEY_JOY1+16, "JOY17"}, - {KEY_JOY1+17, "JOY18"}, - {KEY_JOY1+18, "JOY19"}, - {KEY_JOY1+19, "JOY20"}, - {KEY_JOY1+20, "JOY21"}, - {KEY_JOY1+21, "JOY22"}, - {KEY_JOY1+22, "JOY23"}, - {KEY_JOY1+23, "JOY24"}, - {KEY_JOY1+24, "JOY25"}, - {KEY_JOY1+25, "JOY26"}, - {KEY_JOY1+26, "JOY27"}, - {KEY_JOY1+27, "JOY28"}, - {KEY_JOY1+28, "JOY29"}, - {KEY_JOY1+29, "JOY30"}, - {KEY_JOY1+30, "JOY31"}, - {KEY_JOY1+31, "JOY32"}, + {KEY_JOY1+9, "joy10"}, + {KEY_JOY1+10, "joy11"}, + {KEY_JOY1+11, "joy12"}, + {KEY_JOY1+12, "joy13"}, + {KEY_JOY1+13, "joy14"}, + {KEY_JOY1+14, "joy15"}, + {KEY_JOY1+15, "joy16"}, + {KEY_JOY1+16, "joy17"}, + {KEY_JOY1+17, "joy18"}, + {KEY_JOY1+18, "joy19"}, + {KEY_JOY1+19, "joy20"}, + {KEY_JOY1+20, "joy21"}, + {KEY_JOY1+21, "joy22"}, + {KEY_JOY1+22, "joy23"}, + {KEY_JOY1+23, "joy24"}, + {KEY_JOY1+24, "joy25"}, + {KEY_JOY1+25, "joy26"}, + {KEY_JOY1+26, "joy27"}, + {KEY_JOY1+27, "joy28"}, + {KEY_JOY1+28, "joy29"}, + {KEY_JOY1+29, "joy30"}, + {KEY_JOY1+30, "joy31"}, + {KEY_JOY1+31, "joy32"}, #endif // the DOS version uses Allegro's joystick support - {KEY_HAT1+0, "HATUP"}, - {KEY_HAT1+1, "HATDOWN"}, - {KEY_HAT1+2, "HATLEFT"}, - {KEY_HAT1+3, "HATRIGHT"}, - {KEY_HAT1+4, "HATUP2"}, - {KEY_HAT1+5, "HATDOWN2"}, - {KEY_HAT1+6, "HATLEFT2"}, - {KEY_HAT1+7, "HATRIGHT2"}, - {KEY_HAT1+8, "HATUP3"}, - {KEY_HAT1+9, "HATDOWN3"}, - {KEY_HAT1+10, "HATLEFT3"}, - {KEY_HAT1+11, "HATRIGHT3"}, - {KEY_HAT1+12, "HATUP4"}, - {KEY_HAT1+13, "HATDOWN4"}, - {KEY_HAT1+14, "HATLEFT4"}, - {KEY_HAT1+15, "HATRIGHT4"}, + {KEY_HAT1+0, "hatup"}, + {KEY_HAT1+1, "hatdown"}, + {KEY_HAT1+2, "hatleft"}, + {KEY_HAT1+3, "hatright"}, + {KEY_HAT1+4, "hatup2"}, + {KEY_HAT1+5, "hatdown2"}, + {KEY_HAT1+6, "hatleft2"}, + {KEY_HAT1+7, "hatright2"}, + {KEY_HAT1+8, "hatup3"}, + {KEY_HAT1+9, "hatdown3"}, + {KEY_HAT1+10, "hatleft3"}, + {KEY_HAT1+11, "hatright3"}, + {KEY_HAT1+12, "hatup4"}, + {KEY_HAT1+13, "hatdown4"}, + {KEY_HAT1+14, "hatleft4"}, + {KEY_HAT1+15, "hatright4"}, - {KEY_DBLMOUSE1+0, "DBLMOUSE1"}, - {KEY_DBLMOUSE1+1, "DBLMOUSE2"}, - {KEY_DBLMOUSE1+2, "DBLMOUSE3"}, - {KEY_DBLMOUSE1+3, "DBLMOUSE4"}, - {KEY_DBLMOUSE1+4, "DBLMOUSE5"}, - {KEY_DBLMOUSE1+5, "DBLMOUSE6"}, - {KEY_DBLMOUSE1+6, "DBLMOUSE7"}, - {KEY_DBLMOUSE1+7, "DBLMOUSE8"}, - {KEY_DBL2MOUSE1+0, "DBLSEC_MOUSE2"}, // BP: sorry my mouse handler swap button 1 and 2 - {KEY_DBL2MOUSE1+1, "DBLSEC_MOUSE1"}, - {KEY_DBL2MOUSE1+2, "DBLSEC_MOUSE3"}, - {KEY_DBL2MOUSE1+3, "DBLSEC_MOUSE4"}, - {KEY_DBL2MOUSE1+4, "DBLSEC_MOUSE5"}, - {KEY_DBL2MOUSE1+5, "DBLSEC_MOUSE6"}, - {KEY_DBL2MOUSE1+6, "DBLSEC_MOUSE7"}, - {KEY_DBL2MOUSE1+7, "DBLSEC_MOUSE8"}, + {KEY_DBLMOUSE1+0, "dblmouse1"}, + {KEY_DBLMOUSE1+1, "dblmouse2"}, + {KEY_DBLMOUSE1+2, "dblmouse3"}, + {KEY_DBLMOUSE1+3, "dblmouse4"}, + {KEY_DBLMOUSE1+4, "dblmouse5"}, + {KEY_DBLMOUSE1+5, "dblmouse6"}, + {KEY_DBLMOUSE1+6, "dblmouse7"}, + {KEY_DBLMOUSE1+7, "dblmouse8"}, + {KEY_DBL2MOUSE1+0, "dblsec_mouse2"}, // BP: sorry my mouse handler swap button 1 and 2 + {KEY_DBL2MOUSE1+1, "dblsec_mouse1"}, + {KEY_DBL2MOUSE1+2, "dblsec_mouse3"}, + {KEY_DBL2MOUSE1+3, "dblsec_mouse4"}, + {KEY_DBL2MOUSE1+4, "dblsec_mouse5"}, + {KEY_DBL2MOUSE1+5, "dblsec_mouse6"}, + {KEY_DBL2MOUSE1+6, "dblsec_mouse7"}, + {KEY_DBL2MOUSE1+7, "dblsec_mouse8"}, - {KEY_DBLJOY1+0, "DBLJOY1"}, - {KEY_DBLJOY1+1, "DBLJOY2"}, - {KEY_DBLJOY1+2, "DBLJOY3"}, - {KEY_DBLJOY1+3, "DBLJOY4"}, - {KEY_DBLJOY1+4, "DBLJOY5"}, - {KEY_DBLJOY1+5, "DBLJOY6"}, - {KEY_DBLJOY1+6, "DBLJOY7"}, - {KEY_DBLJOY1+7, "DBLJOY8"}, + {KEY_DBLJOY1+0, "dbljoy1"}, + {KEY_DBLJOY1+1, "dbljoy2"}, + {KEY_DBLJOY1+2, "dbljoy3"}, + {KEY_DBLJOY1+3, "dbljoy4"}, + {KEY_DBLJOY1+4, "dbljoy5"}, + {KEY_DBLJOY1+5, "dbljoy6"}, + {KEY_DBLJOY1+6, "dbljoy7"}, + {KEY_DBLJOY1+7, "dbljoy8"}, #if !defined (NOMOREJOYBTN_1DBL) - {KEY_DBLJOY1+8, "DBLJOY9"}, - {KEY_DBLJOY1+9, "DBLJOY10"}, - {KEY_DBLJOY1+10, "DBLJOY11"}, - {KEY_DBLJOY1+11, "DBLJOY12"}, - {KEY_DBLJOY1+12, "DBLJOY13"}, - {KEY_DBLJOY1+13, "DBLJOY14"}, - {KEY_DBLJOY1+14, "DBLJOY15"}, - {KEY_DBLJOY1+15, "DBLJOY16"}, - {KEY_DBLJOY1+16, "DBLJOY17"}, - {KEY_DBLJOY1+17, "DBLJOY18"}, - {KEY_DBLJOY1+18, "DBLJOY19"}, - {KEY_DBLJOY1+19, "DBLJOY20"}, - {KEY_DBLJOY1+20, "DBLJOY21"}, - {KEY_DBLJOY1+21, "DBLJOY22"}, - {KEY_DBLJOY1+22, "DBLJOY23"}, - {KEY_DBLJOY1+23, "DBLJOY24"}, - {KEY_DBLJOY1+24, "DBLJOY25"}, - {KEY_DBLJOY1+25, "DBLJOY26"}, - {KEY_DBLJOY1+26, "DBLJOY27"}, - {KEY_DBLJOY1+27, "DBLJOY28"}, - {KEY_DBLJOY1+28, "DBLJOY29"}, - {KEY_DBLJOY1+29, "DBLJOY30"}, - {KEY_DBLJOY1+30, "DBLJOY31"}, - {KEY_DBLJOY1+31, "DBLJOY32"}, + {KEY_DBLJOY1+8, "dbljoy9"}, + {KEY_DBLJOY1+9, "dbljoy10"}, + {KEY_DBLJOY1+10, "dbljoy11"}, + {KEY_DBLJOY1+11, "dbljoy12"}, + {KEY_DBLJOY1+12, "dbljoy13"}, + {KEY_DBLJOY1+13, "dbljoy14"}, + {KEY_DBLJOY1+14, "dbljoy15"}, + {KEY_DBLJOY1+15, "dbljoy16"}, + {KEY_DBLJOY1+16, "dbljoy17"}, + {KEY_DBLJOY1+17, "dbljoy18"}, + {KEY_DBLJOY1+18, "dbljoy19"}, + {KEY_DBLJOY1+19, "dbljoy20"}, + {KEY_DBLJOY1+20, "dbljoy21"}, + {KEY_DBLJOY1+21, "dbljoy22"}, + {KEY_DBLJOY1+22, "dbljoy23"}, + {KEY_DBLJOY1+23, "dbljoy24"}, + {KEY_DBLJOY1+24, "dbljoy25"}, + {KEY_DBLJOY1+25, "dbljoy26"}, + {KEY_DBLJOY1+26, "dbljoy27"}, + {KEY_DBLJOY1+27, "dbljoy28"}, + {KEY_DBLJOY1+28, "dbljoy29"}, + {KEY_DBLJOY1+29, "dbljoy30"}, + {KEY_DBLJOY1+30, "dbljoy31"}, + {KEY_DBLJOY1+31, "dbljoy32"}, #endif - {KEY_DBLHAT1+0, "DBLHATUP"}, - {KEY_DBLHAT1+1, "DBLHATDOWN"}, - {KEY_DBLHAT1+2, "DBLHATLEFT"}, - {KEY_DBLHAT1+3, "DBLHATRIGHT"}, - {KEY_DBLHAT1+4, "DBLHATUP2"}, - {KEY_DBLHAT1+5, "DBLHATDOWN2"}, - {KEY_DBLHAT1+6, "DBLHATLEFT2"}, - {KEY_DBLHAT1+7, "DBLHATRIGHT2"}, - {KEY_DBLHAT1+8, "DBLHATUP3"}, - {KEY_DBLHAT1+9, "DBLHATDOWN3"}, - {KEY_DBLHAT1+10, "DBLHATLEFT3"}, - {KEY_DBLHAT1+11, "DBLHATRIGHT3"}, - {KEY_DBLHAT1+12, "DBLHATUP4"}, - {KEY_DBLHAT1+13, "DBLHATDOWN4"}, - {KEY_DBLHAT1+14, "DBLHATLEFT4"}, - {KEY_DBLHAT1+15, "DBLHATRIGHT4"}, + {KEY_DBLHAT1+0, "dblhatup"}, + {KEY_DBLHAT1+1, "dblhatdown"}, + {KEY_DBLHAT1+2, "dblhatleft"}, + {KEY_DBLHAT1+3, "dblhatright"}, + {KEY_DBLHAT1+4, "dblhatup2"}, + {KEY_DBLHAT1+5, "dblhatdown2"}, + {KEY_DBLHAT1+6, "dblhatleft2"}, + {KEY_DBLHAT1+7, "dblhatright2"}, + {KEY_DBLHAT1+8, "dblhatup3"}, + {KEY_DBLHAT1+9, "dblhatdown3"}, + {KEY_DBLHAT1+10, "dblhatleft3"}, + {KEY_DBLHAT1+11, "dblhatright3"}, + {KEY_DBLHAT1+12, "dblhatup4"}, + {KEY_DBLHAT1+13, "dblhatdown4"}, + {KEY_DBLHAT1+14, "dblhatleft4"}, + {KEY_DBLHAT1+15, "dblhatright4"}, - {KEY_2JOY1+0, "SEC_JOY1"}, - {KEY_2JOY1+1, "SEC_JOY2"}, - {KEY_2JOY1+2, "SEC_JOY3"}, - {KEY_2JOY1+3, "SEC_JOY4"}, - {KEY_2JOY1+4, "SEC_JOY5"}, - {KEY_2JOY1+5, "SEC_JOY6"}, - {KEY_2JOY1+6, "SEC_JOY7"}, - {KEY_2JOY1+7, "SEC_JOY8"}, + {KEY_2JOY1+0, "sec_joy1"}, + {KEY_2JOY1+1, "sec_joy2"}, + {KEY_2JOY1+2, "sec_joy3"}, + {KEY_2JOY1+3, "sec_joy4"}, + {KEY_2JOY1+4, "sec_joy5"}, + {KEY_2JOY1+5, "sec_joy6"}, + {KEY_2JOY1+6, "sec_joy7"}, + {KEY_2JOY1+7, "sec_joy8"}, #if !defined (NOMOREJOYBTN_2S) // we use up to 32 buttons in DirectInput - {KEY_2JOY1+8, "SEC_JOY9"}, - {KEY_2JOY1+9, "SEC_JOY10"}, - {KEY_2JOY1+10, "SEC_JOY11"}, - {KEY_2JOY1+11, "SEC_JOY12"}, - {KEY_2JOY1+12, "SEC_JOY13"}, - {KEY_2JOY1+13, "SEC_JOY14"}, - {KEY_2JOY1+14, "SEC_JOY15"}, - {KEY_2JOY1+15, "SEC_JOY16"}, - {KEY_2JOY1+16, "SEC_JOY17"}, - {KEY_2JOY1+17, "SEC_JOY18"}, - {KEY_2JOY1+18, "SEC_JOY19"}, - {KEY_2JOY1+19, "SEC_JOY20"}, - {KEY_2JOY1+20, "SEC_JOY21"}, - {KEY_2JOY1+21, "SEC_JOY22"}, - {KEY_2JOY1+22, "SEC_JOY23"}, - {KEY_2JOY1+23, "SEC_JOY24"}, - {KEY_2JOY1+24, "SEC_JOY25"}, - {KEY_2JOY1+25, "SEC_JOY26"}, - {KEY_2JOY1+26, "SEC_JOY27"}, - {KEY_2JOY1+27, "SEC_JOY28"}, - {KEY_2JOY1+28, "SEC_JOY29"}, - {KEY_2JOY1+29, "SEC_JOY30"}, - {KEY_2JOY1+30, "SEC_JOY31"}, - {KEY_2JOY1+31, "SEC_JOY32"}, + {KEY_2JOY1+8, "sec_joy9"}, + {KEY_2JOY1+9, "sec_joy10"}, + {KEY_2JOY1+10, "sec_joy11"}, + {KEY_2JOY1+11, "sec_joy12"}, + {KEY_2JOY1+12, "sec_joy13"}, + {KEY_2JOY1+13, "sec_joy14"}, + {KEY_2JOY1+14, "sec_joy15"}, + {KEY_2JOY1+15, "sec_joy16"}, + {KEY_2JOY1+16, "sec_joy17"}, + {KEY_2JOY1+17, "sec_joy18"}, + {KEY_2JOY1+18, "sec_joy19"}, + {KEY_2JOY1+19, "sec_joy20"}, + {KEY_2JOY1+20, "sec_joy21"}, + {KEY_2JOY1+21, "sec_joy22"}, + {KEY_2JOY1+22, "sec_joy23"}, + {KEY_2JOY1+23, "sec_joy24"}, + {KEY_2JOY1+24, "sec_joy25"}, + {KEY_2JOY1+25, "sec_joy26"}, + {KEY_2JOY1+26, "sec_joy27"}, + {KEY_2JOY1+27, "sec_joy28"}, + {KEY_2JOY1+28, "sec_joy29"}, + {KEY_2JOY1+29, "sec_joy30"}, + {KEY_2JOY1+30, "sec_joy31"}, + {KEY_2JOY1+31, "sec_joy32"}, #endif // the DOS version uses Allegro's joystick support - {KEY_2HAT1+0, "SEC_HATUP"}, - {KEY_2HAT1+1, "SEC_HATDOWN"}, - {KEY_2HAT1+2, "SEC_HATLEFT"}, - {KEY_2HAT1+3, "SEC_HATRIGHT"}, - {KEY_2HAT1+4, "SEC_HATUP2"}, - {KEY_2HAT1+5, "SEC_HATDOWN2"}, - {KEY_2HAT1+6, "SEC_HATLEFT2"}, - {KEY_2HAT1+7, "SEC_HATRIGHT2"}, - {KEY_2HAT1+8, "SEC_HATUP3"}, - {KEY_2HAT1+9, "SEC_HATDOWN3"}, - {KEY_2HAT1+10, "SEC_HATLEFT3"}, - {KEY_2HAT1+11, "SEC_HATRIGHT3"}, - {KEY_2HAT1+12, "SEC_HATUP4"}, - {KEY_2HAT1+13, "SEC_HATDOWN4"}, - {KEY_2HAT1+14, "SEC_HATLEFT4"}, - {KEY_2HAT1+15, "SEC_HATRIGHT4"}, + {KEY_2HAT1+0, "sec_hatup"}, + {KEY_2HAT1+1, "sec_hatdown"}, + {KEY_2HAT1+2, "sec_hatleft"}, + {KEY_2HAT1+3, "sec_hatright"}, + {KEY_2HAT1+4, "sec_hatup2"}, + {KEY_2HAT1+5, "sec_hatdown2"}, + {KEY_2HAT1+6, "sec_hatleft2"}, + {KEY_2HAT1+7, "sec_hatright2"}, + {KEY_2HAT1+8, "sec_hatup3"}, + {KEY_2HAT1+9, "sec_hatdown3"}, + {KEY_2HAT1+10, "sec_hatleft3"}, + {KEY_2HAT1+11, "sec_hatright3"}, + {KEY_2HAT1+12, "sec_hatup4"}, + {KEY_2HAT1+13, "sec_hatdown4"}, + {KEY_2HAT1+14, "sec_hatleft4"}, + {KEY_2HAT1+15, "sec_hatright4"}, - {KEY_DBL2JOY1+0, "DBLSEC_JOY1"}, - {KEY_DBL2JOY1+1, "DBLSEC_JOY2"}, - {KEY_DBL2JOY1+2, "DBLSEC_JOY3"}, - {KEY_DBL2JOY1+3, "DBLSEC_JOY4"}, - {KEY_DBL2JOY1+4, "DBLSEC_JOY5"}, - {KEY_DBL2JOY1+5, "DBLSEC_JOY6"}, - {KEY_DBL2JOY1+6, "DBLSEC_JOY7"}, - {KEY_DBL2JOY1+7, "DBLSEC_JOY8"}, + {KEY_DBL2JOY1+0, "dblsec_joy1"}, + {KEY_DBL2JOY1+1, "dblsec_joy2"}, + {KEY_DBL2JOY1+2, "dblsec_joy3"}, + {KEY_DBL2JOY1+3, "dblsec_joy4"}, + {KEY_DBL2JOY1+4, "dblsec_joy5"}, + {KEY_DBL2JOY1+5, "dblsec_joy6"}, + {KEY_DBL2JOY1+6, "dblsec_joy7"}, + {KEY_DBL2JOY1+7, "dblsec_joy8"}, #if !defined (NOMOREJOYBTN_2DBL) - {KEY_DBL2JOY1+8, "DBLSEC_JOY9"}, - {KEY_DBL2JOY1+9, "DBLSEC_JOY10"}, - {KEY_DBL2JOY1+10, "DBLSEC_JOY11"}, - {KEY_DBL2JOY1+11, "DBLSEC_JOY12"}, - {KEY_DBL2JOY1+12, "DBLSEC_JOY13"}, - {KEY_DBL2JOY1+13, "DBLSEC_JOY14"}, - {KEY_DBL2JOY1+14, "DBLSEC_JOY15"}, - {KEY_DBL2JOY1+15, "DBLSEC_JOY16"}, - {KEY_DBL2JOY1+16, "DBLSEC_JOY17"}, - {KEY_DBL2JOY1+17, "DBLSEC_JOY18"}, - {KEY_DBL2JOY1+18, "DBLSEC_JOY19"}, - {KEY_DBL2JOY1+19, "DBLSEC_JOY20"}, - {KEY_DBL2JOY1+20, "DBLSEC_JOY21"}, - {KEY_DBL2JOY1+21, "DBLSEC_JOY22"}, - {KEY_DBL2JOY1+22, "DBLSEC_JOY23"}, - {KEY_DBL2JOY1+23, "DBLSEC_JOY24"}, - {KEY_DBL2JOY1+24, "DBLSEC_JOY25"}, - {KEY_DBL2JOY1+25, "DBLSEC_JOY26"}, - {KEY_DBL2JOY1+26, "DBLSEC_JOY27"}, - {KEY_DBL2JOY1+27, "DBLSEC_JOY28"}, - {KEY_DBL2JOY1+28, "DBLSEC_JOY29"}, - {KEY_DBL2JOY1+29, "DBLSEC_JOY30"}, - {KEY_DBL2JOY1+30, "DBLSEC_JOY31"}, - {KEY_DBL2JOY1+31, "DBLSEC_JOY32"}, + {KEY_DBL2JOY1+8, "dblsec_joy9"}, + {KEY_DBL2JOY1+9, "dblsec_joy10"}, + {KEY_DBL2JOY1+10, "dblsec_joy11"}, + {KEY_DBL2JOY1+11, "dblsec_joy12"}, + {KEY_DBL2JOY1+12, "dblsec_joy13"}, + {KEY_DBL2JOY1+13, "dblsec_joy14"}, + {KEY_DBL2JOY1+14, "dblsec_joy15"}, + {KEY_DBL2JOY1+15, "dblsec_joy16"}, + {KEY_DBL2JOY1+16, "dblsec_joy17"}, + {KEY_DBL2JOY1+17, "dblsec_joy18"}, + {KEY_DBL2JOY1+18, "dblsec_joy19"}, + {KEY_DBL2JOY1+19, "dblsec_joy20"}, + {KEY_DBL2JOY1+20, "dblsec_joy21"}, + {KEY_DBL2JOY1+21, "dblsec_joy22"}, + {KEY_DBL2JOY1+22, "dblsec_joy23"}, + {KEY_DBL2JOY1+23, "dblsec_joy24"}, + {KEY_DBL2JOY1+24, "dblsec_joy25"}, + {KEY_DBL2JOY1+25, "dblsec_joy26"}, + {KEY_DBL2JOY1+26, "dblsec_joy27"}, + {KEY_DBL2JOY1+27, "dblsec_joy28"}, + {KEY_DBL2JOY1+28, "dblsec_joy29"}, + {KEY_DBL2JOY1+29, "dblsec_joy30"}, + {KEY_DBL2JOY1+30, "dblsec_joy31"}, + {KEY_DBL2JOY1+31, "dblsec_joy32"}, #endif - {KEY_DBL2HAT1+0, "DBLSEC_HATUP"}, - {KEY_DBL2HAT1+1, "DBLSEC_HATDOWN"}, - {KEY_DBL2HAT1+2, "DBLSEC_HATLEFT"}, - {KEY_DBL2HAT1+3, "DBLSEC_HATRIGHT"}, - {KEY_DBL2HAT1+4, "DBLSEC_HATUP2"}, - {KEY_DBL2HAT1+5, "DBLSEC_HATDOWN2"}, - {KEY_DBL2HAT1+6, "DBLSEC_HATLEFT2"}, - {KEY_DBL2HAT1+7, "DBLSEC_HATRIGHT2"}, - {KEY_DBL2HAT1+8, "DBLSEC_HATUP3"}, - {KEY_DBL2HAT1+9, "DBLSEC_HATDOWN3"}, - {KEY_DBL2HAT1+10, "DBLSEC_HATLEFT3"}, - {KEY_DBL2HAT1+11, "DBLSEC_HATRIGHT3"}, - {KEY_DBL2HAT1+12, "DBLSEC_HATUP4"}, - {KEY_DBL2HAT1+13, "DBLSEC_HATDOWN4"}, - {KEY_DBL2HAT1+14, "DBLSEC_HATLEFT4"}, - {KEY_DBL2HAT1+15, "DBLSEC_HATRIGHT4"}, + {KEY_DBL2HAT1+0, "dblsec_hatup"}, + {KEY_DBL2HAT1+1, "dblsec_hatdown"}, + {KEY_DBL2HAT1+2, "dblsec_hatleft"}, + {KEY_DBL2HAT1+3, "dblsec_hatright"}, + {KEY_DBL2HAT1+4, "dblsec_hatup2"}, + {KEY_DBL2HAT1+5, "dblsec_hatdown2"}, + {KEY_DBL2HAT1+6, "dblsec_hatleft2"}, + {KEY_DBL2HAT1+7, "dblsec_hatright2"}, + {KEY_DBL2HAT1+8, "dblsec_hatup3"}, + {KEY_DBL2HAT1+9, "dblsec_hatdown3"}, + {KEY_DBL2HAT1+10, "dblsec_hatleft3"}, + {KEY_DBL2HAT1+11, "dblsec_hatright3"}, + {KEY_DBL2HAT1+12, "dblsec_hatup4"}, + {KEY_DBL2HAT1+13, "dblsec_hatdown4"}, + {KEY_DBL2HAT1+14, "dblsec_hatleft4"}, + {KEY_DBL2HAT1+15, "dblsec_hatright4"}, }; -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", @@ -619,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); @@ -630,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]; @@ -654,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; @@ -682,92 +676,98 @@ 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_LCTRL; + 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] = KEY_RALT; + gamecontroldefault[gcs_fps][GC_FIRENORMAL ][1] = KEY_MOUSE1+1; + gamecontroldefault[gcs_fps][GC_CUSTOM1 ][0] = 'z'; + gamecontroldefault[gcs_fps][GC_CUSTOM2 ][0] = 'x'; + gamecontroldefault[gcs_fps][GC_CUSTOM3 ][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'; + // Platform game controls (arrow keys), currently unused + 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_JUMP ][1] = KEY_JOY1+0; // A + gamecontroldefault[i][GC_SPIN ][1] = KEY_JOY1+2; // X + gamecontroldefault[i][GC_CUSTOM1 ][1] = KEY_JOY1+1; // B + gamecontroldefault[i][GC_CUSTOM2 ][1] = KEY_JOY1+3; // Y + gamecontroldefault[i][GC_CUSTOM3 ][1] = KEY_JOY1+8; // Left Stick + gamecontroldefault[i][GC_CENTERVIEW ][1] = KEY_JOY1+9; // Right Stick + gamecontroldefault[i][GC_WEAPONPREV ][1] = KEY_JOY1+4; // LB + gamecontroldefault[i][GC_WEAPONNEXT ][1] = KEY_JOY1+5; // RB + gamecontroldefault[i][GC_SCREENSHOT ][1] = KEY_JOY1+6; // Back + gamecontroldefault[i][GC_SYSTEMMENU ][0] = KEY_JOY1+7; // Start + gamecontroldefault[i][GC_CAMTOGGLE ][1] = KEY_HAT1+0; // D-Pad Up + gamecontroldefault[i][GC_VIEWPOINT ][1] = KEY_HAT1+1; // D-Pad Down + gamecontroldefault[i][GC_TOSSFLAG ][1] = KEY_HAT1+2; // D-Pad Left + gamecontroldefault[i][GC_SCORES ][1] = KEY_HAT1+3; // D-Pad Right // 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_JUMP ][1] = KEY_2JOY1+0; // A + gamecontrolbisdefault[i][GC_SPIN ][1] = KEY_2JOY1+2; // X + gamecontrolbisdefault[i][GC_CUSTOM1 ][1] = KEY_2JOY1+1; // B + gamecontrolbisdefault[i][GC_CUSTOM2 ][1] = KEY_2JOY1+3; // Y + gamecontrolbisdefault[i][GC_CUSTOM3 ][1] = KEY_2JOY1+8; // Left Stick + gamecontrolbisdefault[i][GC_CENTERVIEW ][1] = KEY_2JOY1+9; // Right Stick + gamecontrolbisdefault[i][GC_WEAPONPREV ][1] = KEY_2JOY1+4; // LB + gamecontrolbisdefault[i][GC_WEAPONNEXT ][1] = KEY_2JOY1+5; // RB + gamecontrolbisdefault[i][GC_SCREENSHOT ][1] = KEY_2JOY1+6; // Back + //gamecontrolbisdefault[i][GC_SYSTEMMENU ][0] = KEY_2JOY1+7; // Start + gamecontrolbisdefault[i][GC_CAMTOGGLE ][1] = KEY_2HAT1+0; // D-Pad Up + gamecontrolbisdefault[i][GC_VIEWPOINT ][1] = KEY_2HAT1+1; // D-Pad Down + gamecontrolbisdefault[i][GC_TOSSFLAG ][1] = KEY_2HAT1+2; // D-Pad Left + //gamecontrolbisdefault[i][GC_SCORES ][1] = KEY_2HAT1+3; // D-Pad Right } } @@ -779,7 +779,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) && @@ -802,7 +802,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]; @@ -814,24 +814,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"); } @@ -839,11 +839,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) { @@ -889,11 +889,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; @@ -901,7 +901,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]); @@ -999,16 +999,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) @@ -1073,3 +1073,17 @@ void Command_Setcontrol2_f(void) setcontrol(gamecontrolbis); } + +void G_SetMouseDeltas(INT32 dx, INT32 dy, UINT8 ssplayer) +{ + mouse_t *m = ssplayer == 1 ? &mouse : &mouse2; + consvar_t *cvsens, *cvysens; + + cvsens = ssplayer == 1 ? &cv_mousesens : &cv_mousesens2; + cvysens = ssplayer == 1 ? &cv_mouseysens : &cv_mouseysens2; + m->rdx = dx; + m->rdy = dy; + m->dx = (INT32)(m->rdx*((cvsens->value*cvsens->value)/110.0f + 0.1f)); + m->dy = (INT32)(m->rdy*((cvsens->value*cvsens->value)/110.0f + 0.1f)); + m->mlookdy = (INT32)(m->rdy*((cvysens->value*cvsens->value)/110.0f + 0.1f)); +} diff --git a/src/g_input.h b/src/g_input.h index ce38f6ba9..bf6ad39b3 100644 --- a/src/g_input.h +++ b/src/g_input.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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 @@ -116,9 +116,29 @@ extern consvar_t cv_mousesens, cv_mouseysens; extern consvar_t cv_mousesens2, cv_mouseysens2; extern consvar_t cv_controlperkey; -extern INT32 mousex, mousey; -extern INT32 mlooky; //mousey with mlookSensitivity -extern INT32 mouse2x, mouse2y, mlook2y; +typedef struct +{ + INT32 dx; // deltas with mousemove sensitivity + INT32 dy; + INT32 mlookdy; // dy with mouselook sensitivity + INT32 rdx; // deltas without sensitivity + INT32 rdy; + UINT16 buttons; +} mouse_t; + +#define MB_BUTTON1 0x0001 +#define MB_BUTTON2 0x0002 +#define MB_BUTTON3 0x0004 +#define MB_BUTTON4 0x0008 +#define MB_BUTTON5 0x0010 +#define MB_BUTTON6 0x0020 +#define MB_BUTTON7 0x0040 +#define MB_BUTTON8 0x0080 +#define MB_SCROLLUP 0x0100 +#define MB_SCROLLDOWN 0x0200 + +extern mouse_t mouse; +extern mouse_t mouse2; extern INT32 joyxmove[JOYAXISSET], joyymove[JOYAXISSET], joy2xmove[JOYAXISSET], joy2ymove[JOYAXISSET]; @@ -126,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)) @@ -161,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); @@ -175,4 +195,7 @@ void G_CopyControls(INT32 (*setupcontrols)[2], INT32 (*fromcontrols)[2], const I void G_SaveKeySetting(FILE *f, INT32 (*fromcontrols)[2], INT32 (*fromcontrolsbis)[2]); INT32 G_CheckDoubleUsage(INT32 keynum, boolean modify); +// sets the members of a mouse_t given position deltas +void G_SetMouseDeltas(INT32 dx, INT32 dy, UINT8 ssplayer); + #endif diff --git a/src/g_state.h b/src/g_state.h index e364c5a35..a6ac1970d 100644 --- a/src/g_state.h +++ b/src/g_state.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hardware/CMakeLists.txt b/src/hardware/CMakeLists.txt new file mode 100644 index 000000000..4e9c67d2f --- /dev/null +++ b/src/hardware/CMakeLists.txt @@ -0,0 +1 @@ +target_sourcefile(c) diff --git a/src/hardware/Sourcefile b/src/hardware/Sourcefile new file mode 100644 index 000000000..1c05de76c --- /dev/null +++ b/src/hardware/Sourcefile @@ -0,0 +1,13 @@ +hw_bsp.c +hw_draw.c +hw_light.c +hw_main.c +hw_clip.c +hw_md2.c +hw_cache.c +hw_md2load.c +hw_md3load.c +hw_model.c +u_list.c +hw_batching.c +r_opengl/r_opengl.c diff --git a/src/hardware/hw_batching.c b/src/hardware/hw_batching.c index fb3417158..f9c6542ae 100644 --- a/src/hardware/hw_batching.c +++ b/src/hardware/hw_batching.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2020-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -137,6 +137,8 @@ static int comparePolygons(const void *p1, const void *p2) PolygonArrayEntry* poly2 = &polygonArray[index2]; int diff; INT64 diff64; + UINT32 downloaded1 = 0; + UINT32 downloaded2 = 0; int shader1 = poly1->shader; int shader2 = poly2->shader; @@ -152,7 +154,11 @@ static int comparePolygons(const void *p1, const void *p2) if (shader1 == -1 && shader2 == -1) return index1 - index2; - diff64 = poly1->texture - poly2->texture; + if (poly1->texture) + downloaded1 = poly1->texture->downloaded; // there should be a opengl texture name here, usable for comparisons + if (poly2->texture) + downloaded2 = poly2->texture->downloaded; + diff64 = downloaded1 - downloaded2; if (diff64 != 0) return diff64; diff = poly1->polyFlags - poly2->polyFlags; @@ -184,16 +190,21 @@ static int comparePolygonsNoShaders(const void *p1, const void *p2) GLMipmap_t *texture1 = poly1->texture; GLMipmap_t *texture2 = poly2->texture; + UINT32 downloaded1 = 0; + UINT32 downloaded2 = 0; if (poly1->polyFlags & PF_NoTexture || poly1->horizonSpecial) texture1 = NULL; if (poly2->polyFlags & PF_NoTexture || poly2->horizonSpecial) texture2 = NULL; - diff64 = texture1 - texture2; - if (diff64 != 0) return diff64; - + if (texture1) + downloaded1 = texture1->downloaded; // there should be a opengl texture name here, usable for comparisons + if (texture2) + downloaded2 = texture2->downloaded; // skywalls and horizon lines must retain their order for horizon lines to work - if (texture1 == NULL && texture2 == NULL) + if (!texture1 && !texture2) return index1 - index2; + diff64 = downloaded1 - downloaded2; + if (diff64 != 0) return diff64; diff = poly1->polyFlags - poly2->polyFlags; if (diff != 0) return diff; @@ -234,13 +245,16 @@ void HWR_RenderBatches(void) currently_batching = false;// no longer collecting batches if (!polygonArraySize) { - ps_hw_numpolys = ps_hw_numcalls = ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 0; + ps_hw_numpolys.value.i = ps_hw_numcalls.value.i = ps_hw_numshaders.value.i + = ps_hw_numtextures.value.i = ps_hw_numpolyflags.value.i + = ps_hw_numcolors.value.i = 0; return;// nothing to draw } // init stats vars - ps_hw_numpolys = polygonArraySize; - ps_hw_numcalls = ps_hw_numverts = 0; - ps_hw_numshaders = ps_hw_numtextures = ps_hw_numpolyflags = ps_hw_numcolors = 1; + ps_hw_numpolys.value.i = polygonArraySize; + ps_hw_numcalls.value.i = ps_hw_numverts.value.i = 0; + ps_hw_numshaders.value.i = ps_hw_numtextures.value.i + = ps_hw_numpolyflags.value.i = ps_hw_numcolors.value.i = 1; // init polygonIndexArray for (i = 0; i < polygonArraySize; i++) { @@ -248,12 +262,12 @@ void HWR_RenderBatches(void) } // sort polygons - ps_hw_batchsorttime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_batchsorttime); if (cv_glshaders.value && gl_shadersavailable) qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygons); else qsort(polygonIndexArray, polygonArraySize, sizeof(unsigned int), comparePolygonsNoShaders); - ps_hw_batchsorttime = I_GetPreciseTime() - ps_hw_batchsorttime; + PS_STOP_TIMING(ps_hw_batchsorttime); // sort order // 1. shader // 2. texture @@ -261,7 +275,7 @@ void HWR_RenderBatches(void) // 4. colors + light level // not sure about what order of the last 2 should be, or if it even matters - ps_hw_batchdrawtime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_batchdrawtime); currentShader = polygonArray[polygonIndexArray[0]].shader; currentTexture = polygonArray[polygonIndexArray[0]].texture; @@ -397,8 +411,8 @@ void HWR_RenderBatches(void) // execute draw call HWD.pfnDrawIndexedTriangles(¤tSurfaceInfo, finalVertexArray, finalIndexWritePos, currentPolyFlags, finalVertexIndexArray); // update stats - ps_hw_numcalls++; - ps_hw_numverts += finalIndexWritePos; + ps_hw_numcalls.value.i++; + ps_hw_numverts.value.i += finalIndexWritePos; // reset write positions finalVertexWritePos = 0; finalIndexWritePos = 0; @@ -415,7 +429,7 @@ void HWR_RenderBatches(void) currentShader = nextShader; changeShader = false; - ps_hw_numshaders++; + ps_hw_numshaders.value.i++; } if (changeTexture) { @@ -424,21 +438,21 @@ void HWR_RenderBatches(void) currentTexture = nextTexture; changeTexture = false; - ps_hw_numtextures++; + ps_hw_numtextures.value.i++; } if (changePolyFlags) { currentPolyFlags = nextPolyFlags; changePolyFlags = false; - ps_hw_numpolyflags++; + ps_hw_numpolyflags.value.i++; } if (changeSurfaceInfo) { currentSurfaceInfo = nextSurfaceInfo; changeSurfaceInfo = false; - ps_hw_numcolors++; + ps_hw_numcolors.value.i++; } // and that should be it? } @@ -446,7 +460,7 @@ void HWR_RenderBatches(void) polygonArraySize = 0; unsortedVertexArraySize = 0; - ps_hw_batchdrawtime = I_GetPreciseTime() - ps_hw_batchdrawtime; + PS_STOP_TIMING(ps_hw_batchdrawtime); } diff --git a/src/hardware/hw_batching.h b/src/hardware/hw_batching.h index 42291a0df..df5c478a3 100644 --- a/src/hardware/hw_batching.h +++ b/src/hardware/hw_batching.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2020-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index b4fa7ec6c..fe0b65c50 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -108,7 +108,7 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm //Hurdler: 25/04/2000: now support colormap in hardware mode if (mipmap->colormap) - texel = mipmap->colormap[texel]; + texel = mipmap->colormap->data[texel]; // hope compiler will get this switch out of the loops (dreams...) // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?) @@ -218,7 +218,7 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, //Hurdler: 25/04/2000: now support colormap in hardware mode if (mipmap->colormap) - texel = mipmap->colormap[texel]; + texel = mipmap->colormap->data[texel]; // hope compiler will get this switch out of the loops (dreams...) // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?) @@ -659,7 +659,10 @@ void HWR_FreeTextureColormaps(patch_t *patch) // Free image data from memory. if (next->data) Z_Free(next->data); + if (next->colormap) + Z_Free(next->colormap); next->data = NULL; + next->colormap = NULL; HWD.pfnDeleteTexture(next); // Free the old colormap mipmap from memory. @@ -667,16 +670,29 @@ void HWR_FreeTextureColormaps(patch_t *patch) } } +static boolean FreeTextureCallback(void *mem) +{ + patch_t *patch = (patch_t *)mem; + HWR_FreeTexture(patch); + return false; +} + +static boolean FreeColormapsCallback(void *mem) +{ + patch_t *patch = (patch_t *)mem; + HWR_FreeTextureColormaps(patch); + return false; +} + static void HWR_FreePatchCache(boolean freeall) { - INT32 i; + boolean (*callback)(void *mem) = FreeTextureCallback; - for (i = 0; i < numwadfiles; i++) - { - INT32 j = 0; - for (; j < wadfiles[i]->numlumps; j++) - (freeall ? HWR_FreeTexture : HWR_FreeTextureColormaps)(wadfiles[i]->patchcache[j]); - } + if (!freeall) + callback = FreeColormapsCallback; + + Z_IterateTags(PU_PATCH, PU_PATCH_ROTATED, callback); + Z_IterateTags(PU_SPRITE, PU_HUDGFX, callback); } // free all textures after each level @@ -850,7 +866,7 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) } // Download a Doom 'flat' to the hardware cache and make it ready for use -void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum) +void HWR_GetRawFlat(lumpnum_t flatlumpnum) { GLMipmap_t *grmip; patch_t *patch; @@ -879,7 +895,7 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) return; if (levelflat->type == LEVELFLAT_FLAT) - HWR_LiterallyGetFlat(levelflat->u.flat.lumpnum); + HWR_GetRawFlat(levelflat->u.flat.lumpnum); else if (levelflat->type == LEVELFLAT_TEXTURE) { GLMapTexture_t *grtex; @@ -918,15 +934,17 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) #ifndef NO_PNG_LUMPS else if (levelflat->type == LEVELFLAT_PNG) { - INT32 pngwidth = 0, pngheight = 0; GLMipmap_t *mipmap = levelflat->mipmap; - UINT8 *flat; - size_t size; // Cache the picture. - if (!levelflat->picture) + if (!levelflat->mippic) { - levelflat->picture = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); + INT32 pngwidth = 0, pngheight = 0; + void *pic = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); + + Z_ChangeTag(pic, PU_LEVEL); + Z_SetUser(pic, &levelflat->mippic); + levelflat->width = (UINT16)pngwidth; levelflat->height = (UINT16)pngheight; } @@ -934,7 +952,7 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) // Make the mipmap. if (mipmap == NULL) { - mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_LEVEL, NULL); + mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_STATIC, NULL); mipmap->format = GL_TEXFMT_P_8; mipmap->flags = TF_WRAPXY|TF_CHROMAKEYED; levelflat->mipmap = mipmap; @@ -942,17 +960,22 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) if (!mipmap->data && !mipmap->downloaded) { + UINT8 *flat; + size_t size; + + if (levelflat->mippic == NULL) + I_Error("HWR_GetLevelFlat: levelflat->mippic == NULL"); + mipmap->width = levelflat->width; mipmap->height = levelflat->height; + size = (mipmap->width * mipmap->height); flat = Z_Malloc(size, PU_LEVEL, &mipmap->data); - if (levelflat->picture == NULL) - I_Error("HWR_GetLevelFlat: levelflat->picture == NULL"); - M_Memcpy(flat, levelflat->picture, size); + M_Memcpy(flat, levelflat->mippic, size); } // Tell the hardware driver to bind the current texture to the flat's mipmap - HWD.pfnSetTexture(mipmap); + HWR_SetCurrentTexture(mipmap); } #endif else // set no texture @@ -977,8 +1000,28 @@ static void HWR_LoadPatchMipmap(patch_t *patch, GLMipmap_t *grMipmap) Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED); } +// ----------------------+ +// HWR_UpdatePatchMipmap : Updates a mipmap. +// ----------------------+ +static void HWR_UpdatePatchMipmap(patch_t *patch, GLMipmap_t *grMipmap) +{ + GLPatch_t *grPatch = patch->hardware; + HWR_MakePatch(patch, grPatch, grMipmap, true); + + // If hardware does not have the texture, then call pfnSetTexture to upload it + // If it does have the texture, then call pfnUpdateTexture to update it + if (!grMipmap->downloaded) + HWD.pfnSetTexture(grMipmap); + else + HWD.pfnUpdateTexture(grMipmap); + HWR_SetCurrentTexture(grMipmap); + + // The system-memory data can be purged now. + Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED); +} + // -----------------+ -// HWR_GetPatch : Download a patch to the hardware cache and make it ready for use +// HWR_GetPatch : Downloads a patch to the hardware cache and make it ready for use // -----------------+ void HWR_GetPatch(patch_t *patch) { @@ -1006,14 +1049,20 @@ void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap) return; } - // search for the mimmap + // search for the mipmap // skip the first (no colormap translated) for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { grMipmap = grMipmap->nextcolormap; - if (grMipmap->colormap == colormap) + if (grMipmap->colormap && grMipmap->colormap->source == colormap) { - HWR_LoadPatchMipmap(patch, grMipmap); + if (memcmp(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8))) + { + M_Memcpy(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); + HWR_UpdatePatchMipmap(patch, grMipmap); + } + else + HWR_LoadPatchMipmap(patch, grMipmap); return; } } @@ -1029,7 +1078,10 @@ void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap) I_Error("%s: Out of memory", "HWR_GetMappedPatch"); grMipmap->nextcolormap = newMipmap; - newMipmap->colormap = colormap; + newMipmap->colormap = Z_Calloc(sizeof(*newMipmap->colormap), PU_HWRPATCHCOLMIPMAP, NULL); + newMipmap->colormap->source = colormap; + M_Memcpy(newMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); + HWR_LoadPatchMipmap(patch, newMipmap); } @@ -1039,7 +1091,6 @@ void HWR_UnlockCachedPatch(GLPatch_t *gpatch) return; Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED); - Z_ChangeTag(gpatch, PU_HWRPATCHINFO_UNLOCKED); } static const INT32 picmode2GR[] = diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h index 3ae4ef8bc..ceefe9abd 100644 --- a/src/hardware/hw_data.h +++ b/src/hardware/hw_data.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -39,45 +39,53 @@ typedef enum GLTextureFormat_e GL_TEXFMT_ALPHA_INTENSITY_88 = 0x22, } GLTextureFormat_t; -// data holds the address of the graphics data cached in heap memory -// NULL if the texture is not in Doom heap cache. +// Colormap structure for mipmaps. +struct GLColormap_s +{ + const UINT8 *source; + UINT8 data[256]; +}; +typedef struct GLColormap_s GLColormap_t; + + +// Texture information (misleadingly named "mipmap" all over the code.) +// The *data pointer holds the address of the graphics data cached in heap memory. +// NULL if the texture is not in SRB2's heap cache. struct GLMipmap_s { - // for TexDownloadMipMap + // for UpdateTexture GLTextureFormat_t format; void *data; UINT32 flags; UINT16 height; UINT16 width; - UINT32 downloaded; // The GPU has this texture. + UINT32 downloaded; // The GPU has this texture. struct GLMipmap_s *nextcolormap; - const UINT8 *colormap; - - struct GLMipmap_s *nextmipmap; // Linked list of all textures + struct GLColormap_s *colormap; }; typedef struct GLMipmap_s GLMipmap_t; // -// Doom texture info, as cached for hardware rendering +// Level textures, as cached for hardware rendering. // struct GLMapTexture_s { GLMipmap_t mipmap; - float scaleX; //used for scaling textures on walls + float scaleX; // Used for scaling textures on walls float scaleY; }; typedef struct GLMapTexture_s GLMapTexture_t; -// a cached patch as converted to hardware format +// Patch information for the hardware renderer. struct GLPatch_s { - float max_s,max_t; - GLMipmap_t *mipmap; -} ATTRPACK; + GLMipmap_t *mipmap; // Texture data. Allocated whenever the patch is. + float max_s, max_t; +}; typedef struct GLPatch_s GLPatch_t; #endif //_HWR_DATA_ diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index a782762a3..fca9b80a3 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -216,28 +216,28 @@ enum EPolyFlags PF_Masked = 0x00000001, // Poly is alpha scaled and 0 alpha pixels are discarded (holes in texture) PF_Translucent = 0x00000002, // Poly is transparent, alpha = level of transparency PF_Environment = 0x00000004, // Poly should be drawn environment mapped. (Hurdler: used for text drawing) - PF_Additive = 0x00000008, // Additive color blending - PF_AdditiveSource = 0x00000010, // Source blending factor is additive. This is the opposite of regular additive blending. - PF_Subtractive = 0x00000020, // Subtractive color blending - PF_ReverseSubtract = 0x00000040, // Reverse subtract, used in wall splats (decals) - PF_Multiplicative = 0x00000080, // Multiplicative color blending + PF_Additive = 0x00000008, // Source blending factor is additive. + PF_Subtractive = 0x00000010, // Subtractive color blending + PF_ReverseSubtract = 0x00000020, // Reverse subtract, used in wall splats (decals) + PF_Multiplicative = 0x00000040, // Multiplicative color blending PF_Fog = 0x20000000, // Fog blocks PF_NoAlphaTest = 0x40000000, // Disables alpha testing - PF_Blending = (PF_Masked|PF_Translucent|PF_Environment|PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Fog) & ~PF_NoAlphaTest, + PF_Blending = (PF_Masked|PF_Translucent|PF_Environment|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Fog) & ~PF_NoAlphaTest, // other flag bits PF_Occlude = 0x00000100, // Updates the depth buffer PF_NoDepthTest = 0x00000200, // Disables the depth test mode PF_Invisible = 0x00000400, // Disables write to color buffer PF_Decal = 0x00000800, // Enables polygon offset - PF_Modulated = 0x00001000, // Modulation (multiply output with constant ARGB) + PF_Modulated = 0x00001000, // Modulation (multiply output with constant RGBA) // When set, pass the color constant into the FSurfaceInfo -> PolyColor PF_NoTexture = 0x00002000, // Disables texturing PF_Corona = 0x00004000, // Tells the renderer we are drawing a corona - PF_Ripple = 0x00008000, // Water effect shader + PF_ColorMapped = 0x00008000, // Surface has "tint" and "fade" colors, which are sent as uniforms to a shader. PF_RemoveYWrap = 0x00010000, // Forces clamp texture on Y PF_ForceWrapX = 0x00020000, // Forces repeat texture on X - PF_ForceWrapY = 0x00040000 // Forces repeat texture on Y + PF_ForceWrapY = 0x00040000, // Forces repeat texture on Y + PF_Ripple = 0x00100000 // Water ripple effect. The current backend doesn't use it for anything. }; @@ -255,9 +255,17 @@ enum ETextureFlags TF_TRANSPARENT = 0x00000040, // texture with some alpha == 0 }; -typedef struct GLMipmap_s FTextureInfo; +struct FTextureInfo +{ + UINT32 width, height; + UINT32 downloaded; + UINT32 format; + + struct GLMipmap_s *texture; + struct FTextureInfo *prev, *next; +}; +typedef struct FTextureInfo FTextureInfo; -// jimita 14032019 struct FLightInfo { FUINT light_level; @@ -273,7 +281,7 @@ struct FSurfaceInfo RGBA_t PolyColor; RGBA_t TintColor; RGBA_t FadeColor; - FLightInfo LightInfo; // jimita 14032019 + FLightInfo LightInfo; }; typedef struct FSurfaceInfo FSurfaceInfo; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index c5d362520..691e3cd3f 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -119,11 +119,6 @@ void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option) flags = PF_Translucent|PF_NoDepthTest; - if (option & V_WRAPX) - flags |= PF_ForceWrapX; - if (option & V_WRAPY) - flags |= PF_ForceWrapY; - // clip it since it is used for bunny scroll in doom I HWD.pfnDrawPolygon(NULL, v, 4, flags); } @@ -135,6 +130,7 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + UINT8 blendmode = ((option & V_BLENDMASK) >> V_BLENDSHIFT); GLPatch_t *hwrPatch; // 3--2 @@ -145,9 +141,6 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p UINT8 perplayershuffle = 0; - if (alphalevel >= 10 && alphalevel < 13) - return; - // make patch ready in hardware cache if (!colormap) HWR_GetPatch(gpatch); @@ -191,15 +184,9 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p offsetx = (float)(gpatch->leftoffset) * fscalew; // top offset - // TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!? + // TODO: make some kind of vertical version of V_FLIP offsety = (float)(gpatch->topoffset) * fscaleh; - if ((option & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs - { - offsetx *= dupx; - offsety *= dupy; - } - cx -= offsetx; cy -= offsety; } @@ -317,7 +304,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; @@ -359,21 +346,17 @@ void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t p v[0].t = v[1].t = 0.0f; v[2].t = v[3].t = hwrPatch->max_t; - flags = PF_Translucent|PF_NoDepthTest; - - if (option & V_WRAPX) - flags |= PF_ForceWrapX; - if (option & V_WRAPY) - flags |= PF_ForceWrapY; - // clip it since it is used for bunny scroll in doom I + flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; + if (alphalevel) { FSurfaceInfo Surf; Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; - if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; - else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; - else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; + + if (alphalevel == 10) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; // V_HUDTRANSHALF + else if (alphalevel == 11) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; // V_HUDTRANS + else if (alphalevel == 12) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; // V_HUDTRANSDOUBLE else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); @@ -382,26 +365,30 @@ 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; float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + UINT8 blendmode = ((option & V_BLENDMASK) >> V_BLENDSHIFT); GLPatch_t *hwrPatch; // 3--2 // | /| // |/ | // 0--1 - float dupx, dupy, fscale, fwidth, fheight; + float dupx, dupy, fscalew, fscaleh, fwidth, fheight; - if (alphalevel >= 10 && alphalevel < 13) - return; + UINT8 perplayershuffle = 0; // 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 +410,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)) { @@ -437,18 +492,9 @@ void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, if (!(option & V_SCALEPATCHMASK)) { - // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) - // cx and cy are possibly *slightly* off from float maths - // This is done before here compared to software because we directly alter cx and cy to centre - if (cx >= -0.1f && cx <= 0.1f && gpatch->width == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && gpatch->height == BASEVIDHEIGHT) - { - const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0])); - if (!column->topdelta) - { - const UINT8 *source = (const UINT8 *)(column) + 3; - HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); - } - } + // if it's meant to cover the whole screen, black out the rest + // no the patch is cropped do not do this ever + // centre screen if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) { @@ -456,6 +502,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) { @@ -463,23 +513,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 (fwidth > gpatch->width) - fwidth = gpatch->width; + if (sx + w > gpatch->width<width< gpatch->height) - fheight = gpatch->height; + if (sy + h > gpatch->height<height<width))*hwrPatch->max_s; - if (sx + w > gpatch->width) - v[2].s = v[1].s = hwrPatch->max_s - ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s; + v[0].s = v[3].s = (FIXED_TO_FLOAT(sx)/(float)(gpatch->width))*hwrPatch->max_s; + if (sx + w > gpatch->width<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[2].t = v[3].t = hwrPatch->max_t - ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t; + v[0].t = v[1].t = (FIXED_TO_FLOAT(sy)/(float)(gpatch->height))*hwrPatch->max_t; + if (sy + h > gpatch->height<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; + // Auto-crop at splitscreen borders! + if (splitscreen && (option & V_PERPLAYER)) + { +#define flerp(a,b,amount) (((a) * (1.0f - (amount))) + ((b) * (amount))) // Float lerp - if (option & V_WRAPX) - flags |= PF_ForceWrapX; - if (option & V_WRAPY) - flags |= PF_ForceWrapY; +#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 + flags = HWR_GetBlendModeFlag(blendmode+1)|PF_NoDepthTest; + if (alphalevel) { FSurfaceInfo Surf; Surf.PolyColor.s.red = Surf.PolyColor.s.green = Surf.PolyColor.s.blue = 0xff; - if (alphalevel == 13) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; - else if (alphalevel == 14) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; - else if (alphalevel == 15) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; + + if (alphalevel == 10) Surf.PolyColor.s.alpha = softwaretranstogl_lo[st_translucency]; // V_HUDTRANSHALF + else if (alphalevel == 11) Surf.PolyColor.s.alpha = softwaretranstogl[st_translucency]; // V_HUDTRANS + else if (alphalevel == 12) Surf.PolyColor.s.alpha = softwaretranstogl_hi[st_translucency]; // V_HUDTRANSDOUBLE else Surf.PolyColor.s.alpha = softwaretranstogl[10-alphalevel]; + flags |= PF_Modulated; HWD.pfnDrawPolygon(&Surf, v, 4, flags); } @@ -639,7 +760,7 @@ void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum v[0].t = v[1].t = (float)((y & flatflag)/dflatsize); v[2].t = v[3].t = (float)(v[0].t + h/dflatsize); - HWR_LiterallyGetFlat(flatlumpnum); + HWR_GetRawFlat(flatlumpnum); //Hurdler: Boris, the same comment as above... but maybe for pics // it not a problem since they don't have any transparent pixel diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 5a2e0e44e..718774773 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -40,13 +40,12 @@ EXPORT void HWRAPI(DrawIndexedTriangles) (FSurfaceInfo *pSurf, FOutVector *pOutV EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky); EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); -EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); -EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *TexInfo); -EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *TexInfo); +EXPORT void HWRAPI(SetTexture) (GLMipmap_t *TexInfo); +EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *TexInfo); +EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *TexInfo); EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); -EXPORT void HWRAPI(ClearCacheList) (void); //Hurdler: added for backward compatibility EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); @@ -69,7 +68,6 @@ EXPORT void HWRAPI(DrawScreenFinalTexture) (int width, int height); #define SCREENVERTS 10 EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); -// jimita EXPORT boolean HWRAPI(CompileShaders) (void); EXPORT void HWRAPI(CleanShaders) (void); EXPORT void HWRAPI(SetShader) (int type); @@ -101,7 +99,6 @@ struct hwdriver_s ReadRect pfnReadRect; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; - ClearCacheList pfnClearCacheList; SetSpecialState pfnSetSpecialState;//Hurdler: added for backward compatibility DrawModel pfnDrawModel; CreateModelVBOs pfnCreateModelVBOs; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 87405d3d4..8b30a3468 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -118,7 +118,7 @@ patch_t *HWR_GetPic(lumpnum_t lumpnum); GLMapTexture_t *HWR_GetTexture(INT32 tex); void HWR_GetLevelFlat(levelflat_t *levelflat); -void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum); +void HWR_GetRawFlat(lumpnum_t flatlumpnum); void HWR_FreeTexture(patch_t *patch); void HWR_FreeTextureData(patch_t *patch); diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 987d70c69..eb3c9bbbb 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -35,7 +35,7 @@ #define DL_HIGH_QUALITY //#define STATICLIGHT //Hurdler: TODO! -#define LIGHTMAPFLAGS (PF_Modulated|PF_AdditiveSource) +#define LIGHTMAPFLAGS (PF_Modulated|PF_Additive) #ifdef ALAM_LIGHTING static dynlights_t view_dynlights[2]; // 2 players in splitscreen mode @@ -253,6 +253,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_SIGN &lspr[NOLIGHT], // SPR_SPIK &lspr[NOLIGHT], // SPR_SFLM + &lspr[NOLIGHT], // SPR_TFLM &lspr[NOLIGHT], // SPR_USPK &lspr[NOLIGHT], // SPR_WSPK &lspr[NOLIGHT], // SPR_WSPB @@ -1055,7 +1056,7 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gl_vissprite_t *spr) HWR_GetPic(coronalumpnum); /// \todo use different coronas - HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_Corona | PF_NoDepthTest); + HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Corona | PF_NoDepthTest); } } #endif @@ -1143,7 +1144,7 @@ void HWR_DrawCoronas(void) light[3].y = cy+size*1.33f; light[3].s = 0.0f; light[3].t = 1.0f; - HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_NoDepthTest | PF_Corona); + HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_NoDepthTest | PF_Corona); } } #endif diff --git a/src/hardware/hw_light.h b/src/hardware/hw_light.h index fed7db47f..a0a9e93ad 100644 --- a/src/hardware/hw_light.h +++ b/src/hardware/hw_light.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c5f63654b..a6b08812b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -147,22 +147,22 @@ static angle_t gl_aimingangle; static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean skybox); // Render stats -precise_t ps_hw_skyboxtime = 0; -precise_t ps_hw_nodesorttime = 0; -precise_t ps_hw_nodedrawtime = 0; -precise_t ps_hw_spritesorttime = 0; -precise_t ps_hw_spritedrawtime = 0; +ps_metric_t ps_hw_skyboxtime = {0}; +ps_metric_t ps_hw_nodesorttime = {0}; +ps_metric_t ps_hw_nodedrawtime = {0}; +ps_metric_t ps_hw_spritesorttime = {0}; +ps_metric_t ps_hw_spritedrawtime = {0}; // Render stats for batching -int ps_hw_numpolys = 0; -int ps_hw_numverts = 0; -int ps_hw_numcalls = 0; -int ps_hw_numshaders = 0; -int ps_hw_numtextures = 0; -int ps_hw_numpolyflags = 0; -int ps_hw_numcolors = 0; -precise_t ps_hw_batchsorttime = 0; -precise_t ps_hw_batchdrawtime = 0; +ps_metric_t ps_hw_numpolys = {0}; +ps_metric_t ps_hw_numverts = {0}; +ps_metric_t ps_hw_numcalls = {0}; +ps_metric_t ps_hw_numshaders = {0}; +ps_metric_t ps_hw_numtextures = {0}; +ps_metric_t ps_hw_numpolyflags = {0}; +ps_metric_t ps_hw_numcolors = {0}; +ps_metric_t ps_hw_batchsorttime = {0}; +ps_metric_t ps_hw_batchdrawtime = {0}; boolean gl_init = false; boolean gl_maploaded = false; @@ -173,6 +173,11 @@ boolean gl_shadersavailable = true; // Lighting // ========================================================================== +static boolean HWR_UseShader(void) +{ + return (cv_glshaders.value && gl_shadersavailable); +} + void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap) { RGBA_t poly_color, tint_color, fade_color; @@ -182,7 +187,7 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col fade_color.rgba = (colormap != NULL) ? (UINT32)colormap->fadergba : GL_DEFAULTFOG; // Crappy backup coloring if you can't do shaders - if (!cv_glshaders.value || !gl_shadersavailable) + if (!HWR_UseShader()) { // be careful, this may get negative for high lightlevel values. float tint_alpha, fade_alpha; @@ -362,16 +367,16 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool float fflatwidth = 64.0f, fflatheight = 64.0f; INT32 flatflag = 63; boolean texflat = false; - float scrollx = 0.0f, scrolly = 0.0f; + float scrollx = 0.0f, scrolly = 0.0f, anglef = 0.0f; angle_t angle = 0; FSurfaceInfo Surf; - fixed_t tempxsow, tempytow; + float tempxsow, tempytow; pslope_t *slope = NULL; static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; - int shader; + INT32 shader = SHADER_DEFAULT; // no convex poly were generated for this subsector if (!xsub->planepoly) @@ -499,24 +504,15 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool } } - if (angle) // Only needs to be done if there's an altered angle { + tempxsow = flatxref; + tempytow = flatyref; - angle = (InvAngle(angle))>>ANGLETOFINESHIFT; + anglef = ANG2RAD(InvAngle(angle)); - // This needs to be done so that it scrolls in a different direction after rotation like software - /*tempxsow = FLOAT_TO_FIXED(scrollx); - tempytow = FLOAT_TO_FIXED(scrolly); - scrollx = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - scrolly = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));*/ - - // This needs to be done so everything aligns after rotation - // It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does - tempxsow = FLOAT_TO_FIXED(flatxref); - tempytow = FLOAT_TO_FIXED(flatyref); - flatxref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle)))); - flatyref = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle)))); + flatxref = (tempxsow * cos(anglef)) - (tempytow * sin(anglef)); + flatyref = (tempxsow * sin(anglef)) + (tempytow * cos(anglef)); } #define SETUP3DVERT(vert, vx, vy) {\ @@ -535,10 +531,10 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool /* Need to rotate before translate */\ if (angle) /* Only needs to be done if there's an altered angle */\ {\ - tempxsow = FLOAT_TO_FIXED(vert->s);\ - tempytow = FLOAT_TO_FIXED(vert->t);\ - vert->s = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINECOSINE(angle)) - FixedMul(tempytow, FINESINE(angle))));\ - vert->t = (FIXED_TO_FLOAT(FixedMul(tempxsow, FINESINE(angle)) + FixedMul(tempytow, FINECOSINE(angle))));\ + tempxsow = vert->s;\ + tempytow = vert->t;\ + vert->s = (tempxsow * cos(anglef)) - (tempytow * sin(anglef));\ + vert->t = (tempxsow * sin(anglef)) + (tempytow * cos(anglef));\ }\ \ vert->x = (vx);\ @@ -560,7 +556,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool HWR_Lighting(&Surf, lightlevel, planecolormap); - if (PolyFlags & (PF_Translucent|PF_Fog)) + if (PolyFlags & (PF_Translucent|PF_Fog|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Environment)) { Surf.PolyColor.s.alpha = (UINT8)alpha; PolyFlags |= PF_Modulated; @@ -568,12 +564,17 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool else PolyFlags |= PF_Masked|PF_Modulated; - if (PolyFlags & PF_Fog) - shader = SHADER_FOG; // fog shader - else if (PolyFlags & PF_Ripple) - shader = SHADER_WATER; // water shader - else - shader = SHADER_FLOOR; // floor shader + if (HWR_UseShader()) + { + if (PolyFlags & PF_Fog) + shader = SHADER_FOG; + else if (PolyFlags & PF_Ripple) + shader = SHADER_WATER; + else + shader = SHADER_FLOOR; + + PolyFlags |= PF_ColorMapped; + } HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, PolyFlags, shader, false); @@ -702,10 +703,12 @@ static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight) #endif //doplanes -FBITFIELD HWR_GetBlendModeFlag(INT32 ast) +FBITFIELD HWR_GetBlendModeFlag(INT32 style) { - switch (ast) + switch (style) { + case AST_TRANSLUCENT: + return PF_Translucent; case AST_ADD: return PF_Additive; case AST_SUBTRACT: @@ -715,10 +718,8 @@ FBITFIELD HWR_GetBlendModeFlag(INT32 ast) case AST_MODULATE: return PF_Multiplicative; default: - return PF_Translucent; + return PF_Masked; } - - return 0; } UINT8 HWR_GetTranstableAlpha(INT32 transtablenum) @@ -744,7 +745,7 @@ UINT8 HWR_GetTranstableAlpha(INT32 transtablenum) FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf) { - if (!transtablenum) + if (!transtablenum || style <= AST_COPY || style >= AST_OVERLAY) { pSurf->PolyColor.s.alpha = 0xff; return PF_Masked; @@ -785,8 +786,17 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I // static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { + INT32 shader = SHADER_DEFAULT; + HWR_Lighting(pSurf, lightlevel, wallcolormap); - HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, SHADER_WALL, false); // wall shader + + if (HWR_UseShader()) + { + shader = SHADER_WALL; + blendmode |= PF_ColorMapped; + } + + HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, shader, false); } // ========================================================================== @@ -831,7 +841,7 @@ static float HWR_ClipViewSegment(INT32 x, polyvertex_t *v1, polyvertex_t *v2) // // HWR_SplitWall // -static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor) +static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfaceInfo* Surf, INT32 cutflag, ffloor_t *pfloor, FBITFIELD polyflags) { /* SoM: split up and light walls according to the lightlist. This may also include leaving out parts @@ -969,11 +979,11 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, wallVerts[1].y = endbot; if (cutflag & FF_FOG) - HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap); - else if (cutflag & FF_TRANSLUCENT) - HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); + HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture|polyflags, true, lightnum, colormap); + else if (polyflags & (PF_Translucent|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Environment)) + HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, false, lightnum, colormap); else - HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap); + HWR_ProjectWall(wallVerts, Surf, PF_Masked|polyflags, lightnum, colormap); top = bot; endtop = endbot; @@ -998,11 +1008,11 @@ static void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, wallVerts[1].y = endbot; if (cutflag & FF_FOG) - HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture, true, lightnum, colormap); - else if (cutflag & FF_TRANSLUCENT) - HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Translucent, false, lightnum, colormap); + HWR_AddTransparentWall(wallVerts, Surf, texnum, PF_Fog|PF_NoTexture|polyflags, true, lightnum, colormap); + else if (polyflags & (PF_Translucent|PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Environment)) + HWR_AddTransparentWall(wallVerts, Surf, texnum, polyflags, false, lightnum, colormap); else - HWR_ProjectWall(wallVerts, Surf, PF_Masked, lightnum, colormap); + HWR_ProjectWall(wallVerts, Surf, PF_Masked|polyflags, lightnum, colormap); } // HWR_DrawSkyWall @@ -1104,7 +1114,6 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom SLOPEPARAMS(gl_backsector->c_slope, worldhigh, worldhighslope, gl_backsector->ceilingheight) SLOPEPARAMS(gl_backsector->f_slope, worldlow, worldlowslope, gl_backsector->floorheight) -#undef SLOPEPARAMS // hack to allow height changes in outdoor areas // This is what gets rid of the upper textures if there should be sky @@ -1137,7 +1146,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // PEGGING if (gl_linedef->flags & ML_DONTPEGTOP) texturevpegtop = 0; - else if (gl_linedef->flags & ML_EFFECT1) + else if (gl_linedef->flags & ML_SKEWTD) texturevpegtop = worldhigh + textureheight[gl_sidedef->toptexture] - worldtop; else texturevpegtop = gl_backsector->ceilingheight + textureheight[gl_sidedef->toptexture] - gl_frontsector->ceilingheight; @@ -1153,7 +1162,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; // Adjust t value for sloped walls - if (!(gl_linedef->flags & ML_EFFECT1)) + if (!(gl_linedef->flags & ML_SKEWTD)) { // Unskewed wallVerts[3].t -= (worldtop - gl_frontsector->ceilingheight) * grTex->scaleY; @@ -1183,7 +1192,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[1].y = FIXED_TO_FLOAT(worldhighslope); if (gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, gl_toptexture, &Surf, FF_CUTLEVEL, NULL); + HWR_SplitWall(gl_frontsector, wallVerts, gl_toptexture, &Surf, FF_CUTLEVEL, NULL, 0); else if (grTex->mipmap.flags & TF_TRANSPARENT) HWR_AddTransparentWall(wallVerts, &Surf, gl_toptexture, PF_Environment, false, lightnum, colormap); else @@ -1203,7 +1212,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // PEGGING if (!(gl_linedef->flags & ML_DONTPEGBOTTOM)) texturevpegbottom = 0; - else if (gl_linedef->flags & ML_EFFECT1) + else if (gl_linedef->flags & ML_SKEWTD) texturevpegbottom = worldbottom - worldlow; else texturevpegbottom = gl_frontsector->floorheight - gl_backsector->floorheight; @@ -1219,7 +1228,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; // Adjust t value for sloped walls - if (!(gl_linedef->flags & ML_EFFECT1)) + if (!(gl_linedef->flags & ML_SKEWTD)) { // Unskewed wallVerts[0].t -= (worldbottom - gl_frontsector->floorheight) * grTex->scaleY; @@ -1249,12 +1258,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[1].y = FIXED_TO_FLOAT(worldbottomslope); if (gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, gl_bottomtexture, &Surf, FF_CUTLEVEL, NULL); + HWR_SplitWall(gl_frontsector, wallVerts, gl_bottomtexture, &Surf, FF_CUTLEVEL, NULL, 0); else if (grTex->mipmap.flags & TF_TRANSPARENT) HWR_AddTransparentWall(wallVerts, &Surf, gl_bottomtexture, PF_Environment, false, lightnum, colormap); else HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap); } + gl_midtexture = R_GetTextureNum(gl_sidedef->midtexture); if (gl_midtexture) { @@ -1276,7 +1286,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom if (gl_sidedef->repeatcnt) repeats = 1 + gl_sidedef->repeatcnt; - else if (gl_linedef->flags & ML_EFFECT5) + else if (gl_linedef->flags & ML_WRAPMIDTEX) { fixed_t high, low; @@ -1318,9 +1328,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom popenbottom = max(worldbottom, worldlow); } - if (gl_linedef->flags & ML_EFFECT2) + if (gl_linedef->flags & ML_NOSKEW) { - if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3)) + if (gl_linedef->flags & ML_MIDPEG) { polybottom = max(front->floorheight, back->floorheight) + gl_sidedef->rowoffset; polytop = polybottom + textureheight[gl_midtexture]*repeats; @@ -1331,7 +1341,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom polybottom = polytop - textureheight[gl_midtexture]*repeats; } } - else if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3)) + else if (gl_linedef->flags & ML_MIDPEG) { polybottom = popenbottom + gl_sidedef->rowoffset; polytop = polybottom + textureheight[gl_midtexture]*repeats; @@ -1361,7 +1371,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { // PEGGING - if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3)) + if (gl_linedef->flags & ML_MIDPEG) texturevpeg = textureheight[gl_sidedef->midtexture]*repeats - h + polybottom; else texturevpeg = polytop - h; @@ -1384,9 +1394,9 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { fixed_t midtextureslant; - if (gl_linedef->flags & ML_EFFECT2) + if (gl_linedef->flags & ML_NOSKEW) midtextureslant = 0; - else if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3)) + else if (gl_linedef->flags & ML_MIDPEG) midtextureslant = worldlow < worldbottom ? worldbottomslope-worldbottom : worldlowslope-worldlow; @@ -1411,7 +1421,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { // PEGGING - if (!!(gl_linedef->flags & ML_DONTPEGBOTTOM) ^ !!(gl_linedef->flags & ML_EFFECT3)) + if (gl_linedef->flags & ML_MIDPEG) texturevpeg = textureheight[gl_sidedef->midtexture]*repeats - h + polybottom; else texturevpeg = polytop - h; @@ -1425,34 +1435,17 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // set alpha for transparent walls // ooops ! this do not work at all because render order we should render it in backtofront order - switch (gl_linedef->special) + if (gl_linedef->blendmode && gl_linedef->blendmode != AST_FOG) { - // Translucent - case 102: - case 121: - case 123: - case 124: - case 125: - case 141: - case 142: - case 144: - case 145: - case 174: - case 175: - case 192: - case 195: - case 221: - case 253: - case 256: - blendmode = PF_Translucent; - break; - default: - if (gl_linedef->alpha >= 0 && gl_linedef->alpha < FRACUNIT) - blendmode = HWR_TranstableToAlpha(R_GetLinedefTransTable(gl_linedef->alpha), &Surf); - else - blendmode = PF_Masked; - break; + if (gl_linedef->alpha >= 0 && gl_linedef->alpha < FRACUNIT) + blendmode = HWR_SurfaceBlend(gl_linedef->blendmode, R_GetLinedefTransTable(gl_linedef->alpha), &Surf); + else + blendmode = HWR_GetBlendModeFlag(gl_linedef->blendmode); } + else if (gl_linedef->alpha >= 0 && gl_linedef->alpha < FRACUNIT) + blendmode = HWR_TranstableToAlpha(R_GetLinedefTransTable(gl_linedef->alpha), &Surf); + else + blendmode = PF_Masked; if (gl_curline->polyseg && gl_curline->polyseg->translucency > 0) { @@ -1465,14 +1458,16 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = HWR_TranstableToAlpha(gl_curline->polyseg->translucency, &Surf); } + // Render midtextures on two-sided lines with a z-buffer offset. + // This will cause the midtexture appear on top, if a FOF overlaps with it. + blendmode |= PF_Decal; + if (gl_frontsector->numlights) { if (!(blendmode & PF_Masked)) - HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_TRANSLUCENT, NULL); + HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_TRANSLUCENT, NULL, blendmode); else - { - HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_CUTLEVEL, NULL); - } + HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_CUTLEVEL, NULL, blendmode); } else if (!(blendmode & PF_Masked)) HWR_AddTransparentWall(wallVerts, &Surf, gl_midtexture, blendmode, false, lightnum, colormap); @@ -1516,7 +1511,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { fixed_t texturevpeg; // PEGGING - if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_EFFECT2)) == (ML_DONTPEGBOTTOM|ML_EFFECT2)) + if ((gl_linedef->flags & (ML_DONTPEGBOTTOM|ML_NOSKEW)) == (ML_DONTPEGBOTTOM|ML_NOSKEW)) texturevpeg = gl_frontsector->floorheight + textureheight[gl_sidedef->midtexture] - gl_frontsector->ceilingheight + gl_sidedef->rowoffset; else if (gl_linedef->flags & ML_DONTPEGBOTTOM) texturevpeg = worldbottom + textureheight[gl_sidedef->midtexture] - worldtop + gl_sidedef->rowoffset; @@ -1532,7 +1527,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom wallVerts[2].s = wallVerts[1].s = cliphigh * grTex->scaleX; // Texture correction for slopes - if (gl_linedef->flags & ML_EFFECT2) { + if (gl_linedef->flags & ML_NOSKEW) { wallVerts[3].t += (gl_frontsector->ceilingheight - worldtop) * grTex->scaleY; wallVerts[2].t += (gl_frontsector->ceilingheight - worldtopslope) * grTex->scaleY; wallVerts[0].t += (gl_frontsector->floorheight - worldbottom) * grTex->scaleY; @@ -1554,7 +1549,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom // I don't think that solid walls can use translucent linedef types... if (gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_CUTLEVEL, NULL); + HWR_SplitWall(gl_frontsector, wallVerts, gl_midtexture, &Surf, FF_CUTLEVEL, NULL, 0); else { if (grTex->mipmap.flags & TF_TRANSPARENT) @@ -1589,14 +1584,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { ffloor_t * rover; fixed_t highcut = 0, lowcut = 0; + fixed_t lowcutslope, highcutslope; + + // Used for height comparisons and etc across FOFs and slopes + fixed_t high1, highslope1, low1, lowslope1; INT32 texnum; line_t * newline = NULL; // Multi-Property FOF - ///TODO add slope support (fixing cutoffs, proper wall clipping) - maybe just disable highcut/lowcut if either sector or FOF has a slope - /// to allow fun plane intersecting in OGL? But then people would abuse that and make software look bad. :C - highcut = gl_frontsector->ceilingheight < gl_backsector->ceilingheight ? gl_frontsector->ceilingheight : gl_backsector->ceilingheight; - lowcut = gl_frontsector->floorheight > gl_backsector->floorheight ? gl_frontsector->floorheight : gl_backsector->floorheight; + lowcut = max(worldbottom, worldlow); + highcut = min(worldtop, worldhigh); + lowcutslope = max(worldbottomslope, worldlowslope); + highcutslope = min(worldtopslope, worldhighslope); if (gl_backsector->ffloors) { @@ -1618,7 +1617,11 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom continue; if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES) continue; - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) + + SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) + SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) + + if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) continue; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture); @@ -1634,10 +1637,17 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom hS = P_GetFFloorTopZAt (rover, v2x, v2y); l = P_GetFFloorBottomZAt(rover, v1x, v1y); lS = P_GetFFloorBottomZAt(rover, v2x, v2y); - if (!(*rover->t_slope) && !gl_frontsector->c_slope && !gl_backsector->c_slope && h > highcut) - h = hS = highcut; - if (!(*rover->b_slope) && !gl_frontsector->f_slope && !gl_backsector->f_slope && l < lowcut) - l = lS = lowcut; + // Adjust the heights so the FOF does not overlap with top and bottom textures. + if (h >= highcut && hS >= highcutslope) + { + h = highcut; + hS = highcutslope; + } + if (l <= lowcut && lS <= lowcutslope) + { + l = lowcut; + lS = lowcutslope; + } //Hurdler: HW code starts here //FIXME: check if peging is correct // set top/bottom coords @@ -1666,13 +1676,13 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { texturevpeg = sides[newline->sidenum[0]].rowoffset; attachtobottom = !!(newline->flags & ML_DONTPEGBOTTOM); - slopeskew = !!(newline->flags & ML_DONTPEGTOP); + slopeskew = !!(newline->flags & ML_SKEWTD); } else { texturevpeg = sides[rover->master->sidenum[0]].rowoffset; attachtobottom = !!(gl_linedef->flags & ML_DONTPEGBOTTOM); - slopeskew = !!(rover->master->flags & ML_DONTPEGTOP); + slopeskew = !!(rover->master->flags & ML_SKEWTD); } grTex = HWR_GetTexture(texnum); @@ -1717,7 +1727,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); if (gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, 0, &Surf, rover->flags, rover); + HWR_SplitWall(gl_frontsector, wallVerts, 0, &Surf, rover->flags, rover, blendmode); else HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap); } @@ -1725,14 +1735,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { FBITFIELD blendmode = PF_Masked; - if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) + if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { - blendmode = PF_Translucent; + blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; } if (gl_frontsector->numlights) - HWR_SplitWall(gl_frontsector, wallVerts, texnum, &Surf, rover->flags, rover); + HWR_SplitWall(gl_frontsector, wallVerts, texnum, &Surf, rover->flags, rover, blendmode); else { if (blendmode != PF_Masked) @@ -1764,7 +1774,11 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom continue; if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) continue; - if (*rover->topheight < lowcut || *rover->bottomheight > highcut) + + SLOPEPARAMS(*rover->t_slope, high1, highslope1, *rover->topheight) + SLOPEPARAMS(*rover->b_slope, low1, lowslope1, *rover->bottomheight) + + if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope)) continue; texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture); @@ -1779,10 +1793,17 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom hS = P_GetFFloorTopZAt (rover, v2x, v2y); l = P_GetFFloorBottomZAt(rover, v1x, v1y); lS = P_GetFFloorBottomZAt(rover, v2x, v2y); - if (!(*rover->t_slope) && !gl_frontsector->c_slope && !gl_backsector->c_slope && h > highcut) - h = hS = highcut; - if (!(*rover->b_slope) && !gl_frontsector->f_slope && !gl_backsector->f_slope && l < lowcut) - l = lS = lowcut; + // Adjust the heights so the FOF does not overlap with top and bottom textures. + if (h >= highcut && hS >= highcutslope) + { + h = highcut; + hS = highcutslope; + } + if (l <= lowcut && lS <= lowcutslope) + { + l = lowcut; + lS = lowcutslope; + } //Hurdler: HW code starts here //FIXME: check if peging is correct // set top/bottom coords @@ -1829,7 +1850,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); if (gl_backsector->numlights) - HWR_SplitWall(gl_backsector, wallVerts, 0, &Surf, rover->flags, rover); + HWR_SplitWall(gl_backsector, wallVerts, 0, &Surf, rover->flags, rover, blendmode); else HWR_AddTransparentWall(wallVerts, &Surf, 0, blendmode, true, lightnum, colormap); } @@ -1837,14 +1858,14 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { FBITFIELD blendmode = PF_Masked; - if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) + if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { - blendmode = PF_Translucent; + blendmode = rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent; Surf.PolyColor.s.alpha = (UINT8)rover->alpha-1 > 255 ? 255 : rover->alpha-1; } if (gl_backsector->numlights) - HWR_SplitWall(gl_backsector, wallVerts, texnum, &Surf, rover->flags, rover); + HWR_SplitWall(gl_backsector, wallVerts, texnum, &Surf, rover->flags, rover, blendmode); else { if (blendmode != PF_Masked) @@ -1856,6 +1877,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom } } } +#undef SLOPEPARAMS //Hurdler: end of 3d-floors test } @@ -2659,30 +2681,30 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, FBITFIELD blendmode, UINT8 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap) { - float height; //constant y for all points on the convex flat polygon - FOutVector *v3d; - INT32 i; - float flatxref,flatyref; + FSurfaceInfo Surf; + FOutVector *v3d; + INT32 shader = SHADER_DEFAULT; + + size_t nrPlaneVerts = polysector->numVertices; + INT32 i; + + float height = FIXED_TO_FLOAT(fixedheight); // constant y for all points on the convex flat polygon + float flatxref, flatyref; float fflatwidth = 64.0f, fflatheight = 64.0f; INT32 flatflag = 63; + boolean texflat = false; + float scrollx = 0.0f, scrolly = 0.0f; angle_t angle = 0; - FSurfaceInfo Surf; fixed_t tempxs, tempyt; - size_t nrPlaneVerts; static FOutVector *planeVerts = NULL; static UINT16 numAllocedPlaneVerts = 0; - nrPlaneVerts = polysector->numVertices; - - height = FIXED_TO_FLOAT(fixedheight); - - if (nrPlaneVerts < 3) //not even a triangle ? + if (nrPlaneVerts < 3) // Not even a triangle? return; - - if (nrPlaneVerts > (size_t)UINT16_MAX) // FIXME: exceeds plVerts size + else if (nrPlaneVerts > (size_t)UINT16_MAX) // FIXME: exceeds plVerts size { CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX); return; @@ -2834,7 +2856,6 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, v3d->z = FIXED_TO_FLOAT(polysector->vertices[i]->y); } - HWR_Lighting(&Surf, lightlevel, planecolormap); if (blendmode & PF_Translucent) @@ -2845,7 +2866,13 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, else blendmode |= PF_Masked|PF_Modulated; - HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, SHADER_FLOOR, false); // floor shader + if (HWR_UseShader()) + { + shader = SHADER_FLOOR; + blendmode |= PF_ColorMapped; + } + + HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, shader, false); } static void HWR_AddPolyObjectPlanes(void) @@ -2915,6 +2942,13 @@ static void HWR_AddPolyObjectPlanes(void) } } +static FBITFIELD HWR_RippleBlend(sector_t *sector, ffloor_t *rover, boolean ceiling) +{ + (void)sector; + (void)ceiling; + return /*R_IsRipplePlane(sector, rover, ceiling)*/ (rover->flags & FF_RIPPLE) ? PF_Ripple : 0; +} + // -----------------+ // HWR_Subsector : Determine floor/ceiling planes. // : Add sprites of things in sector. @@ -3001,13 +3035,13 @@ static void HWR_Subsector(size_t num) } light = R_GetPlaneLight(gl_frontsector, locFloorHeight, false); - if (gl_frontsector->floorlightsec == -1) - floorlightlevel = *gl_frontsector->lightlist[light].lightlevel; + if (gl_frontsector->floorlightsec == -1 && !gl_frontsector->floorlightabsolute) + floorlightlevel = max(0, min(255, *gl_frontsector->lightlist[light].lightlevel + gl_frontsector->floorlightlevel)); floorcolormap = *gl_frontsector->lightlist[light].extra_colormap; light = R_GetPlaneLight(gl_frontsector, locCeilingHeight, false); - if (gl_frontsector->ceilinglightsec == -1) - ceilinglightlevel = *gl_frontsector->lightlist[light].lightlevel; + if (gl_frontsector->ceilinglightsec == -1 && !gl_frontsector->ceilinglightabsolute) + ceilinglightlevel = max(0, min(255, *gl_frontsector->lightlist[light].lightlevel + gl_frontsector->ceilinglightlevel)); ceilingcolormap = *gl_frontsector->lightlist[light].extra_colormap; } @@ -3105,7 +3139,7 @@ static void HWR_Subsector(size_t num) alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } - else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) // SoM: Flags are more efficient + else if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) // SoM: Flags are more efficient { light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); @@ -3114,14 +3148,15 @@ static void HWR_Subsector(size_t num) false, *rover->bottomheight, *gl_frontsector->lightlist[light].lightlevel, - rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, + rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, + HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), false, *gl_frontsector->lightlist[light].extra_colormap); } else { HWR_GetLevelFlat(&levelflats[*rover->bottompic]); light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); - HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic], + HWR_RenderPlane(sub, &extrasubsectors[num], false, *rover->bottomheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->bottompic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap); } } @@ -3150,7 +3185,7 @@ static void HWR_Subsector(size_t num) alpha, rover->master->frontsector, PF_Fog|PF_NoTexture, true, rover->master->frontsector->extra_colormap); } - else if (rover->flags & FF_TRANSLUCENT && rover->alpha < 256) + else if ((rover->flags & FF_TRANSLUCENT && rover->alpha < 256) || rover->blend) { light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); @@ -3159,14 +3194,15 @@ static void HWR_Subsector(size_t num) true, *rover->topheight, *gl_frontsector->lightlist[light].lightlevel, - rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Translucent, + rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, + HWR_RippleBlend(gl_frontsector, rover, false) | (rover->blend ? HWR_GetBlendModeFlag(rover->blend) : PF_Translucent), false, *gl_frontsector->lightlist[light].extra_colormap); } else { HWR_GetLevelFlat(&levelflats[*rover->toppic]); light = R_GetPlaneLight(gl_frontsector, centerHeight, dup_viewz < cullHeight ? true : false); - HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, (rover->flags & FF_RIPPLE ? PF_Ripple : 0)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic], + HWR_RenderPlane(sub, &extrasubsectors[num], true, *rover->topheight, HWR_RippleBlend(gl_frontsector, rover, false)|PF_Occlude, *gl_frontsector->lightlist[light].lightlevel, &levelflats[*rover->toppic], rover->master->frontsector, 255, *gl_frontsector->lightlist[light].extra_colormap); } } @@ -3190,7 +3226,7 @@ static void HWR_Subsector(size_t num) } // for render stats - ps_numpolyobjects += numpolys; + ps_numpolyobjects.value.i += numpolys; // Sort polyobjects R_SortPolyObjects(sub); @@ -3298,7 +3334,7 @@ static void HWR_RenderBSPNode(INT32 bspnum) // Decide which side the view point is on INT32 side; - ps_numbspcalls++; + ps_numbspcalls.value.i++; // Found a subsector? if (bspnum & NF_SUBSECTOR) @@ -3531,7 +3567,7 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v return false; cullplane = FIXED_TO_FLOAT(cullheight->frontsector->floorheight); - if (cullheight->flags & ML_NOCLIMB) // Group culling + if (cullheight->args[1]) // Group culling { if (!viewcullheight) return false; @@ -3566,7 +3602,10 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) FSurfaceInfo sSurf; float fscale; float fx; float fy; float offset; extracolormap_t *colormap = NULL; + FBITFIELD blendmode = PF_Translucent|PF_Modulated; + INT32 shader = SHADER_DEFAULT; UINT8 i; + INT32 heightsec, phs; SINT8 flip = P_MobjFlip(thing); INT32 light; @@ -3579,7 +3618,23 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) groundz = R_GetShadowZ(thing, &groundslope); - //if (abs(groundz - gl_viewz) / tz > 4) return; // Prevent stretchy shadows and possible crashes + heightsec = thing->subsector->sector->heightsec; + if (viewplayer->mo && viewplayer->mo->subsector) + phs = viewplayer->mo->subsector->sector->heightsec; + else + phs = -1; + + if (heightsec != -1 && phs != -1) // only clip things which are in special sectors + { + if (gl_viewz < FIXED_TO_FLOAT(sectors[phs].floorheight) ? + thing->z >= sectors[heightsec].floorheight : + thing->z < sectors[heightsec].floorheight) + return; + if (gl_viewz > FIXED_TO_FLOAT(sectors[phs].ceilingheight) ? + thing->z < sectors[heightsec].ceilingheight && gl_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) : + thing->z >= sectors[heightsec].ceilingheight) + return; + } floordiff = abs((flip < 0 ? thing->height : 0) + thing->z - groundz); @@ -3658,14 +3713,20 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) HWR_Lighting(&sSurf, 0, colormap); sSurf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated, SHADER_SPRITE, false); // sprite shader + if (HWR_UseShader()) + { + shader = SHADER_SPRITE; + blendmode |= PF_ColorMapped; + } + + HWR_ProcessPolygon(&sSurf, shadowVerts, 4, blendmode, shader, false); } // This is expecting a pointer to an array containing 4 wallVerts for a sprite static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts, const boolean precip) { if (cv_glspritebillboarding.value - && spr && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE) + && spr && spr->mobj && !R_ThingIsPaperSprite(spr->mobj) && wallVerts) { float basey = FIXED_TO_FLOAT(spr->mobj->z); @@ -3706,8 +3767,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) boolean lightset = true; FBITFIELD blend = 0; FBITFIELD occlusion; + INT32 shader = SHADER_DEFAULT; boolean use_linkdraw_hack = false; - boolean splat = R_ThingIsFloorSprite(spr->mobj); UINT8 alpha; INT32 i; @@ -3766,22 +3827,19 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) baseWallVerts[0].t = baseWallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; } - if (!splat) - { - // if it has a dispoffset, push it a little towards the camera - if (spr->dispoffset) { - float co = -gl_viewcos*(0.05f*spr->dispoffset); - float si = -gl_viewsin*(0.05f*spr->dispoffset); - baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si; - baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si; - baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co; - baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co; - } - - // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, baseWallVerts, false); + // if it has a dispoffset, push it a little towards the camera + if (spr->dispoffset) { + float co = -gl_viewcos*(0.05f*spr->dispoffset); + float si = -gl_viewsin*(0.05f*spr->dispoffset); + baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si; + baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si; + baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co; + baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co; } + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, baseWallVerts, false); + realtop = top = baseWallVerts[3].y; realbot = bot = baseWallVerts[0].y; ttop = baseWallVerts[3].t; @@ -3803,6 +3861,12 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) else occlusion = PF_Occlude; + INT32 blendmode; + if (spr->mobj->frame & FF_BLENDMASK) + blendmode = ((spr->mobj->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = spr->mobj->blendmode; + if (!cv_translucency.value) // translucency disabled { Surf.PolyColor.s.alpha = 0xFF; @@ -3812,14 +3876,12 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = HWR_GetBlendModeFlag(spr->mobj->blendmode); + blend = HWR_GetBlendModeFlag(blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) { INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; - if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) - return; - blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); + blend = HWR_SurfaceBlend(blendmode, trans, &Surf); } else { @@ -3828,10 +3890,16 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion; + blend = HWR_GetBlendModeFlag(blendmode)|occlusion; if (!occlusion) use_linkdraw_hack = true; } + if (HWR_UseShader()) + { + shader = SHADER_SPRITE; + blend |= PF_ColorMapped; + } + alpha = Surf.PolyColor.s.alpha; // Start with the lightlevel and colormap from the top of the sprite @@ -3862,6 +3930,9 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) } } + if (R_ThingIsSemiBright(spr->mobj)) + lightlevel = 128 + (lightlevel>>1); + for (i = 0; i < sector->numlights; i++) { if (endtop < endrealbot && top < realbot) @@ -3914,7 +3985,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // The x and y only need to be adjusted in the case that it's not a papersprite if (cv_glspritebillboarding.value - && spr->mobj && !(spr->mobj->frame & FF_PAPERSPRITE)) + && spr->mobj && !R_ThingIsPaperSprite(spr->mobj)) { // Get the x and z of the vertices so billboarding draws correctly realheight = realbot - realtop; @@ -3940,7 +4011,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -3969,7 +4040,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -3983,7 +4054,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) static void HWR_DrawSprite(gl_vissprite_t *spr) { FOutVector wallVerts[4]; - patch_t *gpatch; // sprite patch converted to hardware + patch_t *gpatch; FSurfaceInfo Surf; const boolean splat = R_ThingIsFloorSprite(spr->mobj); @@ -4141,6 +4212,11 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) wallVerts[1].z = wallVerts[2].z = spr->z2; } + // cache the patch in the graphics card memory + //12/12/99: Hurdler: same comment as above (for md2) + //Hurdler: 25/04/2000: now support colormap in hardware mode + HWR_GetMappedPatch(gpatch, spr->colormap); + if (spr->flip) { wallVerts[0].s = wallVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s; @@ -4160,11 +4236,6 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) wallVerts[0].t = wallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; } - // cache the patch in the graphics card memory - //12/12/99: Hurdler: same comment as above (for md2) - //Hurdler: 25/04/2000: now support colormap in hardware mode - HWR_GetMappedPatch(gpatch, spr->colormap); - if (!splat) { // if it has a dispoffset, push it a little towards the camera @@ -4215,10 +4286,14 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) else if (!lightset) lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; + if (R_ThingIsSemiBright(spr->mobj)) + lightlevel = 128 + (lightlevel>>1); + HWR_Lighting(&Surf, lightlevel, colormap); } { + INT32 shader = SHADER_DEFAULT; FBITFIELD blend = 0; FBITFIELD occlusion; boolean use_linkdraw_hack = false; @@ -4230,6 +4305,12 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) else occlusion = PF_Occlude; + INT32 blendmode; + if (spr->mobj->frame & FF_BLENDMASK) + blendmode = ((spr->mobj->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = spr->mobj->blendmode; + if (!cv_translucency.value) // translucency disabled { Surf.PolyColor.s.alpha = 0xFF; @@ -4239,14 +4320,12 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = HWR_GetBlendModeFlag(spr->mobj->blendmode); + blend = HWR_GetBlendModeFlag(blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) { INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; - if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) - return; - blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); + blend = HWR_SurfaceBlend(blendmode, trans, &Surf); } else { @@ -4255,7 +4334,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion; + blend = HWR_GetBlendModeFlag(blendmode)|occlusion; if (!occlusion) use_linkdraw_hack = true; } @@ -4271,7 +4350,13 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) if (!occlusion) use_linkdraw_hack = true; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader + if (HWR_UseShader()) + { + shader = SHADER_SPRITE; + blend |= PF_ColorMapped; + } + + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -4282,9 +4367,10 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Sprite drawer for precipitation static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) { + INT32 shader = SHADER_DEFAULT; FBITFIELD blend = 0; FOutVector wallVerts[4]; - patch_t *gpatch; // sprite patch converted to hardware + patch_t *gpatch; FSurfaceInfo Surf; if (!spr->mobj) @@ -4337,7 +4423,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) // Always use the light at the top instead of whatever I was doing before INT32 light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (!R_ThingIsFullBright(spr->mobj)) lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; if (*sector->lightlist[light].extra_colormap) @@ -4345,7 +4431,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) } else { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (!R_ThingIsFullBright(spr->mobj)) lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; if (sector->extra_colormap) @@ -4358,9 +4444,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) if (spr->mobj->frame & FF_TRANSMASK) { INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; - if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) - return; - blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); + blend = HWR_SurfaceBlend(AST_TRANSLUCENT, trans, &Surf); } else { @@ -4372,7 +4456,13 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|PF_Occlude; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader + if (HWR_UseShader()) + { + shader = SHADER_SPRITE; + blend |= PF_ColorMapped; + } + + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, shader, false); } #endif @@ -4654,7 +4744,7 @@ static void HWR_CreateDrawNodes(void) // that is already lying around. This should all be in some sort of linked list or lists. sortindex = Z_Calloc(sizeof(size_t) * (numplanes + numpolyplanes + numwalls), PU_STATIC, NULL); - ps_hw_nodesorttime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_nodesorttime); for (i = 0; i < numplanes; i++, p++) { @@ -4674,7 +4764,7 @@ static void HWR_CreateDrawNodes(void) sortindex[p] = p; } - ps_numdrawnodes = p; + ps_numdrawnodes.value.i = p; // p is the number of stuff to sort @@ -4709,9 +4799,9 @@ static void HWR_CreateDrawNodes(void) } } - ps_hw_nodesorttime = I_GetPreciseTime() - ps_hw_nodesorttime; + PS_STOP_TIMING(ps_hw_nodesorttime); - ps_hw_nodedrawtime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_nodedrawtime); // Okay! Let's draw it all! Woo! HWD.pfnSetTransform(&atransform); @@ -4748,7 +4838,7 @@ static void HWR_CreateDrawNodes(void) } } - ps_hw_nodedrawtime = I_GetPreciseTime() - ps_hw_nodedrawtime; + PS_STOP_TIMING(ps_hw_nodedrawtime); numwalls = 0; numplanes = 0; @@ -4921,8 +5011,8 @@ static void HWR_ProjectSprite(mobj_t *thing) angle_t ang; INT32 heightsec, phs; - const boolean papersprite = R_ThingIsPaperSprite(thing); const boolean splat = R_ThingIsFloorSprite(thing); + const boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat); angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle); float z1, z2; @@ -4939,6 +5029,19 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->spritexscale < 1 || thing->spriteyscale < 1) return; + INT32 blendmode; + if (thing->frame & FF_BLENDMASK) + blendmode = ((thing->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = thing->blendmode; + + // Visibility check by the blend mode. + if (thing->frame & FF_TRANSMASK) + { + if (!R_BlendLevelVisible(blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT)) + return; + } + dispoffset = thing->info->dispoffset; this_scale = FIXED_TO_FLOAT(thing->scale); @@ -5188,13 +5291,19 @@ static void HWR_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { + float top = gzt; + float bottom = FIXED_TO_FLOAT(thing->z); + + if (R_ThingIsFloorSprite(thing)) + top = bottom; + if (gl_viewz < FIXED_TO_FLOAT(sectors[phs].floorheight) ? - FIXED_TO_FLOAT(thing->z) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) : - gzt < FIXED_TO_FLOAT(sectors[heightsec].floorheight)) + bottom >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) : + top < FIXED_TO_FLOAT(sectors[heightsec].floorheight)) return; if (gl_viewz > FIXED_TO_FLOAT(sectors[phs].ceilingheight) ? - gzt < FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) && gl_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) : - FIXED_TO_FLOAT(thing->z) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight)) + top < FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) && gl_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) : + bottom >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight)) return; } @@ -5270,7 +5379,7 @@ static void HWR_ProjectSprite(mobj_t *thing) else if (vis->mobj->type == MT_METALSONIC_BATTLE) vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); else - vis->colormap = R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); + vis->colormap = R_GetTranslationColormap(TC_BOSS, vis->mobj->color, GTC_CACHE); } else if (thing->color) { @@ -5295,7 +5404,7 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->colormap = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color ? vis->mobj->color : SKINCOLOR_CYAN, GTC_CACHE); } else - vis->colormap = colormaps; + vis->colormap = NULL; // set top/bottom coords vis->gzt = gzt; @@ -5325,6 +5434,13 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) unsigned rot = 0; UINT8 flip; + // Visibility check by the blend mode. + if (thing->frame & FF_TRANSMASK) + { + if (!R_BlendLevelVisible(thing->blendmode, (thing->frame & FF_TRANSMASK)>>FF_TRANSSHIFT)) + return; + } + // transform the origin point tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx; tr_y = FIXED_TO_FLOAT(thing->y) - gl_viewy; @@ -5358,7 +5474,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) return; #endif - sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK]; + sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK]; // use single rotation for all views lumpoff = sprframe->lumpid[0]; @@ -5396,7 +5512,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->flip = flip; vis->mobj = (mobj_t *)thing; - vis->colormap = colormaps; + vis->colormap = NULL; // set top/bottom coords vis->gzt = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); @@ -5651,7 +5767,7 @@ static void HWR_DrawSkyBackground(player_t *player) dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); - v[0].s = v[3].s = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left + v[0].s = v[3].s = (-1.0f * angle) / (((float)ANGLE_90-1.0f)*dimensionmultiply); // left v[2].s = v[1].s = v[0].s + (1.0f/dimensionmultiply); // right (or left + 1.0f) // use +angle and -1.0f above instead if you wanted old backwards behavior @@ -6017,10 +6133,10 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) if (viewnumber == 0) // Only do it if it's the first screen being rendered HWD.pfnClearBuffer(true, false, &ClearColor); // Clear the Color Buffer, stops HOMs. Also seems to fix the skybox issue on Intel GPUs. - ps_hw_skyboxtime = I_GetPreciseTime(); + PS_START_TIMING(ps_hw_skyboxtime); if (skybox && drawsky) // If there's a skybox and we should be drawing the sky, draw the skybox HWR_RenderSkyboxView(viewnumber, player); // This is drawn before everything else so it is placed behind - ps_hw_skyboxtime = I_GetPreciseTime() - ps_hw_skyboxtime; + PS_STOP_TIMING(ps_hw_skyboxtime); { // do we really need to save player (is it not the same)? @@ -6130,9 +6246,9 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) // Reset the shader state. HWR_SetShaderState(); - ps_numbspcalls = 0; - ps_numpolyobjects = 0; - ps_bsptime = I_GetPreciseTime(); + ps_numbspcalls.value.i = 0; + ps_numpolyobjects.value.i = 0; + PS_START_TIMING(ps_bsptime); validcount++; @@ -6170,7 +6286,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) } #endif - ps_bsptime = I_GetPreciseTime() - ps_bsptime; + PS_STOP_TIMING(ps_bsptime); if (cv_glbatching.value) HWR_RenderBatches(); @@ -6185,22 +6301,22 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) #endif // Draw MD2 and sprites - ps_numsprites = gl_visspritecount; - ps_hw_spritesorttime = I_GetPreciseTime(); + ps_numsprites.value.i = gl_visspritecount; + PS_START_TIMING(ps_hw_spritesorttime); HWR_SortVisSprites(); - ps_hw_spritesorttime = I_GetPreciseTime() - ps_hw_spritesorttime; - ps_hw_spritedrawtime = I_GetPreciseTime(); + PS_STOP_TIMING(ps_hw_spritesorttime); + PS_START_TIMING(ps_hw_spritedrawtime); HWR_DrawSprites(); - ps_hw_spritedrawtime = I_GetPreciseTime() - ps_hw_spritedrawtime; + PS_STOP_TIMING(ps_hw_spritedrawtime); #ifdef NEWCORONAS //Hurdler: they must be drawn before translucent planes, what about gl fog? HWR_DrawCoronas(); #endif - ps_numdrawnodes = 0; - ps_hw_nodesorttime = 0; - ps_hw_nodedrawtime = 0; + ps_numdrawnodes.value.i = 0; + ps_hw_nodesorttime.value.p = 0; + ps_hw_nodedrawtime.value.p = 0; if (numplanes || numpolyplanes || numwalls) //Hurdler: render 3D water and transparent walls after everything { HWR_CreateDrawNodes(); @@ -6454,24 +6570,29 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, FBITFIELD blendmode = blend; UINT8 alpha = pSurf->PolyColor.s.alpha; // retain the alpha - int shader; + INT32 shader = SHADER_DEFAULT; // Lighting is done here instead so that fog isn't drawn incorrectly on transparent walls after sorting HWR_Lighting(pSurf, lightlevel, wallcolormap); pSurf->PolyColor.s.alpha = alpha; // put the alpha back after lighting - shader = SHADER_WALL; // wall shader - if (blend & PF_Environment) blendmode |= PF_Occlude; // PF_Occlude must be used for solid objects - if (fogwall) + if (HWR_UseShader()) { - blendmode |= PF_Fog; - shader = SHADER_FOG; // fog shader + if (fogwall) + shader = SHADER_FOG; + else + shader = SHADER_WALL; + + blendmode |= PF_ColorMapped; } + if (fogwall) + blendmode |= PF_Fog; + blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode, shader, false); } @@ -6514,7 +6635,7 @@ void HWR_DoPostProcessor(player_t *player) Surf.PolyColor.s.alpha = 0xc0; // match software mode - HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_AdditiveSource|PF_NoTexture|PF_NoDepthTest); + HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest); } // Capture the screen for intermission and screen waving @@ -6647,7 +6768,6 @@ void HWR_DrawScreenFinalTexture(int width, int height) HWD.pfnDrawScreenFinalTexture(width, height); } -// jimita 18032019 static inline UINT16 HWR_FindShaderDefs(UINT16 wadnum) { UINT16 i; @@ -6685,7 +6805,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 4ad09aa3d..cd822c0c1 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -20,6 +20,8 @@ #include "../d_player.h" #include "../r_defs.h" +#include "../m_perfstats.h" + // Startup & Shutdown the hardware mode renderer void HWR_Startup(void); void HWR_Switch(void); @@ -39,7 +41,7 @@ void HWR_InitTextureMapping(void); void HWR_SetViewSize(void); void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option); void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); -void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); +void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum); @@ -69,7 +71,7 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work UINT8 HWR_GetTranstableAlpha(INT32 transtablenum); -FBITFIELD HWR_GetBlendModeFlag(INT32 ast); +FBITFIELD HWR_GetBlendModeFlag(INT32 style); FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf); FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); @@ -116,22 +118,22 @@ extern FTransform atransform; // Render stats -extern precise_t ps_hw_skyboxtime; -extern precise_t ps_hw_nodesorttime; -extern precise_t ps_hw_nodedrawtime; -extern precise_t ps_hw_spritesorttime; -extern precise_t ps_hw_spritedrawtime; +extern ps_metric_t ps_hw_skyboxtime; +extern ps_metric_t ps_hw_nodesorttime; +extern ps_metric_t ps_hw_nodedrawtime; +extern ps_metric_t ps_hw_spritesorttime; +extern ps_metric_t ps_hw_spritedrawtime; // Render stats for batching -extern int ps_hw_numpolys; -extern int ps_hw_numverts; -extern int ps_hw_numcalls; -extern int ps_hw_numshaders; -extern int ps_hw_numtextures; -extern int ps_hw_numpolyflags; -extern int ps_hw_numcolors; -extern precise_t ps_hw_batchsorttime; -extern precise_t ps_hw_batchdrawtime; +extern ps_metric_t ps_hw_numpolys; +extern ps_metric_t ps_hw_numverts; +extern ps_metric_t ps_hw_numcalls; +extern ps_metric_t ps_hw_numshaders; +extern ps_metric_t ps_hw_numtextures; +extern ps_metric_t ps_hw_numpolyflags; +extern ps_metric_t ps_hw_numcolors; +extern ps_metric_t ps_hw_batchsorttime; +extern ps_metric_t ps_hw_batchdrawtime; extern boolean gl_init; extern boolean gl_maploaded; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 9c786e67e..a003163db 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -158,7 +158,7 @@ static GLTextureFormat_t PNG_Load(const char *filename, int *w, int *h, GLPatch_ jmp_buf jmpbuf; #endif #endif - png_FILE_p png_FILE; + volatile png_FILE_p png_FILE; //Filename checking fixed ~Monster Iestyn and Golden char *pngfilename = va("%s"PATHSEP"models"PATHSEP"%s", srb2home, filename); @@ -777,24 +777,7 @@ static void HWR_CreateBlendedTexture(patch_t *gpatch, patch_t *blendgpatch, GLMi while (size--) { - if (skinnum == TC_BOSS) - { - // Turn everything below a certain threshold white - if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue < 127) - { - // Lactozilla: Invert the colors - cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue); - } - else - { - cur->s.red = image->s.red; - cur->s.green = image->s.green; - cur->s.blue = image->s.blue; - } - - cur->s.alpha = image->s.alpha; - } - else if (skinnum == TC_ALLWHITE) + if (skinnum == TC_ALLWHITE) { // Turn everything white cur->s.red = cur->s.green = cur->s.blue = 255; @@ -1065,6 +1048,15 @@ skippixel: cur->s.alpha = image->s.alpha; } + else if (skinnum == TC_BOSS) + { + // Turn everything below a certain threshold white + if ((image->s.red == image->s.green) && (image->s.green == image->s.blue) && image->s.blue < 127) + { + // Lactozilla: Invert the colors + cur->s.red = cur->s.green = cur->s.blue = (255 - image->s.blue); + } + } } } @@ -1106,11 +1098,19 @@ static void HWR_GetBlendedTexture(patch_t *patch, patch_t *blendpatch, INT32 ski for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { grMipmap = grMipmap->nextcolormap; - if (grMipmap->colormap == colormap) + if (grMipmap->colormap && grMipmap->colormap->source == colormap) { if (grMipmap->downloaded && grMipmap->data) { - HWD.pfnSetTexture(grMipmap); // found the colormap, set it to the correct texture + if (memcmp(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8))) + { + M_Memcpy(grMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); + HWR_CreateBlendedTexture(patch, blendpatch, grMipmap, skinnum, color); + HWD.pfnUpdateTexture(grMipmap); + } + else + HWD.pfnSetTexture(grMipmap); // found the colormap, set it to the correct texture + Z_ChangeTag(grMipmap->data, PU_HWRMODELTEXTURE_UNLOCKED); return; } @@ -1128,7 +1128,10 @@ static void HWR_GetBlendedTexture(patch_t *patch, patch_t *blendpatch, INT32 ski if (newMipmap == NULL) I_Error("%s: Out of memory", "HWR_GetBlendedTexture"); grMipmap->nextcolormap = newMipmap; - newMipmap->colormap = colormap; + + newMipmap->colormap = Z_Calloc(sizeof(*newMipmap->colormap), PU_HWRPATCHCOLMIPMAP, NULL); + newMipmap->colormap->source = colormap; + M_Memcpy(newMipmap->colormap->data, colormap, 256 * sizeof(UINT8)); HWR_CreateBlendedTexture(patch, blendpatch, newMipmap, skinnum, color); @@ -1303,7 +1306,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; + else if (R_ThingIsSemiBright(spr->mobj)) + lightlevel = 128 + (*sector->lightlist[light].lightlevel>>1); + else if (!R_ThingIsFullBright(spr->mobj)) lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; if (*sector->lightlist[light].extra_colormap) @@ -1311,7 +1318,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } else { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; + else if (R_ThingIsSemiBright(spr->mobj)) + lightlevel = 128 + (sector->lightlevel>>1); + else if (!R_ThingIsFullBright(spr->mobj)) lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; if (sector->extra_colormap) @@ -1329,10 +1340,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL; INT32 durs = spr->mobj->state->tics; INT32 tics = spr->mobj->tics; - //mdlframe_t *next = NULL; - const boolean papersprite = (spr->mobj->frame & FF_PAPERSPRITE); - const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP)); - const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !(spr->mobj->frame & FF_HORIZONTALFLIP)); + const boolean papersprite = (R_ThingIsPaperSprite(spr->mobj) && !R_ThingIsFloorSprite(spr->mobj)); + const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj)); + const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj)); spritedef_t *sprdef; spriteframe_t *sprframe; spriteinfo_t *sprinfo; @@ -1344,12 +1354,18 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) //if (tics > durs) //durs = tics; + INT32 blendmode; + if (spr->mobj->frame & FF_BLENDMASK) + blendmode = ((spr->mobj->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = spr->mobj->blendmode; + if (spr->mobj->frame & FF_TRANSMASK) - Surf.PolyFlags = HWR_SurfaceBlend(spr->mobj->blendmode, (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + Surf.PolyFlags = HWR_SurfaceBlend(blendmode, (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else { Surf.PolyColor.s.alpha = (spr->mobj->flags2 & MF2_SHADOW) ? 0x40 : 0xff; - Surf.PolyFlags = HWR_GetBlendModeFlag(spr->mobj->blendmode); + Surf.PolyFlags = HWR_GetBlendModeFlag(blendmode); } // don't forget to enable the depth test because we can't do this @@ -1394,6 +1410,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) || ((!hwrBlendPatch->mipmap->format || !hwrBlendPatch->mipmap->downloaded) && !md2->noblendfile))) md2_loadBlendTexture(md2); + // Load it again, because it isn't being loaded into blendgpatch after md2_loadblendtexture... + blendgpatch = md2->blendgrpatch; + if (blendgpatch) + hwrBlendPatch = ((GLPatch_t *)blendgpatch->hardware); + if (md2->error) return false; // we already failed loading this before :( if (!md2->model) @@ -1518,7 +1539,12 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { nextFrame = (spr->mobj->frame & FF_FRAMEMASK) + 1; if (nextFrame >= mod) - nextFrame = 0; + { + if (spr->mobj->state->frame & FF_SPR2ENDSTATE) + nextFrame--; + else + nextFrame = 0; + } if (frame || !(spr->mobj->state->frame & FF_SPR2ENDSTATE)) nextFrame = md2->model->spr2frames[spr2].frames[nextFrame]; else diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 0f4d2c7bc..966ed016b 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 8cd948eea..7ec7ee270 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 1998-2020 by Sonic Team Junior. +// Copyright (C) 1998-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -58,8 +58,12 @@ static GLuint tex_downloaded = 0; static GLfloat fov = 90.0f; static FBITFIELD CurrentPolyFlags; -static FTextureInfo *gl_cachetail = NULL; -static FTextureInfo *gl_cachehead = NULL; +// Linked list of all textures. +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() @@ -130,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 @@ -158,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, ...) @@ -183,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, ...) @@ -909,7 +908,6 @@ void SetupGLFunc4(void) pgluBuild2DMipmaps = GetGLFunc("gluBuild2DMipmaps"); } -// jimita EXPORT boolean HWRAPI(CompileShaders) (void) { #ifdef GL_SHADERS @@ -961,8 +959,6 @@ EXPORT boolean HWRAPI(CompileShaders) (void) } } - SetShader(SHADER_DEFAULT); - return true; #else return false; @@ -1287,10 +1283,34 @@ void SetStates(void) // -----------------+ // DeleteTexture : Deletes a texture from the GPU and frees its data // -----------------+ -EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *pTexInfo) +EXPORT void HWRAPI(DeleteTexture) (GLMipmap_t *pTexInfo) { - if (pTexInfo->downloaded) + FTextureInfo *head = TexCacheHead; + + if (!pTexInfo) + return; + else if (pTexInfo->downloaded) pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded); + + while (head) + { + if (head->downloaded == pTexInfo->downloaded) + { + if (head->next) + head->next->prev = head->prev; + else // no next -> tail is being deleted -> update TexCacheTail + TexCacheTail = head->prev; + if (head->prev) + head->prev->next = head->next; + else // no prev -> head is being deleted -> update TexCacheHead + TexCacheHead = head->next; + free(head); + break; + } + + head = head->next; + } + pTexInfo->downloaded = 0; } @@ -1303,23 +1323,30 @@ void Flush(void) { //GL_DBG_Printf ("HWR_Flush()\n"); - while (gl_cachehead) + while (TexCacheHead) { - DeleteTexture(gl_cachehead); - gl_cachehead = gl_cachehead->nextmipmap; + FTextureInfo *pTexInfo = TexCacheHead; + GLMipmap_t *texture = pTexInfo->texture; + + if (pTexInfo->downloaded) + { + pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded); + pTexInfo->downloaded = 0; + } + + if (texture) + texture->downloaded = 0; + + TexCacheHead = pTexInfo->next; + free(pTexInfo); } - ClearCacheList(); //Hurdler: well, gl_cachehead is already NULL + TexCacheTail = TexCacheHead = NULL; //Hurdler: well, TexCacheHead is already NULL tex_downloaded = 0; -} - -// -----------------+ -// ClearCacheList : Clears the texture cache tail and head -// -----------------+ -EXPORT void HWRAPI(ClearCacheList) (void) -{ - gl_cachetail = gl_cachehead = NULL; + free(textureBuffer); + textureBuffer = NULL; + textureBufferSize = 0; } @@ -1353,7 +1380,6 @@ INT32 isExtAvailable(const char *extension, const GLubyte *start) // -----------------+ // Init : Initialise the OpenGL interface API -// Returns : // -----------------+ EXPORT boolean HWRAPI(Init) (void) { @@ -1554,12 +1580,11 @@ static void SetBlendMode(FBITFIELD flags) case PF_Additive & PF_Blending: case PF_Subtractive & PF_Blending: case PF_ReverseSubtract & PF_Blending: + pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest + break; case PF_Environment & PF_Blending: pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break; - case PF_AdditiveSource & PF_Blending: - pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest - break; case PF_Multiplicative & PF_Blending: pglBlendFunc(GL_DST_COLOR, GL_ZERO); break; @@ -1598,7 +1623,6 @@ static void SetBlendMode(FBITFIELD flags) break; case PF_Translucent & PF_Blending: case PF_Additive & PF_Blending: - case PF_AdditiveSource & PF_Blending: case PF_Subtractive & PF_Blending: case PF_ReverseSubtract & PF_Blending: case PF_Environment & PF_Blending: @@ -1715,37 +1739,48 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) CurrentPolyFlags = PolyFlags; } -// -----------------+ -// UpdateTexture : Updates the texture data. -// -----------------+ -EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *pTexInfo) +static void AllocTextureBuffer(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; - - if (!pTexInfo->downloaded) + size_t size = pTexInfo->width * pTexInfo->height; + if (size > textureBufferSize) { - pglGenTextures(1, &texnum); - pTexInfo->downloaded = texnum; - updatemipmap = false; + 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; } - else - texnum = pTexInfo->downloaded; +} - //GL_DBG_Printf ("DownloadMipmap %d %x\n",(INT32)texnum,pTexInfo->data); +// -----------------+ +// UpdateTexture : Updates texture data. +// -----------------+ +EXPORT void HWRAPI(UpdateTexture) (GLMipmap_t *pTexInfo) +{ + // Upload a texture + GLuint num = pTexInfo->downloaded; + boolean update = true; - w = pTexInfo->width; - h = pTexInfo->height; + INT32 w = pTexInfo->width, h = pTexInfo->height; + INT32 i, j; - if ((pTexInfo->format == GL_TEXFMT_P_8) || - (pTexInfo->format == GL_TEXFMT_AP_88)) + const GLubyte *pImgData = (const GLubyte *)pTexInfo->data; + const GLvoid *ptex = NULL; + RGBA_t *tex = NULL; + + // Generate a new texture name. + if (!num) { - const GLubyte *pImgData = (const GLubyte *)pTexInfo->data; - INT32 i, j; + pglGenTextures(1, &num); + pTexInfo->downloaded = num; + update = false; + } + + //GL_DBG_Printf("UpdateTexture %d %x\n", (INT32)num, pImgData); + + if ((pTexInfo->format == GL_TEXFMT_P_8) || (pTexInfo->format == GL_TEXFMT_AP_88)) + { + AllocTextureBuffer(pTexInfo); + ptex = tex = textureBuffer; for (j = 0; j < h; j++) { @@ -1776,20 +1811,18 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *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++) { @@ -1806,8 +1839,8 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *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++) { @@ -1822,11 +1855,10 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *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) @@ -1855,7 +1887,7 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *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); @@ -1876,7 +1908,7 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *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); @@ -1896,7 +1928,7 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *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); @@ -1920,7 +1952,7 @@ EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *pTexInfo) // -----------------+ // SetTexture : The mipmap becomes the current texture source // -----------------+ -EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) +EXPORT void HWRAPI(SetTexture) (GLMipmap_t *pTexInfo) { if (!pTexInfo) { @@ -1937,17 +1969,25 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } else { + FTextureInfo *newTex = calloc(1, sizeof (*newTex)); + UpdateTexture(pTexInfo); - pTexInfo->nextmipmap = NULL; + + newTex->texture = pTexInfo; + newTex->downloaded = (UINT32)pTexInfo->downloaded; + newTex->width = (UINT32)pTexInfo->width; + newTex->height = (UINT32)pTexInfo->height; + newTex->format = (UINT32)pTexInfo->format; // insertion at the tail - if (gl_cachetail) + if (TexCacheTail) { - gl_cachetail->nextmipmap = pTexInfo; - gl_cachetail = pTexInfo; + newTex->prev = TexCacheTail; + TexCacheTail->next = newTex; + TexCacheTail = newTex; } else // initialization of the linked list - gl_cachetail = gl_cachehead = pTexInfo; + TexCacheTail = TexCacheHead = newTex; } } @@ -2144,32 +2184,34 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD SetBlend(PolyFlags); //TODO: inline (#pragma..) - // PolyColor if (pSurf) { - // If Modulated, mix the surface colour to the texture + // If modulated, mix the surface colour to the texture if (CurrentPolyFlags & PF_Modulated) - { - // Poly color - poly.red = byte2float[pSurf->PolyColor.s.red]; - poly.green = byte2float[pSurf->PolyColor.s.green]; - poly.blue = byte2float[pSurf->PolyColor.s.blue]; - poly.alpha = byte2float[pSurf->PolyColor.s.alpha]; - pglColor4ubv((GLubyte*)&pSurf->PolyColor.s); + + // If the surface is either modulated or colormapped, or both + if (CurrentPolyFlags & (PF_Modulated | PF_ColorMapped)) + { + poly.red = byte2float[pSurf->PolyColor.s.red]; + poly.green = byte2float[pSurf->PolyColor.s.green]; + poly.blue = byte2float[pSurf->PolyColor.s.blue]; + poly.alpha = byte2float[pSurf->PolyColor.s.alpha]; } - // Tint color - tint.red = byte2float[pSurf->TintColor.s.red]; - tint.green = byte2float[pSurf->TintColor.s.green]; - tint.blue = byte2float[pSurf->TintColor.s.blue]; - tint.alpha = byte2float[pSurf->TintColor.s.alpha]; + // Only if the surface is colormapped + if (CurrentPolyFlags & PF_ColorMapped) + { + tint.red = byte2float[pSurf->TintColor.s.red]; + tint.green = byte2float[pSurf->TintColor.s.green]; + tint.blue = byte2float[pSurf->TintColor.s.blue]; + tint.alpha = byte2float[pSurf->TintColor.s.alpha]; - // Fade color - fade.red = byte2float[pSurf->FadeColor.s.red]; - fade.green = byte2float[pSurf->FadeColor.s.green]; - fade.blue = byte2float[pSurf->FadeColor.s.blue]; - fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; + fade.red = byte2float[pSurf->FadeColor.s.red]; + fade.green = byte2float[pSurf->FadeColor.s.green]; + fade.blue = byte2float[pSurf->FadeColor.s.blue]; + fade.alpha = byte2float[pSurf->FadeColor.s.alpha]; + } } // this test is added for new coronas' code (without depth buffer) @@ -2722,7 +2764,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 fade.alpha = byte2float[Surface->FadeColor.s.alpha]; flags = (Surface->PolyFlags | PF_Modulated); - if (Surface->PolyFlags & (PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative)) + if (Surface->PolyFlags & (PF_Additive|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative)) flags |= PF_Occlude; else if (Surface->PolyColor.s.alpha == 0xFF) flags |= (PF_Occlude | PF_Masked); @@ -2983,7 +3025,6 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); - // jimita 14042019 // Simulate Software's y-shearing // https://zdoom.org/wiki/Y-shearing if (shearing) @@ -3011,7 +3052,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) EXPORT INT32 HWRAPI(GetTextureUsed) (void) { - FTextureInfo *tmp = gl_cachehead; + FTextureInfo *tmp = TexCacheHead; INT32 res = 0; while (tmp) @@ -3028,7 +3069,7 @@ EXPORT INT32 HWRAPI(GetTextureUsed) (void) // Add it up! res += tmp->height*tmp->width*bpp; - tmp = tmp->nextmipmap; + tmp = tmp->next; } return res; diff --git a/src/http-mserv.c b/src/http-mserv.c index 7c7d04495..b0ef37fa1 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by James R. +// Copyright (C) 2020-2022 by James R. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 7e9144f98..5d893a551 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -76,7 +76,7 @@ patch_t *nto_font[NT_FONTSIZE]; static player_t *plr; boolean chat_on; // entering a chat message? -static char w_chat[HU_MAXMSGLEN]; +static char w_chat[HU_MAXMSGLEN + 1]; static size_t c_input = 0; // let's try to make the chat input less shitty. static boolean headsupactive = false; boolean hu_showscores; // draw rankings @@ -98,6 +98,7 @@ patch_t *emeraldpics[3][8]; // 0 = normal, 1 = tiny, 2 = coinbox static patch_t *emblemicon; patch_t *tokenicon; static patch_t *exiticon; +static patch_t *nopingicon; //------------------------------------------- // misc vars @@ -286,6 +287,7 @@ void HU_LoadGraphics(void) emblemicon = W_CachePatchName("EMBLICON", PU_HUDGFX); tokenicon = W_CachePatchName("TOKNICON", PU_HUDGFX); exiticon = W_CachePatchName("EXITICON", PU_HUDGFX); + nopingicon = W_CachePatchName("NOPINGICON", PU_HUDGFX); emeraldpics[0][0] = W_CachePatchName("CHAOS1", PU_HUDGFX); emeraldpics[0][1] = W_CachePatchName("CHAOS2", PU_HUDGFX); @@ -459,7 +461,7 @@ void HU_AddChatText(const char *text, boolean playsound) static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) { - char buf[254]; + char buf[2 + HU_MAXMSGLEN + 1]; size_t numwords, ix; char *msg = &buf[2]; const size_t msgspace = sizeof buf - 2; @@ -535,7 +537,7 @@ static void DoSayCommand(SINT8 target, size_t usedargs, UINT8 flags) } buf[0] = target; newmsg = msg+5+spc; - strlcpy(msg, newmsg, 252); + strlcpy(msg, newmsg, HU_MAXMSGLEN + 1); } SendNetXCmd(XD_SAY, buf, strlen(msg) + 1 + msg-buf); @@ -642,7 +644,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) target = READSINT8(*p); flags = READUINT8(*p); msg = (char *)*p; - SKIPSTRING(*p); + SKIPSTRINGL(*p, HU_MAXMSGLEN + 1); if ((cv_mute.value || flags & (HU_CSAY|HU_SERVER_SAY)) && playernum != serverplayer && !(IsPlayerAdmin(playernum))) { @@ -684,7 +686,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) // run the lua hook even if we were supposed to eat the msg, netgame consistency goes first. - if (LUAh_PlayerMsg(playernum, target, flags, msg)) + if (LUA_HookPlayerMsg(playernum, target, flags, msg)) return; if (spam_eatmsg) @@ -856,72 +858,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) #endif } -// Handles key input and string input -// -static inline boolean HU_keyInChatString(char *s, char ch) -{ - size_t l; - - if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && hu_font[ch-HU_FONTSTART]) - || ch == ' ') // Allow spaces, of course - { - l = strlen(s); - if (l < HU_MAXMSGLEN - 1) - { - if (c_input >= strlen(s)) // don't do anything complicated - { - s[l++] = ch; - s[l]=0; - } - else - { - - // move everything past c_input for new characters: - size_t m = HU_MAXMSGLEN-1; - while (m>=c_input) - { - if (s[m]) - s[m+1] = (s[m]); - if (m == 0) // prevent overflow - break; - m--; - } - s[c_input] = ch; // and replace this. - } - c_input++; - return true; - } - return false; - } - else if (ch == KEY_BACKSPACE) - { - size_t i = c_input; - - if (c_input <= 0) - return false; - - if (!s[i-1]) - return false; - - if (i >= strlen(s)-1) - { - s[strlen(s)-1] = 0; - c_input--; - return false; - } - - for (; (i < HU_MAXMSGLEN); i++) - { - s[i-1] = s[i]; - } - c_input--; - } - else if (ch != KEY_ENTER) - return false; // did not eat key - - return true; // ate the key -} - #endif // @@ -934,7 +870,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; @@ -943,151 +879,123 @@ void HU_Ticker(void) #ifndef NONET static boolean teamtalk = false; +static boolean justscrolleddown; +static boolean justscrolledup; +static INT16 typelines = 1; // number of drawfill lines we need when drawing the chat. it's some weird hack and might be one frame off but I'm lazy to make another loop. +// It's up here since it has to be reset when we open the chat. -// Clear spaces so we don't end up with messages only made out of emptiness -static boolean HU_clearChatSpaces(void) +static boolean HU_chatboxContainsOnlySpaces(void) { - size_t i = 0; // Used to just check our message - char c; // current character we're iterating. - boolean nothingbutspaces = true; + size_t i; - for (; i < strlen(w_chat); i++) // iterate through message and eradicate all spaces that don't belong. - { - c = w_chat[i]; - if (!c) - break; // if there's nothing, it's safe to assume our message has ended, so let's not waste any more time here. + for (i = 0; w_chat[i]; i++) + if (w_chat[i] != ' ') + return false; - if (c != ' ') // Isn't a space - { - nothingbutspaces = false; - } - } - return nothingbutspaces; + return true; } -// -// -static void HU_queueChatChar(char c) +static void HU_sendChatMessage(void) { - // send automaticly the message (no more chat char) - if (c == KEY_ENTER) + char buf[2 + HU_MAXMSGLEN + 1]; + char *msg = &buf[2]; + size_t ci; + INT32 target = 0; + + // if our message was nothing but spaces, don't send it. + if (HU_chatboxContainsOnlySpaces()) + return; + + // copy printable characters and terminating '\0' only. + for (ci = 2; w_chat[ci-2]; ci++) { - char buf[2+256]; - char *msg = &buf[2]; - size_t i = 0; - size_t ci = 2; - INT32 target = 0; + char c = w_chat[ci-2]; + if (c >= ' ' && !(c & 0x80)) + buf[ci] = c; + }; + buf[ci] = '\0'; - if (HU_clearChatSpaces()) // Avoids being able to send empty messages, or something. - return; // If this returns true, that means our message was NOTHING but spaces, so don't send it period. + memset(w_chat, '\0', sizeof(w_chat)); + c_input = 0; - do { - c = w_chat[-2+ci++]; - if (!c || (c >= ' ' && !(c & 0x80))) // copy printable characters and terminating '\0' only. - buf[ci-1]=c; - } while (c); + // last minute mute check + if (CHAT_MUTE) + { + HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); + return; + } - for (;(i 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm + { + INT32 spc = 1; // used if playernum[1] is a space. + char playernum[3]; + const char *newmsg; - c_input = 0; + // what we're gonna do now is check if the player exists + // with that logic, characters 4 and 5 are our numbers: - // last minute mute check - if (CHAT_MUTE) + // teamtalk can't send PMs, just don't send it, else everyone would be able to see it, and no one wants to see your sex RP sicko. + if (teamtalk) { - HU_AddChatText(va("%s>ERROR: The chat is muted. You can't say anything.", "\x85"), false); + HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85"), false); return; } - if (strlen(msg) > 4 && strnicmp(msg, "/pm", 3) == 0) // used /pm + strncpy(playernum, msg+3, 3); + // check for undesirable characters in our "number" + if (!(isdigit(playernum[0]) && isdigit(playernum[1]))) { - INT32 spc = 1; // used if playernum[1] is a space. - char playernum[3]; - const char *newmsg; - - // what we're gonna do now is check if the player exists - // with that logic, characters 4 and 5 are our numbers: - - // teamtalk can't send PMs, just don't send it, else everyone would be able to see it, and no one wants to see your sex RP sicko. - if (teamtalk) - { - HU_AddChatText(va("%sCannot send sayto in Say-Team.", "\x85"), false); - return; - } - - strncpy(playernum, msg+3, 3); - // check for undesirable characters in our "number" - if (((playernum[0] < '0') || (playernum[0] > '9')) || ((playernum[1] < '0') || (playernum[1] > '9'))) - { - // check if playernum[1] is a space - if (playernum[1] == ' ') - spc = 0; - // let it slide - else - { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); - return; - } - } - // I'm very bad at C, I swear I am, additional checks eww! - if (spc != 0) - { - if (msg[5] != ' ') - { - HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); - return; - } - } - - target = atoi(playernum); // turn that into a number - //CONS_Printf("%d\n", target); - - // check for target player, if it doesn't exist then we can't send the message! - if (target < MAXPLAYERS && playeringame[target]) // player exists - target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! + // check if playernum[1] is a space + if (playernum[1] == ' ') + spc = 0; + // let it slide else { - HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); return; } - - // we need to get rid of the /pm - newmsg = msg+5+spc; - strlcpy(msg, newmsg, 255); } - if (ci > 3) // don't send target+flags+empty message. + // I'm very bad at C, I swear I am, additional checks eww! + if (spc != 0 && msg[5] != ' ') { - if (teamtalk) - buf[0] = -1; // target - else - buf[0] = target; - - buf[1] = 0; // flags - SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); + HU_AddChatText("\x82NOTICE: \x80Invalid command format. Correct format is \'/pm \'.", false); + return; } - return; + + target = atoi(playernum); // turn that into a number + + // check for target player, if it doesn't exist then we can't send the message! + if (target < MAXPLAYERS && playeringame[target]) // player exists + target++; // even though playernums are from 0 to 31, target is 1 to 32, so up that by 1 to have it work! + else + { + HU_AddChatText(va("\x82NOTICE: \x80Player %d does not exist.", target), false); // same + return; + } + + // we need to get rid of the /pm + newmsg = msg+5+spc; + strlcpy(msg, newmsg, HU_MAXMSGLEN + 1); + } + if (ci > 2) // don't send target+flags+empty message. + { + buf[0] = teamtalk ? -1 : target; // target + buf[1] = 0; // flags + SendNetXCmd(XD_SAY, buf, 2 + strlen(&buf[2]) + 1); } } + #endif void HU_clearChatChars(void) { - size_t i = 0; - for (;idata1 >= 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; @@ -1138,7 +1046,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; @@ -1155,12 +1063,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 @@ -1169,21 +1077,23 @@ boolean HU_Responder(event_t *ev) if (shiftdown ^ capslock) c = shiftxform[c]; } - else // if we're holding shift we should still shift non letter symbols + else // if we're holding shift we should still shift non letter symbols { if (shiftdown) c = shiftxform[c]; } // pasting. pasting is cool. chat is a bit limited, though :( - if (((c == 'v' || c == 'V') && ctrldown) && !CHAT_MUTE) + if ((c == 'v' || c == 'V') && ctrldown) { - const char *paste = I_ClipboardPaste(); + const char *paste; size_t chatlen; size_t pastelen; - // create a dummy string real quickly + if (CHAT_MUTE) + return true; + paste = I_ClipboardPaste(); if (paste == NULL) return true; @@ -1192,48 +1102,24 @@ boolean HU_Responder(event_t *ev) if (chatlen+pastelen > HU_MAXMSGLEN) return true; // we can't paste this!! - if (c_input >= strlen(w_chat)) // add it at the end of the string. - { - memcpy(&w_chat[chatlen], paste, pastelen); // copy all of that. - c_input += pastelen; - /*size_t i = 0; - for (;i= c_input) - { - if (w_chat[i]) - w_chat[i+pastelen] = w_chat[i]; - if (i == 0) // prevent overflow - break; - i--; - } - memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. - c_input += pastelen; - return true; - } + memmove(&w_chat[c_input + pastelen], &w_chat[c_input], pastelen); + memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. + c_input += pastelen; + return true; } + else if (c == KEY_ENTER) + { + if (!CHAT_MUTE) + HU_sendChatMessage(); - if (!CHAT_MUTE && HU_keyInChatString(w_chat,c)) - { - HU_queueChatChar(c); - } - if (c == KEY_ENTER) - { chat_on = false; c_input = 0; // reset input cursor chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :) 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; @@ -1266,6 +1152,32 @@ boolean HU_Responder(event_t *ev) else c_input++; } + else if ((c >= HU_FONTSTART && c <= HU_FONTEND && hu_font[c-HU_FONTSTART]) + || c == ' ') // Allow spaces, of course + { + if (CHAT_MUTE || strlen(w_chat) >= HU_MAXMSGLEN) + return true; + + memmove(&w_chat[c_input + 1], &w_chat[c_input], strlen(w_chat) - c_input + 1); + w_chat[c_input] = c; + c_input++; + } + else if (c == KEY_BACKSPACE) + { + if (CHAT_MUTE || c_input <= 0) + return true; + + memmove(&w_chat[c_input - 1], &w_chat[c_input], strlen(w_chat) - c_input + 1); + c_input--; + } + else if (c == KEY_DEL) + { + if (CHAT_MUTE || c_input >= strlen(w_chat)) + return true; + + memmove(&w_chat[c_input], &w_chat[c_input + 1], strlen(w_chat) - c_input); + } + return true; } #endif @@ -1861,60 +1773,25 @@ static void HU_DrawChat_Old(void) } #endif -// draw the Crosshair, at the exact center of the view. -// +// Draw crosshairs at the exact center of the view. +// In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them. // Crosshairs are pre-cached at HU_Init -static inline void HU_DrawCrosshair(void) +static inline void HU_DrawCrosshairs(void) { - INT32 i, y; + INT32 cross1 = cv_crosshair.value & 3; + INT32 cross2 = cv_crosshair2.value & 3; - i = cv_crosshair.value & 3; - if (!i) + if (automapactive || demoplayback) return; - if ((netgame || multiplayer) && players[displayplayer].spectator) - return; + stplyr = ((stplyr == &players[displayplayer]) ? &players[secondarydisplayplayer] : &players[displayplayer]); + if (!players[displayplayer].spectator && (!camera.chase || ticcmd_ztargetfocus[0]) && cross1) + V_DrawStretchyFixedPatch((BASEVIDWIDTH/2)<>1); - - V_DrawScaledPatch(vid.width>>1, y, V_NOSCALESTART|V_OFFSET|V_TRANSLUCENT, crosshair[i - 1]); -} - -static inline void HU_DrawCrosshair2(void) -{ - INT32 i, y; - - i = cv_crosshair2.value & 3; - if (!i) - return; - - if ((netgame || multiplayer) && players[secondarydisplayplayer].spectator) - return; - -#ifdef HWRENDER - if (rendermode != render_soft) - y = (INT32)gl_basewindowcentery; - else -#endif - y = viewwindowy + (viewheight>>1); - - if (splitscreen) - { -#ifdef HWRENDER - if (rendermode != render_soft) - y += (INT32)gl_viewheight; - else -#endif - y += viewheight; - - V_DrawScaledPatch(vid.width>>1, y, V_NOSCALESTART|V_OFFSET|V_TRANSLUCENT, crosshair[i - 1]); - } + stplyr = ((stplyr == &players[displayplayer]) ? &players[secondarydisplayplayer] : &players[displayplayer]); + if (!players[secondarydisplayplayer].spectator && (!camera2.chase || ticcmd_ztargetfocus[1]) && cross2 && splitscreen) + V_DrawStretchyFixedPatch((BASEVIDWIDTH/2)<= 640) // how sad, we're using a shit resolution. + if (ping < UINT32_MAX && (!notext || vid.width >= 640)) // how sad, we're using a shit resolution. V_DrawSmallString(dx, y+4, V_ALLOWLOWERCASE|flags, va("%dms", ping)); for (i=0; (i<3); i++) // Draw the ping bar @@ -2272,6 +2147,9 @@ void HU_drawPing(INT32 x, INT32 y, UINT32 ping, boolean notext, INT32 flags) yoffset -= 2; } + + if (ping == UINT32_MAX) + V_DrawSmallScaledPatch(x + 4 - nopingicon->width/2, y + 9 - nopingicon->height/2, 0, nopingicon); } // @@ -2298,16 +2176,17 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I if (!splitscreen) // don't draw it on splitscreen, { - if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) - HU_drawPing(x+ 253, y, playerpingtable[tab[i].num], false, 0); + if (tab[i].num != serverplayer) + HU_drawPing(x + 253, y, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], false, 0); //else // V_DrawSmallString(x+ 246, y+4, V_YELLOWMAP, "SERVER"); } - V_DrawString(x + 20, y, - ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | (greycheck ? V_60TRANS : 0) - | V_ALLOWLOWERCASE, tab[i].name); + if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1)) + V_DrawString(x + 20, y, + ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) + | (greycheck ? V_60TRANS : 0) + | V_ALLOWLOWERCASE, tab[i].name); // Draw emeralds if (players[tab[i].num].powers[pw_invulnerability] && (players[tab[i].num].powers[pw_invulnerability] == players[tab[i].num].powers[pw_sneakers]) && ((leveltime/7) & 1)) @@ -2455,10 +2334,11 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) supercheck = supercheckdef; strlcpy(name, tab[i].name, 8); - V_DrawString(x + 10, y, - ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | (greycheck ? 0 : V_TRANSLUCENT) - | V_ALLOWLOWERCASE, name); + if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1)) + V_DrawString(x + 10, y, + ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) + | (greycheck ? V_TRANSLUCENT : 0) + | V_ALLOWLOWERCASE, name); if (gametyperules & GTR_TEAMFLAGS) { @@ -2497,10 +2377,10 @@ static void HU_Draw32TeamTabRankings(playersort_t *tab, INT32 whiteplayer) V_DrawRightAlignedThinString(x+128, y, ((players[tab[i].num].spectator || players[tab[i].num].playerstate == PST_DEAD) ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); if (!splitscreen) { - if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) - HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0); - //else - //V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); + if (tab[i].num != serverplayer) + HU_drawPing(x + 135, y+1, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], true, 0); + //else + //V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); } } } @@ -2583,10 +2463,11 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer) supercheck = supercheckdef; strlcpy(name, tab[i].name, 7); - V_DrawString(x + 20, y, - ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | (greycheck ? V_TRANSLUCENT : 0) - | V_ALLOWLOWERCASE, name); + if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1)) + V_DrawString(x + 20, y, + ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) + | (greycheck ? V_TRANSLUCENT : 0) + | V_ALLOWLOWERCASE, name); if (gametyperules & GTR_TEAMFLAGS) { @@ -2621,10 +2502,10 @@ void HU_DrawTeamTabRankings(playersort_t *tab, INT32 whiteplayer) V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count)); if (!splitscreen) { - if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) - HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0); - //else - // V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER"); + if (tab[i].num != serverplayer) + HU_drawPing(x+ 113, y, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], false, 0); + //else + // V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER"); } } } @@ -2652,15 +2533,16 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline supercheck = supercheckdef; strlcpy(name, tab[i].name, 7); - if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) - HU_drawPing(x+ 113, y, playerpingtable[tab[i].num], false, 0); + if (tab[i].num != serverplayer) + HU_drawPing(x+ 113, y, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], false, 0); //else // V_DrawSmallString(x+ 94, y+4, V_YELLOWMAP, "SERVER"); - V_DrawString(x + 20, y, - ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | (greycheck ? V_TRANSLUCENT : 0) - | V_ALLOWLOWERCASE, name); + if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1)) + V_DrawString(x + 20, y, + ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) + | (greycheck ? V_TRANSLUCENT : 0) + | V_ALLOWLOWERCASE, name); if (G_GametypeUsesLives() && !(G_GametypeUsesCoopLives() && (cv_cooplives.value == 0 || cv_cooplives.value == 3)) && (players[tab[i].num].lives != INFLIVES)) //show lives V_DrawRightAlignedString(x, y+4, V_ALLOWLOWERCASE, va("%dx", players[tab[i].num].lives)); @@ -2716,12 +2598,12 @@ void HU_DrawDualTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scoreline if (circuitmap) { if (players[tab[i].num].exiting) - V_DrawRightAlignedThinString(x+146, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); + V_DrawRightAlignedThinString(x+100, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); else - V_DrawRightAlignedThinString(x+146, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count)); } else - V_DrawRightAlignedThinString(x+146, y, (greycheck ? V_TRANSLUCENT : 0), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); + V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); } else V_DrawRightAlignedThinString(x+100, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count)); @@ -2760,16 +2642,17 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor strlcpy(name, tab[i].name, 7); if (!splitscreen) // don't draw it on splitscreen, { - if (!(tab[i].num == serverplayer || players[tab[i].num].quittime)) - HU_drawPing(x+ 135, y+1, playerpingtable[tab[i].num], true, 0); - //else - // V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); + if (tab[i].num != serverplayer) + HU_drawPing(x+ 135, y+1, players[tab[i].num].quittime ? UINT32_MAX : playerpingtable[tab[i].num], true, 0); + //else + // V_DrawSmallString(x+ 129, y+4, V_YELLOWMAP, "HOST"); } - V_DrawString(x + 10, y, - ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) - | (greycheck ? 0 : V_TRANSLUCENT) - | V_ALLOWLOWERCASE, name); + if (!players[tab[i].num].quittime || (leveltime / (TICRATE/2) & 1)) + V_DrawString(x + 10, y, + ((tab[i].num == whiteplayer) ? V_YELLOWMAP : 0) + | (greycheck ? V_TRANSLUCENT : 0) + | V_ALLOWLOWERCASE, name); if (G_GametypeUsesLives()) //show lives V_DrawRightAlignedThinString(x-1, y, V_ALLOWLOWERCASE, va("%d", players[tab[i].num].lives)); @@ -2828,13 +2711,13 @@ static void HU_Draw32TabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scor if (players[tab[i].num].exiting) V_DrawRightAlignedThinString(x+128, y, 0, va("%i:%02i.%02i", G_TicsToMinutes(players[tab[i].num].realtime,true), G_TicsToSeconds(players[tab[i].num].realtime), G_TicsToCentiseconds(players[tab[i].num].realtime))); else - V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+128, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count)); } else - V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); + V_DrawRightAlignedThinString(x+128, y, (greycheck ? V_TRANSLUCENT : 0), va("%i:%02i.%02i", G_TicsToMinutes(tab[i].count,true), G_TicsToSeconds(tab[i].count), G_TicsToCentiseconds(tab[i].count))); } else - V_DrawRightAlignedThinString(x+128, y, (greycheck ? 0 : V_TRANSLUCENT), va("%u", tab[i].count)); + V_DrawRightAlignedThinString(x+128, y, (greycheck ? V_TRANSLUCENT : 0), va("%u", tab[i].count)); y += 9; if (i == 16) @@ -3073,7 +2956,7 @@ static void HU_DrawRankings(void) HU_DrawTeamTabRankings(tab, whiteplayer); else if (scorelines <= 9 && !cv_compactscoreboard.value) HU_DrawTabRankings(40, 32, tab, scorelines, whiteplayer); - else if (scorelines <= 20 && !cv_compactscoreboard.value) + else if (scorelines <= 18 && !cv_compactscoreboard.value) HU_DrawDualTabRankings(32, 32, tab, scorelines, whiteplayer); else HU_Draw32TabRankings(14, 28, tab, scorelines, whiteplayer); diff --git a/src/hu_stuff.h b/src/hu_stuff.h index 63d85f1b8..110486378 100644 --- a/src/hu_stuff.h +++ b/src/hu_stuff.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -62,7 +62,7 @@ typedef struct //------------------------------------ // chat stuff //------------------------------------ -#define HU_MAXMSGLEN 224 +#define HU_MAXMSGLEN 223 #define CHAT_BUFSIZE 64 // that's enough messages, right? We'll delete the older ones when that gets out of hand. #ifdef NETSPLITSCREEN #define OLDCHAT (cv_consolechat.value == 1 || dedicated || vid.width < 640) diff --git a/src/i_addrinfo.c b/src/i_addrinfo.c index e77774549..49aadf27d 100644 --- a/src/i_addrinfo.c +++ b/src/i_addrinfo.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2011-2020 by Sonic Team Junior. +// Copyright (C) 2011-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -20,7 +20,7 @@ #else #include #endif -#elif !defined (__DJGPP__) +#else #include #include #include diff --git a/src/i_addrinfo.h b/src/i_addrinfo.h index 7ae006719..592e693f4 100644 --- a/src/i_addrinfo.h +++ b/src/i_addrinfo.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2011-2020 by Sonic Team Junior. +// Copyright (C) 2011-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_joy.h b/src/i_joy.h index 2a2797fc4..27584cea6 100644 --- a/src/i_joy.h +++ b/src/i_joy.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_net.h b/src/i_net.h index 5d93f191e..62b7528d5 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_sound.h b/src/i_sound.h index d45c0b323..6358fbefb 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_system.h b/src/i_system.h index 12f0d751d..27fcdeb3f 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -50,7 +50,7 @@ tic_t I_GetTime(void); */ precise_t I_GetPreciseTime(void); -/** \brief Returns the difference between precise times as microseconds. +/** \brief Converts a precise_t to microseconds and casts it to a 32 bit integer. */ int I_PreciseToMicros(precise_t); @@ -314,4 +314,12 @@ const char *I_ClipboardPaste(void); void I_RegisterSysCommands(void); +/** \brief Return the position of the cursor relative to the top-left window corner. +*/ +void I_GetCursorPosition(INT32 *x, INT32 *y); + +/** \brief Sets whether the mouse is grabbed +*/ +void I_SetMouseGrab(boolean grab); + #endif diff --git a/src/i_tcp.c b/src/i_tcp.c index ab8a69a9f..8838ba725 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -64,7 +64,7 @@ #include #include - #if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON) + #if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON) #include #endif // UNIXCOMMON #endif @@ -107,15 +107,6 @@ #endif #endif // USE_WINSOCK - #ifdef __DJGPP__ - #ifdef WATTCP // Alam_GBC: Wattcp may need this - #include - #define strerror strerror_s - #else // wattcp - #include - #endif // libsocket - #endif // djgpp - typedef union { struct sockaddr any; @@ -149,32 +140,22 @@ #include "doomstat.h" -// win32 or djgpp -#if defined (USE_WINSOCK) || defined (__DJGPP__) +// win32 +#ifdef USE_WINSOCK // winsock stuff (in winsock a socket is not a file) #define ioctl ioctlsocket #define close closesocket #endif #include "i_addrinfo.h" - -#ifdef __DJGPP__ - -#ifdef WATTCP #define SELECTTEST -#endif - -#else -#define SELECTTEST -#endif - #define DEFAULTPORT "5029" #if defined (USE_WINSOCK) && !defined (NONET) typedef SOCKET SOCKET_TYPE; #define ERRSOCKET (SOCKET_ERROR) #else - #if (defined (__unix__) && !defined (MSDOS)) || defined (__APPLE__) || defined (__HAIKU__) + #if defined (__unix__) || defined (__APPLE__) || defined (__HAIKU__) typedef int SOCKET_TYPE; #else typedef unsigned long SOCKET_TYPE; @@ -184,7 +165,7 @@ #ifndef NONET // define socklen_t in DOS/Windows if it is not already defined - #if (defined (WATTCP) && !defined (__libsocket_socklen_t)) || defined (USE_WINSOCK1) + #ifdef USE_WINSOCK1 typedef int socklen_t; #endif static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET}; @@ -207,19 +188,6 @@ static const char *serverport_name = DEFAULTPORT; static const char *clientport_name;/* any port */ #ifndef NONET - -#ifdef WATTCP -static void wattcp_outch(char s) -{ - static char old = '\0'; - char pr[2] = {s,0}; - if (s == old && old == ' ') return; - else old = s; - if (s == '\r') CONS_Printf("\n"); - else if (s != '\n') CONS_Printf(pr); -} -#endif - #ifdef USE_WINSOCK // stupid microsoft makes things complicated static char *get_WSAErrorStr(int e) @@ -764,11 +732,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen int opt; socklen_t opts; #ifdef FIONBIO -#ifdef WATTCP - char trueval = true; -#else unsigned long trueval = true; -#endif #endif mysockaddr_t straddr; struct sockaddr_in sin; @@ -1138,61 +1102,7 @@ boolean I_InitTcpDriver(void) CONS_Debug(DBG_NETPLAY, "WinSock description: %s\n",WSAData.szDescription); CONS_Debug(DBG_NETPLAY, "WinSock System Status: %s\n",WSAData.szSystemStatus); #endif -#ifdef __DJGPP__ -#ifdef WATTCP // Alam_GBC: survive bootp, dhcp, rarp and wattcp/pktdrv from failing to load - survive_eth = 1; // would be needed to not exit if pkt_eth_init() fails - survive_bootp = 1; // ditto for BOOTP - survive_dhcp = 1; // ditto for DHCP/RARP - survive_rarp = 1; - //_watt_do_exit = false; - //_watt_handle_cbreak = false; - //_watt_no_config = true; - _outch = wattcp_outch; - init_misc(); -//#ifdef DEBUGFILE - dbug_init(); -//#endif - switch (sock_init()) - { - case 0: - init_tcp_driver = true; - break; - case 3: - CONS_Debug(DBG_NETPLAY, "No packet driver detected\n"); - break; - case 4: - CONS_Debug(DBG_NETPLAY, "Error while talking to packet driver\n"); - break; - case 5: - CONS_Debug(DBG_NETPLAY, "BOOTP failed\n"); - break; - case 6: - CONS_Debug(DBG_NETPLAY, "DHCP failed\n"); - break; - case 7: - CONS_Debug(DBG_NETPLAY, "RARP failed\n"); - break; - case 8: - CONS_Debug(DBG_NETPLAY, "TCP/IP failed\n"); - break; - case 9: - CONS_Debug(DBG_NETPLAY, "PPPoE login/discovery failed\n"); - break; - default: - CONS_Debug(DBG_NETPLAY, "Unknown error with TCP/IP stack\n"); - break; - } - hires_timer(0); -#else // wattcp - if (__lsck_init()) - init_tcp_driver = true; - else - CONS_Debug(DBG_NETPLAY, "No TCP/IP driver detected\n"); -#endif // libsocket -#endif // __DJGPP__ -#ifndef __DJGPP__ init_tcp_driver = true; -#endif } #endif if (!tcp_was_up && init_tcp_driver) @@ -1217,10 +1127,8 @@ static void SOCK_CloseSocket(void) if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET && FD_ISSET(mysockets[i], &masterset)) { -#if !defined (__DJGPP__) || defined (WATTCP) FD_CLR(mysockets[i], &masterset); close(mysockets[i]); -#endif } mysockets[i] = ERRSOCKET; } @@ -1237,14 +1145,6 @@ void I_ShutdownTcpDriver(void) WS_addrinfocleanup(); WSACleanup(); #endif -#ifdef __DJGPP__ -#ifdef WATTCP // wattcp - //_outch = NULL; - sock_exit(); -#else - __lsck_uninit(); -#endif // libsocket -#endif // __DJGPP__ CONS_Printf("shut down\n"); init_tcp_driver = false; #endif diff --git a/src/i_tcp.h b/src/i_tcp.h index 738b8b4d1..b6e5b9235 100644 --- a/src/i_tcp.h +++ b/src/i_tcp.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_threads.h b/src/i_threads.h index ecb9fce67..c7b71d26c 100644 --- a/src/i_threads.h +++ b/src/i_threads.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by James R. +// Copyright (C) 2020-2022 by James R. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/i_video.h b/src/i_video.h index ab48881d4..638fcb668 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/info.c b/src/info.c index 8cba61494..179370ca4 100644 --- a/src/info.c +++ b/src/info.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -150,6 +150,7 @@ char sprnames[NUMSPRITES + 1][5] = "SIGN", // Level end sign "SPIK", // Spike Ball "SFLM", // Spin fire + "TFLM", // Spin fire (team) "USPK", // Floor spike "WSPK", // Wall spike "WSPB", // Wall spike base @@ -202,6 +203,10 @@ char sprnames[NUMSPRITES + 1][5] = // The letter "LETR", + // Tutorial Scenery + "TUPL", + "TUPF", + // Greenflower Scenery "FWR1", "FWR2", // GFZ Sunflower @@ -898,7 +903,7 @@ state_t states[NUMSTATES] = {SPR_TRET, FF_FULLBRIGHT|2, 7, {A_Pain}, 0, 0, S_TURRETSHOCK7}, // S_TURRETSHOCK6 {SPR_TRET, FF_FULLBRIGHT|3, 7, {NULL}, 0, 0, S_TURRETSHOCK8}, // S_TURRETSHOCK7 {SPR_TRET, FF_FULLBRIGHT|4, 7, {NULL}, 0, 0, S_TURRETSHOCK9}, // S_TURRETSHOCK8 - {SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecute}, LE_TURRET, 0, S_XPLD1}, // S_TURRETSHOCK9 + {SPR_TRET, FF_FULLBRIGHT|4, 7, {A_LinedefExecuteFromArg}, 0, 0, S_XPLD1}, // S_TURRETSHOCK9 {SPR_TURR, 0, 1, {A_Look}, 1, 0, S_TURRETPOPDOWN8}, // S_TURRETLOOK {SPR_TURR, 0, 0, {A_FaceTarget}, 0, 0, S_TURRETPOPUP1}, // S_TURRETSEE @@ -1451,7 +1456,7 @@ state_t states[NUMSTATES] = {SPR_FANG, 18, 16, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT1}, // S_FANG_PINCHLOBSHOT0 {SPR_FANG, 19, 2, {A_FaceTarget}, 3, 0, S_FANG_PINCHLOBSHOT2}, // S_FANG_PINCHLOBSHOT1 {SPR_FANG, 20, 30, {A_Boss5MakeItRain}, MT_FBOMB, -16, S_FANG_PINCHLOBSHOT3}, // S_FANG_PINCHLOBSHOT2 - {SPR_FANG, 20, 18, {A_LinedefExecute}, LE_BOSS4DROP, 0, S_FANG_PINCHLOBSHOT4}, // S_FANG_PINCHLOBSHOT3 + {SPR_FANG, 20, 18, {A_LinedefExecuteFromArg}, 4, 0, S_FANG_PINCHLOBSHOT4}, // S_FANG_PINCHLOBSHOT3 {SPR_FANG, 0, 0, {A_Boss5Calm}, 0, 0, S_FANG_PATHINGSTART1}, // S_FANG_PINCHLOBSHOT4 {SPR_FANG, 21, 0, {A_DoNPCPain}, 0, 0, S_FANG_DIE2}, // S_FANG_DIE1 @@ -1583,7 +1588,7 @@ state_t states[NUMSTATES] = {SPR_BRAK, 21, 3*TICRATE, {NULL}, 0, 0, S_BLACKEGG_DESTROYPLAT2}, // S_BLACKEGG_DESTROYPLAT1 {SPR_BRAK, 21, 1, {A_PlaySound}, sfx_s3k54, 0, S_BLACKEGG_DESTROYPLAT3}, // S_BLACKEGG_DESTROYPLAT2 - {SPR_BRAK, 21, 14, {A_LinedefExecute}, LE_BRAKPLATFORM, 0, S_BLACKEGG_STND}, // S_BLACKEGG_DESTROYPLAT3 + {SPR_BRAK, 21, 14, {A_LinedefExecuteFromArg}, 5, 0, S_BLACKEGG_STND}, // S_BLACKEGG_DESTROYPLAT3 {SPR_NULL, 0, 1, {A_CapeChase}, (160 - 20) << 16, 0, S_BLACKEGG_HELPER}, // S_BLACKEGG_HELPER @@ -1617,7 +1622,7 @@ state_t states[NUMSTATES] = {SPR_BRAK, 26 + FF_FULLBRIGHT, 2, {A_BrakFireShot}, MT_CYBRAKDEMON_FLAMESHOT, 128, S_CYBRAKDEMON_FLAME_ATTACK4}, // S_CYBRAKDEMON_FLAME_ATTACK3 // Fire {SPR_BRAK, 7, 1, {A_Repeat}, 30, S_CYBRAKDEMON_FLAME_ATTACK3, S_CYBRAKDEMON_FINISH_ATTACK1}, // S_CYBRAKDEMON_FLAME_ATTACK4 // Loop {SPR_BRAK, 0, 6, {A_RandomState}, S_CYBRAKDEMON_VILE_ATTACK1, S_CYBRAKDEMON_NAPALM_ATTACK1, S_CYBRAKDEMON_MISSILE_ATTACK1}, // S_CYBRAKDEMON_CHOOSE_ATTACK2 - {SPR_BRAK, 20, 0, {A_LinedefExecute}, LE_BRAKVILEATACK, 0, S_CYBRAKDEMON_VILE_ATTACK2}, // S_CYBRAKDEMON_VILE_ATTACK1 + {SPR_BRAK, 20, 0, {A_LinedefExecuteFromArg}, 5, 0, S_CYBRAKDEMON_VILE_ATTACK2}, // S_CYBRAKDEMON_VILE_ATTACK1 {SPR_BRAK, 20, 24, {A_VileTarget}, MT_CYBRAKDEMON_TARGET_RETICULE, 1, S_CYBRAKDEMON_VILE_ATTACK3}, // S_CYBRAKDEMON_VILE_ATTACK2 {SPR_BRAK, 19, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK4}, // S_CYBRAKDEMON_VILE_ATTACK3 {SPR_BRAK, 18, 8, {A_FaceTarget}, 0, 0, S_CYBRAKDEMON_VILE_ATTACK5}, // S_CYBRAKDEMON_VILE_ATTACK4 @@ -1630,7 +1635,7 @@ state_t states[NUMSTATES] = {SPR_BRAK, 0, 0, {A_SetReactionTime}, 0, 0, S_CYBRAKDEMON_WALK1}, // S_CYBRAKDEMON_FINISH_ATTACK2 // If just attacked, remove MF2_FRET w/out going back to spawnstate {SPR_BRAK, 18, 24, {A_Pain}, 0, 0, S_CYBRAKDEMON_PAIN2}, // S_CYBRAKDEMON_PAIN1 {SPR_BRAK, 18, 0, {A_CheckHealth}, 3, S_CYBRAKDEMON_PAIN3, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN2 - {SPR_BRAK, 18, 0, {A_LinedefExecute}, LE_PINCHPHASE, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN3 + {SPR_BRAK, 18, 0, {A_LinedefExecuteFromArg}, 4, 0, S_CYBRAKDEMON_CHOOSE_ATTACK1}, // S_CYBRAKDEMON_PAIN3 {SPR_BRAK, 18, 1, {A_Repeat}, 1, S_CYBRAKDEMON_DIE1, S_CYBRAKDEMON_DIE2}, // S_CYBRAKDEMON_DIE1 {SPR_BRAK, 18, 2, {A_BossScream}, 2, 0, S_CYBRAKDEMON_DIE3}, // S_CYBRAKDEMON_DIE2 {SPR_BRAK, 18, 0, {A_Repeat}, 52, S_CYBRAKDEMON_DIE2, S_CYBRAKDEMON_DIE4}, // S_CYBRAKDEMON_DIE3 @@ -1894,6 +1899,13 @@ state_t states[NUMSTATES] = {SPR_SFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_SPINFIRE6}, // S_SPINFIRE5 {SPR_SFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_SPINFIRE1}, // S_SPINFIRE6 + {SPR_TFLM, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE2}, // S_TEAM_SPINFIRE1 + {SPR_TFLM, FF_FULLBRIGHT|1, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE3}, // S_TEAM_SPINFIRE2 + {SPR_TFLM, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE4}, // S_TEAM_SPINFIRE3 + {SPR_TFLM, FF_FULLBRIGHT|3, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE5}, // S_TEAM_SPINFIRE4 + {SPR_TFLM, FF_FULLBRIGHT|4, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE6}, // S_TEAM_SPINFIRE5 + {SPR_TFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE1}, // S_TEAM_SPINFIRE6 + // Floor Spike {SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended {SPR_USPK, 1, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2 @@ -2061,7 +2073,7 @@ state_t states[NUMSTATES] = {SPR_TVFL, 2, 18, {A_GiveShield}, SH_FLAMEAURA, 0, S_NULL}, // S_FLAMEAURA_ICON2 {SPR_TVBB, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_BUBBLEWRAP_ICON2}, // S_BUBBLEWRAP_ICON1 - {SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLERWAP_ICON2 + {SPR_TVBB, 2, 18, {A_GiveShield}, SH_BUBBLEWRAP, 0, S_NULL}, // S_BUBBLEWRAP_ICON2 {SPR_TVZP, FF_ANIMATE|2, 18, {NULL}, 3, 4, S_THUNDERCOIN_ICON2}, // S_THUNDERCOIN_ICON1 {SPR_TVZP, 2, 18, {A_GiveShield}, SH_THUNDERCOIN, 0, S_NULL}, // S_THUNDERCOIN_ICON2 @@ -2109,6 +2121,56 @@ state_t states[NUMSTATES] = {SPR_LETR, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_LETTER + // Tutorial scenery + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF2}, // S_TUTORIALLEAF1 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF3}, // S_TUTORIALLEAF2 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF4}, // S_TUTORIALLEAF3 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF5}, // S_TUTORIALLEAF4 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF6}, // S_TUTORIALLEAF5 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF7}, // S_TUTORIALLEAF6 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF8}, // S_TUTORIALLEAF7 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF9}, // S_TUTORIALLEAF8 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALLEAF10}, // S_TUTORIALLEAF9 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALLEAF11}, // S_TUTORIALLEAF10 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALLEAF12}, // S_TUTORIALLEAF11 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALLEAF13}, // S_TUTORIALLEAF12 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALLEAF14}, // S_TUTORIALLEAF13 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALLEAF15}, // S_TUTORIALLEAF14 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALLEAF16}, // S_TUTORIALLEAF15 + {SPR_TUPL, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALLEAF1}, // S_TUTORIALLEAF16 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER2}, // S_TUTORIALFLOWER1 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER3}, // S_TUTORIALFLOWER2 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER4}, // S_TUTORIALFLOWER3 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER5}, // S_TUTORIALFLOWER4 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER6}, // S_TUTORIALFLOWER5 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER7}, // S_TUTORIALFLOWER6 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER8}, // S_TUTORIALFLOWER7 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER9}, // S_TUTORIALFLOWER8 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWER10}, // S_TUTORIALFLOWER9 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWER11}, // S_TUTORIALFLOWER10 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWER12}, // S_TUTORIALFLOWER11 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWER13}, // S_TUTORIALFLOWER12 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWER14}, // S_TUTORIALFLOWER13 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWER15}, // S_TUTORIALFLOWER14 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWER16}, // S_TUTORIALFLOWER15 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_PAPERSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWER1}, // S_TUTORIALFLOWER16 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF2}, // S_TUTORIALFLOWERF1 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF3}, // S_TUTORIALFLOWERF2 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF4}, // S_TUTORIALFLOWERF3 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF5}, // S_TUTORIALFLOWERF4 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF6}, // S_TUTORIALFLOWERF5 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF7}, // S_TUTORIALFLOWERF6 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF8}, // S_TUTORIALFLOWERF7 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF9}, // S_TUTORIALFLOWERF8 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|7, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF10}, // S_TUTORIALFLOWERF9 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|6, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF11}, // S_TUTORIALFLOWERF10 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|5, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF12}, // S_TUTORIALFLOWERF11 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|4, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF13}, // S_TUTORIALFLOWERF12 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|3, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF14}, // S_TUTORIALFLOWERF13 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|2, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF15}, // S_TUTORIALFLOWERF14 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|1, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF16}, // S_TUTORIALFLOWERF15 + {SPR_TUPF, FF_SEMIBRIGHT|FF_ADD|FF_FLOORSPRITE|0, 3, {NULL}, 0, 0, S_TUTORIALFLOWERF1}, // S_TUTORIALFLOWERF16 + // GFZ flowers {SPR_FWR1, FF_ANIMATE, -1, {NULL}, 7, 3, S_NULL}, // S_GFZFLOWERA {SPR_FWR2, FF_ANIMATE, -1, {NULL}, 19, 3, S_NULL}, // S_GFZFLOWERB @@ -2160,7 +2222,7 @@ state_t states[NUMSTATES] = {SPR_GARG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BIGGARGOYLE // DSZ Seaweed - {SPR_SEWE, 0, -1, {NULL}, 0, 0, S_SEAWEED2}, // S_SEAWEED1 + {SPR_SEWE, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 26, 3, S_SEAWEED1}, // S_SEAWEED1 {SPR_SEWE, 1, 5, {NULL}, 0, 0, S_SEAWEED3}, // S_SEAWEED2 {SPR_SEWE, 2, 5, {NULL}, 0, 0, S_SEAWEED4}, // S_SEAWEED3 {SPR_SEWE, 3, 5, {NULL}, 0, 0, S_SEAWEED5}, // S_SEAWEED4 @@ -2930,10 +2992,10 @@ state_t states[NUMSTATES] = {SPR_NULL, 0, 15*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB11 // Thunder spark - {SPR_SSPK, FF_ANIMATE, -1, {NULL}, 1, 2, S_NULL}, // S_THUNDERCOIN_SPARK + {SPR_SSPK, FF_ANIMATE|FF_FULLBRIGHT, -1, {NULL}, 1, 2, S_NULL}, // S_THUNDERCOIN_SPARK // Invincibility Sparkles - {SPR_IVSP, FF_ANIMATE, 32, {NULL}, 31, 1, S_NULL}, // S_IVSP + {SPR_IVSP, FF_ANIMATE|FF_FULLBRIGHT, 32, {NULL}, 31, 1, S_NULL}, // S_IVSP // Super Sonic Spark {SPR_SSPK, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_SSPK2}, // S_SSPK1 @@ -3291,18 +3353,18 @@ state_t states[NUMSTATES] = {SPR_WZAP, FF_TRANS10|FF_ANIMATE|FF_RANDOMANIM, 4, {NULL}, 3, 2, S_NULL}, // S_WATERZAP // Spindash dust - {SPR_DUST, 0, 7, {NULL}, 0, 0, S_SPINDUST2}, // S_SPINDUST1 - {SPR_DUST, 1, 6, {NULL}, 0, 0, S_SPINDUST3}, // S_SPINDUST2 - {SPR_DUST, FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4}, // S_SPINDUST3 - {SPR_DUST, FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST4 - {SPR_BUBL, 0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2}, // S_SPINDUST_BUBBLE1 - {SPR_BUBL, 0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3}, // S_SPINDUST_BUBBLE2 - {SPR_BUBL, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4}, // S_SPINDUST_BUBBLE3 - {SPR_BUBL, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_BUBBLE4 - {SPR_FPRT, 0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2}, // S_SPINDUST_FIRE1 - {SPR_FPRT, 0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3}, // S_SPINDUST_FIRE2 - {SPR_FPRT, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4}, // S_SPINDUST_FIRE3 - {SPR_FPRT, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_FIRE4 + {SPR_DUST, 0, 7, {NULL}, 0, 0, S_SPINDUST2}, // S_SPINDUST1 + {SPR_DUST, 1, 6, {NULL}, 0, 0, S_SPINDUST3}, // S_SPINDUST2 + {SPR_DUST, FF_TRANS30|2, 4, {NULL}, 0, 0, S_SPINDUST4}, // S_SPINDUST3 + {SPR_DUST, FF_TRANS60|3, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST4 + {SPR_BUBL, 0, 7, {NULL}, 0, 0, S_SPINDUST_BUBBLE2}, // S_SPINDUST_BUBBLE1 + {SPR_BUBL, 0, 6, {NULL}, 0, 0, S_SPINDUST_BUBBLE3}, // S_SPINDUST_BUBBLE2 + {SPR_BUBL, FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_BUBBLE4}, // S_SPINDUST_BUBBLE3 + {SPR_BUBL, FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_BUBBLE4 + {SPR_FPRT, FF_FULLBRIGHT|0, 7, {NULL}, 0, 0, S_SPINDUST_FIRE2}, // S_SPINDUST_FIRE1 + {SPR_FPRT, FF_FULLBRIGHT|0, 6, {NULL}, 0, 0, S_SPINDUST_FIRE3}, // S_SPINDUST_FIRE2 + {SPR_FPRT, FF_FULLBRIGHT|FF_TRANS30|0, 4, {NULL}, 0, 0, S_SPINDUST_FIRE4}, // S_SPINDUST_FIRE3 + {SPR_FPRT, FF_FULLBRIGHT|FF_TRANS60|0, 3, {NULL}, 0, 0, S_NULL}, // S_SPINDUST_FIRE4 {SPR_TFOG, FF_FULLBRIGHT|FF_TRANS50, 2, {NULL}, 0, 0, S_FOG2}, // S_FOG1 @@ -3728,14 +3790,13 @@ state_t states[NUMSTATES] = {SPR_FL01, 3, 1, {A_OrbitNights}, ANG2*2, 180 | 0x10000, S_NIGHTOPIANHELPER1}, // S_NIGHTOPIANHELPER9 // Nightopian - {SPR_NTPN, 0, 4, {A_Look}, 0, 0, S_PIAN0}, // S_PIAN0 - {SPR_NTPN, 0, 4, {A_JetgThink}, 0, 0, S_PIAN2}, // S_PIAN1 - {SPR_NTPN, 1, 4, {NULL}, 0, 0, S_PIAN3}, // S_PIAN2 - {SPR_NTPN, 2, 4, {NULL}, 0, 0, S_PIAN4}, // S_PIAN3 - {SPR_NTPN, 3, 4, {NULL}, 0, 0, S_PIAN5}, // S_PIAN4 - {SPR_NTPN, 2, 4, {NULL}, 0, 0, S_PIAN6}, // S_PIAN5 - {SPR_NTPN, 1, 4, {NULL}, 0, 0, S_PIAN1}, // S_PIAN6 - {SPR_NTPN, 5|FF_ANIMATE, 4, {NULL}, 1, 4, S_PIAN1}, // S_PIANSING + {SPR_NTPN, 0, 2, {A_Look}, 1, 1, S_PIAN_LOOK2}, // S_PIAN_LOOK1 + {SPR_NTPN, 1, 2, {A_Look}, 1, 1, S_PIAN_LOOK3}, // S_PIAN_LOOK2 + {SPR_NTPN, 2, 2, {A_Look}, 1, 1, S_PIAN_LOOK1}, // S_PIAN_LOOK3 + {SPR_NTPN, 0, 2, {A_JetgThink}, 0, 0, S_PIAN_FLY2}, // S_PIAN_FLY1 + {SPR_NTPN, 1, 2, {NULL}, 0, 0, S_PIAN_FLY3}, // S_PIAN_FLY2 + {SPR_NTPN, 2, 2, {NULL}, 0, 0, S_PIAN_FLY1}, // S_PIAN_FLY3 + {SPR_NTPN, 3|FF_ANIMATE, 24, {NULL}, 2, 2, S_PIAN_FLY1}, // S_PIAN_SING // Shleep {SPR_SHLP, 0, 15, {NULL}, 0, 0, S_SHLEEP2}, // S_SHLEEP1 @@ -3875,23 +3936,23 @@ state_t states[NUMSTATES] = {SPR_SPRK, FF_TRANS20|FF_ANIMATE|9, 18, {NULL}, 8, 2, S_NULL}, // S_SPRK3 // Robot Explosion - {SPR_BOM1, 0, 0, {A_FlickySpawn}, 0, 0, S_XPLD1}, // S_XPLD_FLICKY - {SPR_BOM1, 0, 2, {A_Scream}, 0, 0, S_XPLD2}, // S_XPLD1 - {SPR_BOM1, 1, 2, {NULL}, 0, 0, S_XPLD3}, // S_XPLD2 - {SPR_BOM1, 2, 3, {NULL}, 0, 0, S_XPLD4}, // S_XPLD3 - {SPR_BOM1, 3, 3, {NULL}, 0, 0, S_XPLD5}, // S_XPLD4 - {SPR_BOM1, 4, 4, {NULL}, 0, 0, S_XPLD6}, // S_XPLD5 - {SPR_BOM1, 5, 4, {NULL}, 0, 0, S_NULL}, // S_XPLD6 + {SPR_BOM1, 0, 0, {A_FlickySpawn}, 0, 0, S_XPLD1}, // S_XPLD_FLICKY + {SPR_BOM1, 0, 2, {A_ShadowScream}, 0, 0, S_XPLD2}, // S_XPLD1 + {SPR_BOM1, 1, 2, {NULL}, 0, 0, S_XPLD3}, // S_XPLD2 + {SPR_BOM1, 2, 3, {NULL}, 0, 0, S_XPLD4}, // S_XPLD3 + {SPR_BOM1, 3, 3, {NULL}, 0, 0, S_XPLD5}, // S_XPLD4 + {SPR_BOM1, 4, 4, {NULL}, 0, 0, S_XPLD6}, // S_XPLD5 + {SPR_BOM1, 5, 4, {NULL}, 0, 0, S_NULL}, // S_XPLD6 {SPR_BOM1, FF_ANIMATE, 21, {NULL}, 5, 4, S_INVISIBLE}, // S_XPLD_EGGTRAP // Underwater Explosion - {SPR_BOM4, 0, 3, {A_Scream}, 0, 0, S_WPLD2}, // S_WPLD1 - {SPR_BOM4, 1, 3, {NULL}, 0, 0, S_WPLD3}, // S_WPLD2 - {SPR_BOM4, 2, 3, {NULL}, 0, 0, S_WPLD4}, // S_WPLD3 - {SPR_BOM4, 3, 3, {NULL}, 0, 0, S_WPLD5}, // S_WPLD4 - {SPR_BOM4, 4, 3, {NULL}, 0, 0, S_WPLD6}, // S_WPLD5 - {SPR_BOM4, 5, 3, {NULL}, 0, 0, S_NULL}, // S_WPLD6 + {SPR_BOM4, 0, 3, {A_ShadowScream}, 0, 0, S_WPLD2}, // S_WPLD1 + {SPR_BOM4, 1, 3, {NULL}, 0, 0, S_WPLD3}, // S_WPLD2 + {SPR_BOM4, 2, 3, {NULL}, 0, 0, S_WPLD4}, // S_WPLD3 + {SPR_BOM4, 3, 3, {NULL}, 0, 0, S_WPLD5}, // S_WPLD4 + {SPR_BOM4, 4, 3, {NULL}, 0, 0, S_WPLD6}, // S_WPLD5 + {SPR_BOM4, 5, 3, {NULL}, 0, 0, S_NULL}, // S_WPLD6 {SPR_DUST, FF_TRANS40, 4, {NULL}, 0, 0, S_DUST2}, // S_DUST1 {SPR_DUST, 1|FF_TRANS50, 5, {NULL}, 0, 0, S_DUST3}, // S_DUST2 @@ -5190,11 +5251,11 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // speed 24*FRACUNIT, // radius 34*FRACUNIT, // height - 0, // display offset - 100, // mass + 1, // display offset + DMG_FIRE, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_NOBLOCKMAP|MF_FIRE|MF_PAIN, // flags + MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_FIRE|MF_PAIN, // flags S_NULL // raisestate }, @@ -5593,8 +5654,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE_FLEE1, // xdeathstate sfx_s3kb4, // deathsound 4, // speed - 24*FRACUNIT, // radius - 76*FRACUNIT, // height + 36*FRACUNIT, // radius + 84*FRACUNIT, // height 0, // display offset sfx_None, // mass 3, // damage @@ -5728,8 +5789,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE2_FLEE1,// xdeathstate sfx_s3kb4, // deathsound 2*FRACUNIT, // speed - 24*FRACUNIT, // radius - 76*FRACUNIT, // height + 36*FRACUNIT, // radius + 84*FRACUNIT, // height 0, // display offset 0, // mass 3, // damage @@ -5836,7 +5897,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE3_FLEE1, // xdeathstate sfx_s3kb4, // deathsound 8*FRACUNIT, // speed - 32*FRACUNIT, // radius + 36*FRACUNIT, // radius 116*FRACUNIT, // height 0, // display offset MT_FAKEMOBILE, // mass @@ -5863,7 +5924,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_mswarp, // deathsound 8*FRACUNIT, // speed - 32*FRACUNIT, // radius + 36*FRACUNIT, // radius 116*FRACUNIT, // height 0, // display offset 0, // mass @@ -5917,8 +5978,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_EGGMOBILE4_FLEE1,// xdeathstate sfx_s3kb4, // deathsound 0, // speed - 24*FRACUNIT, // radius - 76*FRACUNIT, // height + 36*FRACUNIT, // radius + 84*FRACUNIT, // height 0, // display offset 0, // mass 3, // damage @@ -7966,7 +8027,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 4, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPHEIGHT, // flags @@ -7993,7 +8054,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16*FRACUNIT, // radius 14*FRACUNIT, // height 0, // display offset - 4, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT|MF_PAPERCOLLISION, // flags @@ -9768,8 +9829,8 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_MINE_BOOM1, // deathstate - S_MINE_BOOM1, // xdeathstate + S_XPLD1, // deathstate + S_XPLD1, // xdeathstate sfx_cybdth, // deathsound 0, // speed 8*FRACUNIT, // radius @@ -9971,6 +10032,114 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_TUTORIALPLANT + 799, // doomednum + S_NULL, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_TUTORIALLEAF + -1, // doomednum + S_TUTORIALLEAF1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_TUTORIALFLOWER + -1, // doomednum + S_TUTORIALFLOWER1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + + { // MT_TUTORIALFLOWERF + -1, // doomednum + S_TUTORIALFLOWERF1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, + { // MT_GFZFLOWER1 800, // doomednum S_GFZFLOWERA, // spawnstate @@ -11422,7 +11591,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 17*FRACUNIT, // radius 34*FRACUNIT, // height 1, // display offset - 0, // mass + DMG_SPIKE, // mass 1, // damage sfx_s3kc9s, //sfx_mswing, -- activesound MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags @@ -11449,7 +11618,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 34*FRACUNIT, // radius 68*FRACUNIT, // height 1, // display offset - 0, // mass + DMG_SPIKE, // mass 1, // damage sfx_s3kc9s, //sfx_mswing, -- activesound MF_SCENERY|MF_PAIN|MF_NOGRAVITY, // flags @@ -13393,7 +13562,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 30*FRACUNIT, // radius 48*FRACUNIT, // height 0, // display offset - 100, // mass + DMG_FIRE, // mass 0, // damage sfx_None, // activesound MF_SPECIAL|MF_PAIN|MF_NOGRAVITY|MF_FIRE, // flags @@ -13473,7 +13642,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 32*FRACUNIT, // speed 30*FRACUNIT, // radius 60*FRACUNIT, // height - 0, // display offset + -1, // display offset 100, // mass 0, // damage sfx_None, // activesound @@ -13798,7 +13967,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset - 0, // mass + 0, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_PAIN, // flags @@ -18048,13 +18217,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - // ambient water 1a (large) - { // MT_AWATERA + // ambient sound effect + { // MT_AMBIENT 700, // doomednum S_INVISIBLE, // spawnstate - 35, // spawnhealth + 1000, // spawnhealth S_NULL, // seestate - sfx_amwtr1, // seesound + sfx_None, // seesound 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate @@ -18076,283 +18245,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - // ambient water 1b (large) - { // MT_AWATERB - 701, // doomednum - S_INVISIBLE, // spawnstate - 35, // spawnhealth - S_NULL, // seestate - sfx_amwtr2, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - // ambient water 2a (medium) - { // MT_AWATERC - 702, // doomednum - S_INVISIBLE, // spawnstate - 35, // spawnhealth - S_NULL, // seestate - sfx_amwtr3, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - // ambient water 2b (medium) - { // MT_AWATERD - 703, // doomednum - S_INVISIBLE, // spawnstate - 35, // spawnhealth - S_NULL, // seestate - sfx_amwtr4, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - // ambient water 3a (small) - { // MT_AWATERE - 704, // doomednum - S_INVISIBLE, // spawnstate - 35, // spawnhealth - S_NULL, // seestate - sfx_amwtr5, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - // ambient water 3b (small) - { // MT_AWATERF - 705, // doomednum - S_INVISIBLE, // spawnstate - 35, // spawnhealth - S_NULL, // seestate - sfx_amwtr6, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - // ambient water 4a (extra large) - { // MT_AWATERG - 706, // doomednum - S_INVISIBLE, // spawnstate - 35, // spawnhealth - S_NULL, // seestate - sfx_amwtr7, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - // ambient water 4b (extra large) - { // MT_AWATERH - 707, // doomednum - S_INVISIBLE, // spawnstate - 35, // spawnhealth - S_NULL, // seestate - sfx_amwtr8, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - { // MT_RANDOMAMBIENT - 708, // doomednum - S_INVISIBLE, // spawnstate - 512, // spawnhealth: repeat speed - S_NULL, // seestate - sfx_ambint, // seesound - 0, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 255, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 1000, // mass - 0, // damage - sfx_None, // activesound - MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - { // MT_RANDOMAMBIENT2 - 709, // doomednum - S_INVISIBLE, // spawnstate - 220, // spawnhealth: repeat speed - S_NULL, // seestate - sfx_ambin2, // seesound - 0, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 255, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 8*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 1000, // mass - 0, // damage - sfx_None, // activesound - MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - - { // MT_MACHINEAMBIENCE - 710, // doomednum - S_INVISIBLE, // spawnstate - 24, // spawnhealth: repeat speed - S_NULL, // seestate - sfx_ambmac, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 200, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 1*FRACUNIT, // speed - 16*FRACUNIT, // radius - 16*FRACUNIT, // height - 0, // display offset - 100, // mass - 20, // damage - sfx_None, // activesound - MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_AMBIENT, // flags - S_NULL // raisestate - }, - { // MT_CORK -1, // doomednum S_CORK, // spawnstate @@ -20111,28 +20003,28 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_PIAN 1602, // doomednum - S_PIAN0, // spawnstate + S_PIAN_LOOK1, // spawnstate 1000, // spawnhealth - S_PIAN1, // seestate + S_PIAN_FLY1, // seestate sfx_None, // seesound 0, // reactiontime sfx_None, // attacksound S_NULL, // painstate 200, // painchance sfx_None, // painsound - S_PIANSING, // meleestate - S_NULL, // missilestate + S_NULL, // meleestate + S_PIAN_SING, // missilestate S_NULL, // deathstate S_NULL, // xdeathstate sfx_None, // deathsound FRACUNIT, // speed 16*FRACUNIT, // radius - 32*FRACUNIT, // height + 40*FRACUNIT, // height 0, // display offset 16, // mass 0, // damage sfx_None, // activesound - MF_SLIDEME|MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + MF_SLIDEME|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -20372,7 +20264,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 18*FRACUNIT, // radius 28*FRACUNIT, // height 0, // display offset - 0, // mass + DMG_SPIKE, // mass 0, // damage sfx_None, // activesound MF_NOGRAVITY|MF_PAIN, // flags @@ -20705,34 +20597,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - // for use with wind and current effects - { // MT_PULL - 755, // doomednum - S_INVISIBLE, // spawnstate - 1000, // spawnhealth - S_NULL, // seestate - sfx_None, // seesound - 8, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate - 0, // painchance - sfx_None, // painsound - S_NULL, // meleestate - S_NULL, // missilestate - S_NULL, // deathstate - S_NULL, // xdeathstate - sfx_None, // deathsound - 0, // speed - 8, // radius - 8, // height - 0, // display offset - 10, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOGRAVITY, // flags - S_NULL // raisestate - }, - { // MT_GHOST -1, // doomednum S_THOK, // spawnstate @@ -21677,6 +21541,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY|MF_NOSECTOR, // flags S_NULL // raisestate }, + + { // MT_RAY + -1, // doomednum + S_NULL, // spawnstate + 0, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 0, // radius + 0, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags + S_NULL // raisestate + }, }; skincolor_t skincolors[MAXSKINCOLORS] = { @@ -21753,7 +21644,7 @@ skincolor_t skincolors[MAXSKINCOLORS] = { {"Violet", {0xd0, 0xd1, 0xd2, 0xca, 0xcc, 0xb8, 0xb9, 0xb9, 0xba, 0xa8, 0xa8, 0xa9, 0xa9, 0xfd, 0xfe, 0xfe}, SKINCOLOR_MINT, 6, V_MAGENTAMAP, true}, // SKINCOLOR_VIOLET {"Lilac", {0x00, 0xd0, 0xd1, 0xd2, 0xd3, 0xc1, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc5, 0xc6, 0xc6, 0xfe, 0x1f}, SKINCOLOR_VAPOR, 4, V_ROSYMAP, true}, // SKINCOLOR_LILAC {"Plum", {0xc8, 0xd3, 0xd5, 0xd6, 0xd7, 0xce, 0xcf, 0xb9, 0xb9, 0xba, 0xba, 0xa9, 0xa9, 0xa9, 0xfd, 0xfe}, SKINCOLOR_MINT, 7, V_ROSYMAP, true}, // SKINCOLOR_PLUM - {"Raspberry", {0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfe, 0xfe}, SKINCOLOR_APPLE, 13, V_MAGENTAMAP, true}, // SKINCOLOR_RASPBERRY + {"Raspberry", {0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xcd, 0xce, 0xb9, 0xb9, 0xba, 0xba, 0xbb, 0xfe, 0xfe}, SKINCOLOR_APPLE, 13, V_ROSYMAP, true}, // SKINCOLOR_RASPBERRY {"Rosy", {0xfc, 0xc8, 0xc8, 0xc9, 0xc9, 0xca, 0xca, 0xcb, 0xcb, 0xcc, 0xcc, 0xcd, 0xcd, 0xce, 0xce, 0xcf}, SKINCOLOR_AQUA, 1, V_ROSYMAP, true}, // SKINCOLOR_ROSY // super diff --git a/src/info.h b/src/info.h index c6a2a2c44..a9f68721f 100644 --- a/src/info.h +++ b/src/info.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -44,6 +44,8 @@ enum actionnum A_FACETRACER, A_SCREAM, A_BOSSDEATH, + A_SETSHADOWSCALE, + A_SHADOWSCREAM, A_CUSTOMPOWER, A_GIVEWEAPON, A_RINGBOX, @@ -150,6 +152,7 @@ enum actionnum A_BOSS3PATH, A_BOSS3SHOCKTHINK, A_LINEDEFEXECUTE, + A_LINEDEFEXECUTEFROMARG, A_PLAYSEESOUND, A_PLAYATTACKSOUND, A_PLAYACTIVESOUND, @@ -177,6 +180,8 @@ enum actionnum A_SETOBJECTFLAGS2, A_RANDOMSTATE, A_RANDOMSTATERANGE, + A_STATERANGEBYANGLE, + A_STATERANGEBYPARAMETER, A_DUALACTION, A_REMOTEACTION, A_TOGGLEFLAMEJET, @@ -310,6 +315,8 @@ void A_FaceTarget(); void A_FaceTracer(); void A_Scream(); void A_BossDeath(); +void A_SetShadowScale(); +void A_ShadowScream(); // MARIA!!!!!! void A_CustomPower(); // Use this for a custom power void A_GiveWeapon(); // Gives the player weapon(s) void A_RingBox(); // Obtained Ring Box Tails @@ -409,6 +416,7 @@ void A_Boss3TakeDamage(); void A_Boss3Path(); void A_Boss3ShockThink(); void A_LinedefExecute(); +void A_LinedefExecuteFromArg(); void A_PlaySeeSound(); void A_PlayAttackSound(); void A_PlayActiveSound(); @@ -443,6 +451,8 @@ void A_SetObjectFlags(); void A_SetObjectFlags2(); void A_RandomState(); void A_RandomStateRange(); +void A_StateRangeByAngle(); +void A_StateRangeByParameter(); void A_DualAction(); void A_RemoteAction(); void A_ToggleFlameJet(); @@ -684,6 +694,7 @@ typedef enum sprite SPR_SIGN, // Level end sign SPR_SPIK, // Spike Ball SPR_SFLM, // Spin fire + SPR_TFLM, // Spin fire (team) SPR_USPK, // Floor spike SPR_WSPK, // Wall spike SPR_WSPB, // Wall spike base @@ -736,6 +747,10 @@ typedef enum sprite // The letter SPR_LETR, + // Tutorial scenery + SPR_TUPL, + SPR_TUPF, + // Greenflower Scenery SPR_FWR1, SPR_FWR2, // GFZ Sunflower @@ -2324,6 +2339,13 @@ typedef enum state S_SPINFIRE5, S_SPINFIRE6, + S_TEAM_SPINFIRE1, + S_TEAM_SPINFIRE2, + S_TEAM_SPINFIRE3, + S_TEAM_SPINFIRE4, + S_TEAM_SPINFIRE5, + S_TEAM_SPINFIRE6, + // Spikes S_SPIKE1, S_SPIKE2, @@ -2543,6 +2565,56 @@ typedef enum state // The letter S_LETTER, + // Tutorial scenery + S_TUTORIALLEAF1, + S_TUTORIALLEAF2, + S_TUTORIALLEAF3, + S_TUTORIALLEAF4, + S_TUTORIALLEAF5, + S_TUTORIALLEAF6, + S_TUTORIALLEAF7, + S_TUTORIALLEAF8, + S_TUTORIALLEAF9, + S_TUTORIALLEAF10, + S_TUTORIALLEAF11, + S_TUTORIALLEAF12, + S_TUTORIALLEAF13, + S_TUTORIALLEAF14, + S_TUTORIALLEAF15, + S_TUTORIALLEAF16, + S_TUTORIALFLOWER1, + S_TUTORIALFLOWER2, + S_TUTORIALFLOWER3, + S_TUTORIALFLOWER4, + S_TUTORIALFLOWER5, + S_TUTORIALFLOWER6, + S_TUTORIALFLOWER7, + S_TUTORIALFLOWER8, + S_TUTORIALFLOWER9, + S_TUTORIALFLOWER10, + S_TUTORIALFLOWER11, + S_TUTORIALFLOWER12, + S_TUTORIALFLOWER13, + S_TUTORIALFLOWER14, + S_TUTORIALFLOWER15, + S_TUTORIALFLOWER16, + S_TUTORIALFLOWERF1, + S_TUTORIALFLOWERF2, + S_TUTORIALFLOWERF3, + S_TUTORIALFLOWERF4, + S_TUTORIALFLOWERF5, + S_TUTORIALFLOWERF6, + S_TUTORIALFLOWERF7, + S_TUTORIALFLOWERF8, + S_TUTORIALFLOWERF9, + S_TUTORIALFLOWERF10, + S_TUTORIALFLOWERF11, + S_TUTORIALFLOWERF12, + S_TUTORIALFLOWERF13, + S_TUTORIALFLOWERF14, + S_TUTORIALFLOWERF15, + S_TUTORIALFLOWERF16, + // GFZ flowers S_GFZFLOWERA, S_GFZFLOWERB, @@ -4085,14 +4157,13 @@ typedef enum state S_NIGHTOPIANHELPER9, // Nightopian - S_PIAN0, - S_PIAN1, - S_PIAN2, - S_PIAN3, - S_PIAN4, - S_PIAN5, - S_PIAN6, - S_PIANSING, + S_PIAN_LOOK1, + S_PIAN_LOOK2, + S_PIAN_LOOK3, + S_PIAN_FLY1, + S_PIAN_FLY2, + S_PIAN_FLY3, + S_PIAN_SING, // Shleep S_SHLEEP1, @@ -4575,6 +4646,12 @@ typedef enum mobj_type // The letter MT_LETTER, + // Tutorial Scenery + MT_TUTORIALPLANT, + MT_TUTORIALLEAF, + MT_TUTORIALFLOWER, + MT_TUTORIALFLOWERF, + // Greenflower Scenery MT_GFZFLOWER1, MT_GFZFLOWER2, @@ -4924,17 +5001,7 @@ typedef enum mobj_type MT_FINISHFLAG, // Finish flag // Ambient Sounds - MT_AWATERA, // Ambient Water Sound 1 - MT_AWATERB, // Ambient Water Sound 2 - MT_AWATERC, // Ambient Water Sound 3 - MT_AWATERD, // Ambient Water Sound 4 - MT_AWATERE, // Ambient Water Sound 5 - MT_AWATERF, // Ambient Water Sound 6 - MT_AWATERG, // Ambient Water Sound 7 - MT_AWATERH, // Ambient Water Sound 8 - MT_RANDOMAMBIENT, - MT_RANDOMAMBIENT2, - MT_MACHINEAMBIENCE, + MT_AMBIENT, MT_CORK, MT_LHRT, @@ -5038,7 +5105,6 @@ typedef enum mobj_type MT_CRUMBLEOBJ, // Sound generator for crumbling platform MT_TUBEWAYPOINT, MT_PUSH, - MT_PULL, MT_GHOST, MT_OVERLAY, MT_ANGLEMAN, @@ -5081,6 +5147,7 @@ typedef enum mobj_type MT_YELLOWBRICKDEBRIS, // for CEZ3 MT_NAMECHECK, + MT_RAY, // General purpose mobj MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, diff --git a/src/keys.h b/src/keys.h index 6cdd7956c..df12c95ae 100644 --- a/src/keys.h +++ b/src/keys.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/libdivide.h b/src/libdivide.h new file mode 100644 index 000000000..1a589c7e5 --- /dev/null +++ b/src/libdivide.h @@ -0,0 +1,2111 @@ +// libdivide.h - Optimized integer division +// https://libdivide.com +// +// Copyright (C) 2010 - 2019 ridiculous_fish, +// Copyright (C) 2016 - 2019 Kim Walisch, +// +// libdivide is dual-licensed under the Boost or zlib licenses. +// You may use libdivide under the terms of either of these. +// See LICENSE.txt in the libdivide source code repository for more details. + + +// NOTICE: This is an altered source version of libdivide. +// Libdivide is used here under the terms of the zlib license. +// Here is the zlib license text from https://github.com/ridiculousfish/libdivide/blob/master/LICENSE.txt +/* + zlib License + ------------ + + Copyright (C) 2010 - 2019 ridiculous_fish, + Copyright (C) 2016 - 2019 Kim Walisch, + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +// This version of libdivide has been modified for use with SRB2. +// Changes made include: +// - unused parts commented out (to avoid the need to fix C90 compilation issues with them) +// - C90 compilation issues fixed with used parts +// - use I_Error for errors + +#ifndef LIBDIVIDE_H +#define LIBDIVIDE_H + +#define LIBDIVIDE_VERSION "3.0" +#define LIBDIVIDE_VERSION_MAJOR 3 +#define LIBDIVIDE_VERSION_MINOR 0 + +#include + +#if defined(__cplusplus) + #include + #include + #include +#else + #include + #include +#endif + +#if defined(LIBDIVIDE_AVX512) + #include +#elif defined(LIBDIVIDE_AVX2) + #include +#elif defined(LIBDIVIDE_SSE2) + #include +#endif + +#if defined(_MSC_VER) + #include + // disable warning C4146: unary minus operator applied + // to unsigned type, result still unsigned + #pragma warning(disable: 4146) + #define LIBDIVIDE_VC +#endif + +#if !defined(__has_builtin) + #define __has_builtin(x) 0 +#endif + +#if defined(__SIZEOF_INT128__) + #define HAS_INT128_T + // clang-cl on Windows does not yet support 128-bit division + #if !(defined(__clang__) && defined(LIBDIVIDE_VC)) + #define HAS_INT128_DIV + #endif +#endif + +#if defined(__x86_64__) || defined(_M_X64) + #define LIBDIVIDE_X86_64 +#endif + +#if defined(__i386__) + #define LIBDIVIDE_i386 +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define LIBDIVIDE_GCC_STYLE_ASM +#endif + +#if defined(__cplusplus) || defined(LIBDIVIDE_VC) + #define LIBDIVIDE_FUNCTION __FUNCTION__ +#else + #define LIBDIVIDE_FUNCTION __func__ +#endif + +#define LIBDIVIDE_ERROR(msg) \ + I_Error("libdivide.h:%d: %s(): Error: %s\n", \ + __LINE__, LIBDIVIDE_FUNCTION, msg); + +#if defined(LIBDIVIDE_ASSERTIONS_ON) + #define LIBDIVIDE_ASSERT(x) \ + if (!(x)) { \ + I_Error("libdivide.h:%d: %s(): Assertion failed: %s\n", \ + __LINE__, LIBDIVIDE_FUNCTION, #x); \ + } +#else + #define LIBDIVIDE_ASSERT(x) +#endif + +#ifdef __cplusplus +namespace libdivide { +#endif + +// pack divider structs to prevent compilers from padding. +// This reduces memory usage by up to 43% when using a large +// array of libdivide dividers and improves performance +// by up to 10% because of reduced memory bandwidth. +#pragma pack(push, 1) + +struct libdivide_u32_t { + uint32_t magic; + uint8_t more; +}; + +struct libdivide_s32_t { + int32_t magic; + uint8_t more; +}; + +struct libdivide_u64_t { + uint64_t magic; + uint8_t more; +}; + +struct libdivide_s64_t { + int64_t magic; + uint8_t more; +}; + +struct libdivide_u32_branchfree_t { + uint32_t magic; + uint8_t more; +}; + +struct libdivide_s32_branchfree_t { + int32_t magic; + uint8_t more; +}; + +struct libdivide_u64_branchfree_t { + uint64_t magic; + uint8_t more; +}; + +struct libdivide_s64_branchfree_t { + int64_t magic; + uint8_t more; +}; + +#pragma pack(pop) + +// Explanation of the "more" field: +// +// * Bits 0-5 is the shift value (for shift path or mult path). +// * Bit 6 is the add indicator for mult path. +// * Bit 7 is set if the divisor is negative. We use bit 7 as the negative +// divisor indicator so that we can efficiently use sign extension to +// create a bitmask with all bits set to 1 (if the divisor is negative) +// or 0 (if the divisor is positive). +// +// u32: [0-4] shift value +// [5] ignored +// [6] add indicator +// magic number of 0 indicates shift path +// +// s32: [0-4] shift value +// [5] ignored +// [6] add indicator +// [7] indicates negative divisor +// magic number of 0 indicates shift path +// +// u64: [0-5] shift value +// [6] add indicator +// magic number of 0 indicates shift path +// +// s64: [0-5] shift value +// [6] add indicator +// [7] indicates negative divisor +// magic number of 0 indicates shift path +// +// In s32 and s64 branchfree modes, the magic number is negated according to +// whether the divisor is negated. In branchfree strategy, it is not negated. + +enum { + LIBDIVIDE_32_SHIFT_MASK = 0x1F, + LIBDIVIDE_64_SHIFT_MASK = 0x3F, + LIBDIVIDE_ADD_MARKER = 0x40, + LIBDIVIDE_NEGATIVE_DIVISOR = 0x80 +}; + +//static inline struct libdivide_s32_t libdivide_s32_gen(int32_t d); +static inline struct libdivide_u32_t libdivide_u32_gen(uint32_t d); +//static inline struct libdivide_s64_t libdivide_s64_gen(int64_t d); +//static inline struct libdivide_u64_t libdivide_u64_gen(uint64_t d); + +/*static inline struct libdivide_s32_branchfree_t libdivide_s32_branchfree_gen(int32_t d); +static inline struct libdivide_u32_branchfree_t libdivide_u32_branchfree_gen(uint32_t d); +static inline struct libdivide_s64_branchfree_t libdivide_s64_branchfree_gen(int64_t d); +static inline struct libdivide_u64_branchfree_t libdivide_u64_branchfree_gen(uint64_t d);*/ + +//static inline int32_t libdivide_s32_do(int32_t numer, const struct libdivide_s32_t *denom); +static inline uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom); +//static inline int64_t libdivide_s64_do(int64_t numer, const struct libdivide_s64_t *denom); +//static inline uint64_t libdivide_u64_do(uint64_t numer, const struct libdivide_u64_t *denom); + +/*static inline int32_t libdivide_s32_branchfree_do(int32_t numer, const struct libdivide_s32_branchfree_t *denom); +static inline uint32_t libdivide_u32_branchfree_do(uint32_t numer, const struct libdivide_u32_branchfree_t *denom); +static inline int64_t libdivide_s64_branchfree_do(int64_t numer, const struct libdivide_s64_branchfree_t *denom); +static inline uint64_t libdivide_u64_branchfree_do(uint64_t numer, const struct libdivide_u64_branchfree_t *denom);*/ + +/*static inline int32_t libdivide_s32_recover(const struct libdivide_s32_t *denom); +static inline uint32_t libdivide_u32_recover(const struct libdivide_u32_t *denom); +static inline int64_t libdivide_s64_recover(const struct libdivide_s64_t *denom); +static inline uint64_t libdivide_u64_recover(const struct libdivide_u64_t *denom);*/ + +/*static inline int32_t libdivide_s32_branchfree_recover(const struct libdivide_s32_branchfree_t *denom); +static inline uint32_t libdivide_u32_branchfree_recover(const struct libdivide_u32_branchfree_t *denom); +static inline int64_t libdivide_s64_branchfree_recover(const struct libdivide_s64_branchfree_t *denom); +static inline uint64_t libdivide_u64_branchfree_recover(const struct libdivide_u64_branchfree_t *denom);*/ + +//////// Internal Utility Functions + +static inline uint32_t libdivide_mullhi_u32(uint32_t x, uint32_t y) { + uint64_t xl = x, yl = y; + uint64_t rl = xl * yl; + return (uint32_t)(rl >> 32); +} + +static inline int32_t libdivide_mullhi_s32(int32_t x, int32_t y) { + int64_t xl = x, yl = y; + int64_t rl = xl * yl; + // needs to be arithmetic shift + return (int32_t)(rl >> 32); +} + +static inline uint64_t libdivide_mullhi_u64(uint64_t x, uint64_t y) { +#if defined(LIBDIVIDE_VC) && \ + defined(LIBDIVIDE_X86_64) + return __umulh(x, y); +#elif defined(HAS_INT128_T) + __uint128_t xl = x, yl = y; + __uint128_t rl = xl * yl; + return (uint64_t)(rl >> 64); +#else + // full 128 bits are x0 * y0 + (x0 * y1 << 32) + (x1 * y0 << 32) + (x1 * y1 << 64) + uint32_t mask = 0xFFFFFFFF; + uint32_t x0 = (uint32_t)(x & mask); + uint32_t x1 = (uint32_t)(x >> 32); + uint32_t y0 = (uint32_t)(y & mask); + uint32_t y1 = (uint32_t)(y >> 32); + uint32_t x0y0_hi = libdivide_mullhi_u32(x0, y0); + uint64_t x0y1 = x0 * (uint64_t)y1; + uint64_t x1y0 = x1 * (uint64_t)y0; + uint64_t x1y1 = x1 * (uint64_t)y1; + uint64_t temp = x1y0 + x0y0_hi; + uint64_t temp_lo = temp & mask; + uint64_t temp_hi = temp >> 32; + + return x1y1 + temp_hi + ((temp_lo + x0y1) >> 32); +#endif +} + +static inline int64_t libdivide_mullhi_s64(int64_t x, int64_t y) { +#if defined(LIBDIVIDE_VC) && \ + defined(LIBDIVIDE_X86_64) + return __mulh(x, y); +#elif defined(HAS_INT128_T) + __int128_t xl = x, yl = y; + __int128_t rl = xl * yl; + return (int64_t)(rl >> 64); +#else + // full 128 bits are x0 * y0 + (x0 * y1 << 32) + (x1 * y0 << 32) + (x1 * y1 << 64) + uint32_t mask = 0xFFFFFFFF; + uint32_t x0 = (uint32_t)(x & mask); + uint32_t y0 = (uint32_t)(y & mask); + int32_t x1 = (int32_t)(x >> 32); + int32_t y1 = (int32_t)(y >> 32); + uint32_t x0y0_hi = libdivide_mullhi_u32(x0, y0); + int64_t t = x1 * (int64_t)y0 + x0y0_hi; + int64_t w1 = x0 * (int64_t)y1 + (t & mask); + + return x1 * (int64_t)y1 + (t >> 32) + (w1 >> 32); +#endif +} + +static inline int32_t libdivide_count_leading_zeros32(uint32_t val) { +#if defined(__GNUC__) || \ + __has_builtin(__builtin_clz) + // Fast way to count leading zeros + return __builtin_clz(val); +#elif defined(LIBDIVIDE_VC) + unsigned long result; + if (_BitScanReverse(&result, val)) { + return 31 - result; + } + return 0; +#else + if (val == 0) + return 32; + int32_t result = 8; + uint32_t hi = 0xFFU << 24; + while ((val & hi) == 0) { + hi >>= 8; + result += 8; + } + while (val & hi) { + result -= 1; + hi <<= 1; + } + return result; +#endif +} + +static inline int32_t libdivide_count_leading_zeros64(uint64_t val) { +#if defined(__GNUC__) || \ + __has_builtin(__builtin_clzll) + // Fast way to count leading zeros + return __builtin_clzll(val); +#elif defined(LIBDIVIDE_VC) && defined(_WIN64) + unsigned long result; + if (_BitScanReverse64(&result, val)) { + return 63 - result; + } + return 0; +#else + uint32_t hi = val >> 32; + uint32_t lo = val & 0xFFFFFFFF; + if (hi != 0) return libdivide_count_leading_zeros32(hi); + return 32 + libdivide_count_leading_zeros32(lo); +#endif +} + +// libdivide_64_div_32_to_32: divides a 64-bit uint {u1, u0} by a 32-bit +// uint {v}. The result must fit in 32 bits. +// Returns the quotient directly and the remainder in *r +static inline uint32_t libdivide_64_div_32_to_32(uint32_t u1, uint32_t u0, uint32_t v, uint32_t *r) { +#if (defined(LIBDIVIDE_i386) || defined(LIBDIVIDE_X86_64)) && \ + defined(LIBDIVIDE_GCC_STYLE_ASM) + uint32_t result; + __asm__("divl %[v]" + : "=a"(result), "=d"(*r) + : [v] "r"(v), "a"(u0), "d"(u1) + ); + return result; +#else + uint64_t n = ((uint64_t)u1 << 32) | u0; + uint32_t result = (uint32_t)(n / v); + *r = (uint32_t)(n - result * (uint64_t)v); + return result; +#endif +} + +// libdivide_128_div_64_to_64: divides a 128-bit uint {u1, u0} by a 64-bit +// uint {v}. The result must fit in 64 bits. +// Returns the quotient directly and the remainder in *r +/*static uint64_t libdivide_128_div_64_to_64(uint64_t u1, uint64_t u0, uint64_t v, uint64_t *r) { +#if defined(LIBDIVIDE_X86_64) && \ + defined(LIBDIVIDE_GCC_STYLE_ASM) + uint64_t result; + __asm__("divq %[v]" + : "=a"(result), "=d"(*r) + : [v] "r"(v), "a"(u0), "d"(u1) + ); + return result; +#elif defined(HAS_INT128_T) && \ + defined(HAS_INT128_DIV) + __uint128_t n = ((__uint128_t)u1 << 64) | u0; + uint64_t result = (uint64_t)(n / v); + *r = (uint64_t)(n - result * (__uint128_t)v); + return result; +#else + // Code taken from Hacker's Delight: + // http://www.hackersdelight.org/HDcode/divlu.c. + // License permits inclusion here per: + // http://www.hackersdelight.org/permissions.htm + + const uint64_t b = (1ULL << 32); // Number base (32 bits) + uint64_t un1, un0; // Norm. dividend LSD's + uint64_t vn1, vn0; // Norm. divisor digits + uint64_t q1, q0; // Quotient digits + uint64_t un64, un21, un10; // Dividend digit pairs + uint64_t rhat; // A remainder + int32_t s; // Shift amount for norm + + // If overflow, set rem. to an impossible value, + // and return the largest possible quotient + if (u1 >= v) { + *r = (uint64_t) -1; + return (uint64_t) -1; + } + + // count leading zeros + s = libdivide_count_leading_zeros64(v); + if (s > 0) { + // Normalize divisor + v = v << s; + un64 = (u1 << s) | (u0 >> (64 - s)); + un10 = u0 << s; // Shift dividend left + } else { + // Avoid undefined behavior of (u0 >> 64). + // The behavior is undefined if the right operand is + // negative, or greater than or equal to the length + // in bits of the promoted left operand. + un64 = u1; + un10 = u0; + } + + // Break divisor up into two 32-bit digits + vn1 = v >> 32; + vn0 = v & 0xFFFFFFFF; + + // Break right half of dividend into two digits + un1 = un10 >> 32; + un0 = un10 & 0xFFFFFFFF; + + // Compute the first quotient digit, q1 + q1 = un64 / vn1; + rhat = un64 - q1 * vn1; + + while (q1 >= b || q1 * vn0 > b * rhat + un1) { + q1 = q1 - 1; + rhat = rhat + vn1; + if (rhat >= b) + break; + } + + // Multiply and subtract + un21 = un64 * b + un1 - q1 * v; + + // Compute the second quotient digit + q0 = un21 / vn1; + rhat = un21 - q0 * vn1; + + while (q0 >= b || q0 * vn0 > b * rhat + un0) { + q0 = q0 - 1; + rhat = rhat + vn1; + if (rhat >= b) + break; + } + + *r = (un21 * b + un0 - q0 * v) >> s; + return q1 * b + q0; +#endif +}*/ + +// Bitshift a u128 in place, left (signed_shift > 0) or right (signed_shift < 0) +static inline void libdivide_u128_shift(uint64_t *u1, uint64_t *u0, int32_t signed_shift) { + if (signed_shift > 0) { + uint32_t shift = signed_shift; + *u1 <<= shift; + *u1 |= *u0 >> (64 - shift); + *u0 <<= shift; + } + else if (signed_shift < 0) { + uint32_t shift = -signed_shift; + *u0 >>= shift; + *u0 |= *u1 << (64 - shift); + *u1 >>= shift; + } +} + +// Computes a 128 / 128 -> 64 bit division, with a 128 bit remainder. +/*static uint64_t libdivide_128_div_128_to_64(uint64_t u_hi, uint64_t u_lo, uint64_t v_hi, uint64_t v_lo, uint64_t *r_hi, uint64_t *r_lo) { +#if defined(HAS_INT128_T) && \ + defined(HAS_INT128_DIV) + __uint128_t ufull = u_hi; + __uint128_t vfull = v_hi; + ufull = (ufull << 64) | u_lo; + vfull = (vfull << 64) | v_lo; + uint64_t res = (uint64_t)(ufull / vfull); + __uint128_t remainder = ufull - (vfull * res); + *r_lo = (uint64_t)remainder; + *r_hi = (uint64_t)(remainder >> 64); + return res; +#else + // Adapted from "Unsigned Doubleword Division" in Hacker's Delight + // We want to compute u / v + typedef struct { uint64_t hi; uint64_t lo; } u128_t; + u128_t u = {u_hi, u_lo}; + u128_t v = {v_hi, v_lo}; + + if (v.hi == 0) { + // divisor v is a 64 bit value, so we just need one 128/64 division + // Note that we are simpler than Hacker's Delight here, because we know + // the quotient fits in 64 bits whereas Hacker's Delight demands a full + // 128 bit quotient + *r_hi = 0; + return libdivide_128_div_64_to_64(u.hi, u.lo, v.lo, r_lo); + } + // Here v >= 2**64 + // We know that v.hi != 0, so count leading zeros is OK + // We have 0 <= n <= 63 + uint32_t n = libdivide_count_leading_zeros64(v.hi); + + // Normalize the divisor so its MSB is 1 + u128_t v1t = v; + libdivide_u128_shift(&v1t.hi, &v1t.lo, n); + uint64_t v1 = v1t.hi; // i.e. v1 = v1t >> 64 + + // To ensure no overflow + u128_t u1 = u; + libdivide_u128_shift(&u1.hi, &u1.lo, -1); + + // Get quotient from divide unsigned insn. + uint64_t rem_ignored; + uint64_t q1 = libdivide_128_div_64_to_64(u1.hi, u1.lo, v1, &rem_ignored); + + // Undo normalization and division of u by 2. + u128_t q0 = {0, q1}; + libdivide_u128_shift(&q0.hi, &q0.lo, n); + libdivide_u128_shift(&q0.hi, &q0.lo, -63); + + // Make q0 correct or too small by 1 + // Equivalent to `if (q0 != 0) q0 = q0 - 1;` + if (q0.hi != 0 || q0.lo != 0) { + q0.hi -= (q0.lo == 0); // borrow + q0.lo -= 1; + } + + // Now q0 is correct. + // Compute q0 * v as q0v + // = (q0.hi << 64 + q0.lo) * (v.hi << 64 + v.lo) + // = (q0.hi * v.hi << 128) + (q0.hi * v.lo << 64) + + // (q0.lo * v.hi << 64) + q0.lo * v.lo) + // Each term is 128 bit + // High half of full product (upper 128 bits!) are dropped + u128_t q0v = {0, 0}; + q0v.hi = q0.hi*v.lo + q0.lo*v.hi + libdivide_mullhi_u64(q0.lo, v.lo); + q0v.lo = q0.lo*v.lo; + + // Compute u - q0v as u_q0v + // This is the remainder + u128_t u_q0v = u; + u_q0v.hi -= q0v.hi + (u.lo < q0v.lo); // second term is borrow + u_q0v.lo -= q0v.lo; + + // Check if u_q0v >= v + // This checks if our remainder is larger than the divisor + if ((u_q0v.hi > v.hi) || + (u_q0v.hi == v.hi && u_q0v.lo >= v.lo)) { + // Increment q0 + q0.lo += 1; + q0.hi += (q0.lo == 0); // carry + + // Subtract v from remainder + u_q0v.hi -= v.hi + (u_q0v.lo < v.lo); + u_q0v.lo -= v.lo; + } + + *r_hi = u_q0v.hi; + *r_lo = u_q0v.lo; + + LIBDIVIDE_ASSERT(q0.hi == 0); + return q0.lo; +#endif +}*/ + +////////// UINT32 + +static inline struct libdivide_u32_t libdivide_internal_u32_gen(uint32_t d, int branchfree) { + struct libdivide_u32_t result; + uint32_t floor_log_2_d; + + if (d == 0) { + LIBDIVIDE_ERROR("divider must be != 0"); + } + + floor_log_2_d = 31 - libdivide_count_leading_zeros32(d); + + // Power of 2 + if ((d & (d - 1)) == 0) { + // We need to subtract 1 from the shift value in case of an unsigned + // branchfree divider because there is a hardcoded right shift by 1 + // in its division algorithm. Because of this we also need to add back + // 1 in its recovery algorithm. + result.magic = 0; + result.more = (uint8_t)(floor_log_2_d - (branchfree != 0)); + } else { + uint8_t more; + uint32_t rem, proposed_m; + uint32_t e; + proposed_m = libdivide_64_div_32_to_32(1U << floor_log_2_d, 0, d, &rem); + + LIBDIVIDE_ASSERT(rem > 0 && rem < d); + e = d - rem; + + // This power works if e < 2**floor_log_2_d. + if (!branchfree && (e < (1U << floor_log_2_d))) { + // This power works + more = floor_log_2_d; + } else { + // We have to use the general 33-bit algorithm. We need to compute + // (2**power) / d. However, we already have (2**(power-1))/d and + // its remainder. By doubling both, and then correcting the + // remainder, we can compute the larger division. + // don't care about overflow here - in fact, we expect it + const uint32_t twice_rem = rem + rem; + proposed_m += proposed_m; + if (twice_rem >= d || twice_rem < rem) proposed_m += 1; + more = floor_log_2_d | LIBDIVIDE_ADD_MARKER; + } + result.magic = 1 + proposed_m; + result.more = more; + // result.more's shift should in general be ceil_log_2_d. But if we + // used the smaller power, we subtract one from the shift because we're + // using the smaller power. If we're using the larger power, we + // subtract one from the shift because it's taken care of by the add + // indicator. So floor_log_2_d happens to be correct in both cases. + } + return result; +} + +struct libdivide_u32_t libdivide_u32_gen(uint32_t d) { + return libdivide_internal_u32_gen(d, 0); +} + +/*struct libdivide_u32_branchfree_t libdivide_u32_branchfree_gen(uint32_t d) { + if (d == 1) { + LIBDIVIDE_ERROR("branchfree divider must be != 1"); + } + struct libdivide_u32_t tmp = libdivide_internal_u32_gen(d, 1); + struct libdivide_u32_branchfree_t ret = {tmp.magic, (uint8_t)(tmp.more & LIBDIVIDE_32_SHIFT_MASK)}; + return ret; +}*/ + +uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return numer >> more; + } + else { + uint32_t q = libdivide_mullhi_u32(denom->magic, numer); + if (more & LIBDIVIDE_ADD_MARKER) { + uint32_t t = ((numer - q) >> 1) + q; + return t >> (more & LIBDIVIDE_32_SHIFT_MASK); + } + else { + // All upper bits are 0, + // don't need to mask them off. + return q >> more; + } + } +} + +/*uint32_t libdivide_u32_branchfree_do(uint32_t numer, const struct libdivide_u32_branchfree_t *denom) { + uint32_t q = libdivide_mullhi_u32(denom->magic, numer); + uint32_t t = ((numer - q) >> 1) + q; + return t >> denom->more; +} + +uint32_t libdivide_u32_recover(const struct libdivide_u32_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + + if (!denom->magic) { + return 1U << shift; + } else if (!(more & LIBDIVIDE_ADD_MARKER)) { + // We compute q = n/d = n*m / 2^(32 + shift) + // Therefore we have d = 2^(32 + shift) / m + // We need to ceil it. + // We know d is not a power of 2, so m is not a power of 2, + // so we can just add 1 to the floor + uint32_t hi_dividend = 1U << shift; + uint32_t rem_ignored; + return 1 + libdivide_64_div_32_to_32(hi_dividend, 0, denom->magic, &rem_ignored); + } else { + // Here we wish to compute d = 2^(32+shift+1)/(m+2^32). + // Notice (m + 2^32) is a 33 bit number. Use 64 bit division for now + // Also note that shift may be as high as 31, so shift + 1 will + // overflow. So we have to compute it as 2^(32+shift)/(m+2^32), and + // then double the quotient and remainder. + uint64_t half_n = 1ULL << (32 + shift); + uint64_t d = (1ULL << 32) | denom->magic; + // Note that the quotient is guaranteed <= 32 bits, but the remainder + // may need 33! + uint32_t half_q = (uint32_t)(half_n / d); + uint64_t rem = half_n % d; + // We computed 2^(32+shift)/(m+2^32) + // Need to double it, and then add 1 to the quotient if doubling th + // remainder would increase the quotient. + // Note that rem<<1 cannot overflow, since rem < d and d is 33 bits + uint32_t full_q = half_q + half_q + ((rem<<1) >= d); + + // We rounded down in gen (hence +1) + return full_q + 1; + } +} + +uint32_t libdivide_u32_branchfree_recover(const struct libdivide_u32_branchfree_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + + if (!denom->magic) { + return 1U << (shift + 1); + } else { + // Here we wish to compute d = 2^(32+shift+1)/(m+2^32). + // Notice (m + 2^32) is a 33 bit number. Use 64 bit division for now + // Also note that shift may be as high as 31, so shift + 1 will + // overflow. So we have to compute it as 2^(32+shift)/(m+2^32), and + // then double the quotient and remainder. + uint64_t half_n = 1ULL << (32 + shift); + uint64_t d = (1ULL << 32) | denom->magic; + // Note that the quotient is guaranteed <= 32 bits, but the remainder + // may need 33! + uint32_t half_q = (uint32_t)(half_n / d); + uint64_t rem = half_n % d; + // We computed 2^(32+shift)/(m+2^32) + // Need to double it, and then add 1 to the quotient if doubling th + // remainder would increase the quotient. + // Note that rem<<1 cannot overflow, since rem < d and d is 33 bits + uint32_t full_q = half_q + half_q + ((rem<<1) >= d); + + // We rounded down in gen (hence +1) + return full_q + 1; + } +}*/ + +/////////// UINT64 + +/*static inline struct libdivide_u64_t libdivide_internal_u64_gen(uint64_t d, int branchfree) { + if (d == 0) { + LIBDIVIDE_ERROR("divider must be != 0"); + } + + struct libdivide_u64_t result; + uint32_t floor_log_2_d = 63 - libdivide_count_leading_zeros64(d); + + // Power of 2 + if ((d & (d - 1)) == 0) { + // We need to subtract 1 from the shift value in case of an unsigned + // branchfree divider because there is a hardcoded right shift by 1 + // in its division algorithm. Because of this we also need to add back + // 1 in its recovery algorithm. + result.magic = 0; + result.more = (uint8_t)(floor_log_2_d - (branchfree != 0)); + } else { + uint64_t proposed_m, rem; + uint8_t more; + // (1 << (64 + floor_log_2_d)) / d + proposed_m = libdivide_128_div_64_to_64(1ULL << floor_log_2_d, 0, d, &rem); + + LIBDIVIDE_ASSERT(rem > 0 && rem < d); + const uint64_t e = d - rem; + + // This power works if e < 2**floor_log_2_d. + if (!branchfree && e < (1ULL << floor_log_2_d)) { + // This power works + more = floor_log_2_d; + } else { + // We have to use the general 65-bit algorithm. We need to compute + // (2**power) / d. However, we already have (2**(power-1))/d and + // its remainder. By doubling both, and then correcting the + // remainder, we can compute the larger division. + // don't care about overflow here - in fact, we expect it + proposed_m += proposed_m; + const uint64_t twice_rem = rem + rem; + if (twice_rem >= d || twice_rem < rem) proposed_m += 1; + more = floor_log_2_d | LIBDIVIDE_ADD_MARKER; + } + result.magic = 1 + proposed_m; + result.more = more; + // result.more's shift should in general be ceil_log_2_d. But if we + // used the smaller power, we subtract one from the shift because we're + // using the smaller power. If we're using the larger power, we + // subtract one from the shift because it's taken care of by the add + // indicator. So floor_log_2_d happens to be correct in both cases, + // which is why we do it outside of the if statement. + } + return result; +} + +struct libdivide_u64_t libdivide_u64_gen(uint64_t d) { + return libdivide_internal_u64_gen(d, 0); +} + +struct libdivide_u64_branchfree_t libdivide_u64_branchfree_gen(uint64_t d) { + if (d == 1) { + LIBDIVIDE_ERROR("branchfree divider must be != 1"); + } + struct libdivide_u64_t tmp = libdivide_internal_u64_gen(d, 1); + struct libdivide_u64_branchfree_t ret = {tmp.magic, (uint8_t)(tmp.more & LIBDIVIDE_64_SHIFT_MASK)}; + return ret; +} + +uint64_t libdivide_u64_do(uint64_t numer, const struct libdivide_u64_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return numer >> more; + } + else { + uint64_t q = libdivide_mullhi_u64(denom->magic, numer); + if (more & LIBDIVIDE_ADD_MARKER) { + uint64_t t = ((numer - q) >> 1) + q; + return t >> (more & LIBDIVIDE_64_SHIFT_MASK); + } + else { + // All upper bits are 0, + // don't need to mask them off. + return q >> more; + } + } +} + +uint64_t libdivide_u64_branchfree_do(uint64_t numer, const struct libdivide_u64_branchfree_t *denom) { + uint64_t q = libdivide_mullhi_u64(denom->magic, numer); + uint64_t t = ((numer - q) >> 1) + q; + return t >> denom->more; +} + +uint64_t libdivide_u64_recover(const struct libdivide_u64_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + + if (!denom->magic) { + return 1ULL << shift; + } else if (!(more & LIBDIVIDE_ADD_MARKER)) { + // We compute q = n/d = n*m / 2^(64 + shift) + // Therefore we have d = 2^(64 + shift) / m + // We need to ceil it. + // We know d is not a power of 2, so m is not a power of 2, + // so we can just add 1 to the floor + uint64_t hi_dividend = 1ULL << shift; + uint64_t rem_ignored; + return 1 + libdivide_128_div_64_to_64(hi_dividend, 0, denom->magic, &rem_ignored); + } else { + // Here we wish to compute d = 2^(64+shift+1)/(m+2^64). + // Notice (m + 2^64) is a 65 bit number. This gets hairy. See + // libdivide_u32_recover for more on what we do here. + // TODO: do something better than 128 bit math + + // Full n is a (potentially) 129 bit value + // half_n is a 128 bit value + // Compute the hi half of half_n. Low half is 0. + uint64_t half_n_hi = 1ULL << shift, half_n_lo = 0; + // d is a 65 bit value. The high bit is always set to 1. + const uint64_t d_hi = 1, d_lo = denom->magic; + // Note that the quotient is guaranteed <= 64 bits, + // but the remainder may need 65! + uint64_t r_hi, r_lo; + uint64_t half_q = libdivide_128_div_128_to_64(half_n_hi, half_n_lo, d_hi, d_lo, &r_hi, &r_lo); + // We computed 2^(64+shift)/(m+2^64) + // Double the remainder ('dr') and check if that is larger than d + // Note that d is a 65 bit value, so r1 is small and so r1 + r1 + // cannot overflow + uint64_t dr_lo = r_lo + r_lo; + uint64_t dr_hi = r_hi + r_hi + (dr_lo < r_lo); // last term is carry + int dr_exceeds_d = (dr_hi > d_hi) || (dr_hi == d_hi && dr_lo >= d_lo); + uint64_t full_q = half_q + half_q + (dr_exceeds_d ? 1 : 0); + return full_q + 1; + } +} + +uint64_t libdivide_u64_branchfree_recover(const struct libdivide_u64_branchfree_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + + if (!denom->magic) { + return 1ULL << (shift + 1); + } else { + // Here we wish to compute d = 2^(64+shift+1)/(m+2^64). + // Notice (m + 2^64) is a 65 bit number. This gets hairy. See + // libdivide_u32_recover for more on what we do here. + // TODO: do something better than 128 bit math + + // Full n is a (potentially) 129 bit value + // half_n is a 128 bit value + // Compute the hi half of half_n. Low half is 0. + uint64_t half_n_hi = 1ULL << shift, half_n_lo = 0; + // d is a 65 bit value. The high bit is always set to 1. + const uint64_t d_hi = 1, d_lo = denom->magic; + // Note that the quotient is guaranteed <= 64 bits, + // but the remainder may need 65! + uint64_t r_hi, r_lo; + uint64_t half_q = libdivide_128_div_128_to_64(half_n_hi, half_n_lo, d_hi, d_lo, &r_hi, &r_lo); + // We computed 2^(64+shift)/(m+2^64) + // Double the remainder ('dr') and check if that is larger than d + // Note that d is a 65 bit value, so r1 is small and so r1 + r1 + // cannot overflow + uint64_t dr_lo = r_lo + r_lo; + uint64_t dr_hi = r_hi + r_hi + (dr_lo < r_lo); // last term is carry + int dr_exceeds_d = (dr_hi > d_hi) || (dr_hi == d_hi && dr_lo >= d_lo); + uint64_t full_q = half_q + half_q + (dr_exceeds_d ? 1 : 0); + return full_q + 1; + } +}*/ + +/////////// SINT32 + +/*static inline struct libdivide_s32_t libdivide_internal_s32_gen(int32_t d, int branchfree) { + if (d == 0) { + LIBDIVIDE_ERROR("divider must be != 0"); + } + + struct libdivide_s32_t result; + + // If d is a power of 2, or negative a power of 2, we have to use a shift. + // This is especially important because the magic algorithm fails for -1. + // To check if d is a power of 2 or its inverse, it suffices to check + // whether its absolute value has exactly one bit set. This works even for + // INT_MIN, because abs(INT_MIN) == INT_MIN, and INT_MIN has one bit set + // and is a power of 2. + uint32_t ud = (uint32_t)d; + uint32_t absD = (d < 0) ? -ud : ud; + uint32_t floor_log_2_d = 31 - libdivide_count_leading_zeros32(absD); + // check if exactly one bit is set, + // don't care if absD is 0 since that's divide by zero + if ((absD & (absD - 1)) == 0) { + // Branchfree and normal paths are exactly the same + result.magic = 0; + result.more = floor_log_2_d | (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0); + } else { + LIBDIVIDE_ASSERT(floor_log_2_d >= 1); + + uint8_t more; + // the dividend here is 2**(floor_log_2_d + 31), so the low 32 bit word + // is 0 and the high word is floor_log_2_d - 1 + uint32_t rem, proposed_m; + proposed_m = libdivide_64_div_32_to_32(1U << (floor_log_2_d - 1), 0, absD, &rem); + const uint32_t e = absD - rem; + + // We are going to start with a power of floor_log_2_d - 1. + // This works if works if e < 2**floor_log_2_d. + if (!branchfree && e < (1U << floor_log_2_d)) { + // This power works + more = floor_log_2_d - 1; + } else { + // We need to go one higher. This should not make proposed_m + // overflow, but it will make it negative when interpreted as an + // int32_t. + proposed_m += proposed_m; + const uint32_t twice_rem = rem + rem; + if (twice_rem >= absD || twice_rem < rem) proposed_m += 1; + more = floor_log_2_d | LIBDIVIDE_ADD_MARKER; + } + + proposed_m += 1; + int32_t magic = (int32_t)proposed_m; + + // Mark if we are negative. Note we only negate the magic number in the + // branchfull case. + if (d < 0) { + more |= LIBDIVIDE_NEGATIVE_DIVISOR; + if (!branchfree) { + magic = -magic; + } + } + + result.more = more; + result.magic = magic; + } + return result; +} + +struct libdivide_s32_t libdivide_s32_gen(int32_t d) { + return libdivide_internal_s32_gen(d, 0); +} + +struct libdivide_s32_branchfree_t libdivide_s32_branchfree_gen(int32_t d) { + struct libdivide_s32_t tmp = libdivide_internal_s32_gen(d, 1); + struct libdivide_s32_branchfree_t result = {tmp.magic, tmp.more}; + return result; +} + +int32_t libdivide_s32_do(int32_t numer, const struct libdivide_s32_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + + if (!denom->magic) { + uint32_t sign = (int8_t)more >> 7; + uint32_t mask = (1U << shift) - 1; + uint32_t uq = numer + ((numer >> 31) & mask); + int32_t q = (int32_t)uq; + q >>= shift; + q = (q ^ sign) - sign; + return q; + } else { + uint32_t uq = (uint32_t)libdivide_mullhi_s32(denom->magic, numer); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift and then sign extend + int32_t sign = (int8_t)more >> 7; + // q += (more < 0 ? -numer : numer) + // cast required to avoid UB + uq += ((uint32_t)numer ^ sign) - sign; + } + int32_t q = (int32_t)uq; + q >>= shift; + q += (q < 0); + return q; + } +} + +int32_t libdivide_s32_branchfree_do(int32_t numer, const struct libdivide_s32_branchfree_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + // must be arithmetic shift and then sign extend + int32_t sign = (int8_t)more >> 7; + int32_t magic = denom->magic; + int32_t q = libdivide_mullhi_s32(magic, numer); + q += numer; + + // If q is non-negative, we have nothing to do + // If q is negative, we want to add either (2**shift)-1 if d is a power of + // 2, or (2**shift) if it is not a power of 2 + uint32_t is_power_of_2 = (magic == 0); + uint32_t q_sign = (uint32_t)(q >> 31); + q += q_sign & ((1U << shift) - is_power_of_2); + + // Now arithmetic right shift + q >>= shift; + // Negate if needed + q = (q ^ sign) - sign; + + return q; +} + +int32_t libdivide_s32_recover(const struct libdivide_s32_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + if (!denom->magic) { + uint32_t absD = 1U << shift; + if (more & LIBDIVIDE_NEGATIVE_DIVISOR) { + absD = -absD; + } + return (int32_t)absD; + } else { + // Unsigned math is much easier + // We negate the magic number only in the branchfull case, and we don't + // know which case we're in. However we have enough information to + // determine the correct sign of the magic number. The divisor was + // negative if LIBDIVIDE_NEGATIVE_DIVISOR is set. If ADD_MARKER is set, + // the magic number's sign is opposite that of the divisor. + // We want to compute the positive magic number. + int negative_divisor = (more & LIBDIVIDE_NEGATIVE_DIVISOR); + int magic_was_negated = (more & LIBDIVIDE_ADD_MARKER) + ? denom->magic > 0 : denom->magic < 0; + + // Handle the power of 2 case (including branchfree) + if (denom->magic == 0) { + int32_t result = 1U << shift; + return negative_divisor ? -result : result; + } + + uint32_t d = (uint32_t)(magic_was_negated ? -denom->magic : denom->magic); + uint64_t n = 1ULL << (32 + shift); // this shift cannot exceed 30 + uint32_t q = (uint32_t)(n / d); + int32_t result = (int32_t)q; + result += 1; + return negative_divisor ? -result : result; + } +} + +int32_t libdivide_s32_branchfree_recover(const struct libdivide_s32_branchfree_t *denom) { + return libdivide_s32_recover((const struct libdivide_s32_t *)denom); +}*/ + +///////////// SINT64 + +/*static inline struct libdivide_s64_t libdivide_internal_s64_gen(int64_t d, int branchfree) { + if (d == 0) { + LIBDIVIDE_ERROR("divider must be != 0"); + } + + struct libdivide_s64_t result; + + // If d is a power of 2, or negative a power of 2, we have to use a shift. + // This is especially important because the magic algorithm fails for -1. + // To check if d is a power of 2 or its inverse, it suffices to check + // whether its absolute value has exactly one bit set. This works even for + // INT_MIN, because abs(INT_MIN) == INT_MIN, and INT_MIN has one bit set + // and is a power of 2. + uint64_t ud = (uint64_t)d; + uint64_t absD = (d < 0) ? -ud : ud; + uint32_t floor_log_2_d = 63 - libdivide_count_leading_zeros64(absD); + // check if exactly one bit is set, + // don't care if absD is 0 since that's divide by zero + if ((absD & (absD - 1)) == 0) { + // Branchfree and non-branchfree cases are the same + result.magic = 0; + result.more = floor_log_2_d | (d < 0 ? LIBDIVIDE_NEGATIVE_DIVISOR : 0); + } else { + // the dividend here is 2**(floor_log_2_d + 63), so the low 64 bit word + // is 0 and the high word is floor_log_2_d - 1 + uint8_t more; + uint64_t rem, proposed_m; + proposed_m = libdivide_128_div_64_to_64(1ULL << (floor_log_2_d - 1), 0, absD, &rem); + const uint64_t e = absD - rem; + + // We are going to start with a power of floor_log_2_d - 1. + // This works if works if e < 2**floor_log_2_d. + if (!branchfree && e < (1ULL << floor_log_2_d)) { + // This power works + more = floor_log_2_d - 1; + } else { + // We need to go one higher. This should not make proposed_m + // overflow, but it will make it negative when interpreted as an + // int32_t. + proposed_m += proposed_m; + const uint64_t twice_rem = rem + rem; + if (twice_rem >= absD || twice_rem < rem) proposed_m += 1; + // note that we only set the LIBDIVIDE_NEGATIVE_DIVISOR bit if we + // also set ADD_MARKER this is an annoying optimization that + // enables algorithm #4 to avoid the mask. However we always set it + // in the branchfree case + more = floor_log_2_d | LIBDIVIDE_ADD_MARKER; + } + proposed_m += 1; + int64_t magic = (int64_t)proposed_m; + + // Mark if we are negative + if (d < 0) { + more |= LIBDIVIDE_NEGATIVE_DIVISOR; + if (!branchfree) { + magic = -magic; + } + } + + result.more = more; + result.magic = magic; + } + return result; +} + +struct libdivide_s64_t libdivide_s64_gen(int64_t d) { + return libdivide_internal_s64_gen(d, 0); +} + +struct libdivide_s64_branchfree_t libdivide_s64_branchfree_gen(int64_t d) { + struct libdivide_s64_t tmp = libdivide_internal_s64_gen(d, 1); + struct libdivide_s64_branchfree_t ret = {tmp.magic, tmp.more}; + return ret; +} + +int64_t libdivide_s64_do(int64_t numer, const struct libdivide_s64_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + + if (!denom->magic) { // shift path + uint64_t mask = (1ULL << shift) - 1; + uint64_t uq = numer + ((numer >> 63) & mask); + int64_t q = (int64_t)uq; + q >>= shift; + // must be arithmetic shift and then sign-extend + int64_t sign = (int8_t)more >> 7; + q = (q ^ sign) - sign; + return q; + } else { + uint64_t uq = (uint64_t)libdivide_mullhi_s64(denom->magic, numer); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift and then sign extend + int64_t sign = (int8_t)more >> 7; + // q += (more < 0 ? -numer : numer) + // cast required to avoid UB + uq += ((uint64_t)numer ^ sign) - sign; + } + int64_t q = (int64_t)uq; + q >>= shift; + q += (q < 0); + return q; + } +} + +int64_t libdivide_s64_branchfree_do(int64_t numer, const struct libdivide_s64_branchfree_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + // must be arithmetic shift and then sign extend + int64_t sign = (int8_t)more >> 7; + int64_t magic = denom->magic; + int64_t q = libdivide_mullhi_s64(magic, numer); + q += numer; + + // If q is non-negative, we have nothing to do. + // If q is negative, we want to add either (2**shift)-1 if d is a power of + // 2, or (2**shift) if it is not a power of 2. + uint64_t is_power_of_2 = (magic == 0); + uint64_t q_sign = (uint64_t)(q >> 63); + q += q_sign & ((1ULL << shift) - is_power_of_2); + + // Arithmetic right shift + q >>= shift; + // Negate if needed + q = (q ^ sign) - sign; + + return q; +} + +int64_t libdivide_s64_recover(const struct libdivide_s64_t *denom) { + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + if (denom->magic == 0) { // shift path + uint64_t absD = 1ULL << shift; + if (more & LIBDIVIDE_NEGATIVE_DIVISOR) { + absD = -absD; + } + return (int64_t)absD; + } else { + // Unsigned math is much easier + int negative_divisor = (more & LIBDIVIDE_NEGATIVE_DIVISOR); + int magic_was_negated = (more & LIBDIVIDE_ADD_MARKER) + ? denom->magic > 0 : denom->magic < 0; + + uint64_t d = (uint64_t)(magic_was_negated ? -denom->magic : denom->magic); + uint64_t n_hi = 1ULL << shift, n_lo = 0; + uint64_t rem_ignored; + uint64_t q = libdivide_128_div_64_to_64(n_hi, n_lo, d, &rem_ignored); + int64_t result = (int64_t)(q + 1); + if (negative_divisor) { + result = -result; + } + return result; + } +} + +int64_t libdivide_s64_branchfree_recover(const struct libdivide_s64_branchfree_t *denom) { + return libdivide_s64_recover((const struct libdivide_s64_t *)denom); +}*/ + +#if defined(LIBDIVIDE_AVX512) + +static inline __m512i libdivide_u32_do_vector(__m512i numers, const struct libdivide_u32_t *denom); +static inline __m512i libdivide_s32_do_vector(__m512i numers, const struct libdivide_s32_t *denom); +static inline __m512i libdivide_u64_do_vector(__m512i numers, const struct libdivide_u64_t *denom); +static inline __m512i libdivide_s64_do_vector(__m512i numers, const struct libdivide_s64_t *denom); + +static inline __m512i libdivide_u32_branchfree_do_vector(__m512i numers, const struct libdivide_u32_branchfree_t *denom); +static inline __m512i libdivide_s32_branchfree_do_vector(__m512i numers, const struct libdivide_s32_branchfree_t *denom); +static inline __m512i libdivide_u64_branchfree_do_vector(__m512i numers, const struct libdivide_u64_branchfree_t *denom); +static inline __m512i libdivide_s64_branchfree_do_vector(__m512i numers, const struct libdivide_s64_branchfree_t *denom); + +//////// Internal Utility Functions + +static inline __m512i libdivide_s64_signbits(__m512i v) {; + return _mm512_srai_epi64(v, 63); +} + +static inline __m512i libdivide_s64_shift_right_vector(__m512i v, int amt) { + return _mm512_srai_epi64(v, amt); +} + +// Here, b is assumed to contain one 32-bit value repeated. +static inline __m512i libdivide_mullhi_u32_vector(__m512i a, __m512i b) { + __m512i hi_product_0Z2Z = _mm512_srli_epi64(_mm512_mul_epu32(a, b), 32); + __m512i a1X3X = _mm512_srli_epi64(a, 32); + __m512i mask = _mm512_set_epi32(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0); + __m512i hi_product_Z1Z3 = _mm512_and_si512(_mm512_mul_epu32(a1X3X, b), mask); + return _mm512_or_si512(hi_product_0Z2Z, hi_product_Z1Z3); +} + +// b is one 32-bit value repeated. +static inline __m512i libdivide_mullhi_s32_vector(__m512i a, __m512i b) { + __m512i hi_product_0Z2Z = _mm512_srli_epi64(_mm512_mul_epi32(a, b), 32); + __m512i a1X3X = _mm512_srli_epi64(a, 32); + __m512i mask = _mm512_set_epi32(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0); + __m512i hi_product_Z1Z3 = _mm512_and_si512(_mm512_mul_epi32(a1X3X, b), mask); + return _mm512_or_si512(hi_product_0Z2Z, hi_product_Z1Z3); +} + +// Here, y is assumed to contain one 64-bit value repeated. +// https://stackoverflow.com/a/28827013 +static inline __m512i libdivide_mullhi_u64_vector(__m512i x, __m512i y) { + __m512i lomask = _mm512_set1_epi64(0xffffffff); + __m512i xh = _mm512_shuffle_epi32(x, (_MM_PERM_ENUM) 0xB1); + __m512i yh = _mm512_shuffle_epi32(y, (_MM_PERM_ENUM) 0xB1); + __m512i w0 = _mm512_mul_epu32(x, y); + __m512i w1 = _mm512_mul_epu32(x, yh); + __m512i w2 = _mm512_mul_epu32(xh, y); + __m512i w3 = _mm512_mul_epu32(xh, yh); + __m512i w0h = _mm512_srli_epi64(w0, 32); + __m512i s1 = _mm512_add_epi64(w1, w0h); + __m512i s1l = _mm512_and_si512(s1, lomask); + __m512i s1h = _mm512_srli_epi64(s1, 32); + __m512i s2 = _mm512_add_epi64(w2, s1l); + __m512i s2h = _mm512_srli_epi64(s2, 32); + __m512i hi = _mm512_add_epi64(w3, s1h); + hi = _mm512_add_epi64(hi, s2h); + + return hi; +} + +// y is one 64-bit value repeated. +static inline __m512i libdivide_mullhi_s64_vector(__m512i x, __m512i y) { + __m512i p = libdivide_mullhi_u64_vector(x, y); + __m512i t1 = _mm512_and_si512(libdivide_s64_signbits(x), y); + __m512i t2 = _mm512_and_si512(libdivide_s64_signbits(y), x); + p = _mm512_sub_epi64(p, t1); + p = _mm512_sub_epi64(p, t2); + return p; +} + +////////// UINT32 + +__m512i libdivide_u32_do_vector(__m512i numers, const struct libdivide_u32_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return _mm512_srli_epi32(numers, more); + } + else { + __m512i q = libdivide_mullhi_u32_vector(numers, _mm512_set1_epi32(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // uint32_t t = ((numer - q) >> 1) + q; + // return t >> denom->shift; + uint32_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + __m512i t = _mm512_add_epi32(_mm512_srli_epi32(_mm512_sub_epi32(numers, q), 1), q); + return _mm512_srli_epi32(t, shift); + } + else { + return _mm512_srli_epi32(q, more); + } + } +} + +__m512i libdivide_u32_branchfree_do_vector(__m512i numers, const struct libdivide_u32_branchfree_t *denom) { + __m512i q = libdivide_mullhi_u32_vector(numers, _mm512_set1_epi32(denom->magic)); + __m512i t = _mm512_add_epi32(_mm512_srli_epi32(_mm512_sub_epi32(numers, q), 1), q); + return _mm512_srli_epi32(t, denom->more); +} + +////////// UINT64 + +__m512i libdivide_u64_do_vector(__m512i numers, const struct libdivide_u64_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return _mm512_srli_epi64(numers, more); + } + else { + __m512i q = libdivide_mullhi_u64_vector(numers, _mm512_set1_epi64(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // uint32_t t = ((numer - q) >> 1) + q; + // return t >> denom->shift; + uint32_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + __m512i t = _mm512_add_epi64(_mm512_srli_epi64(_mm512_sub_epi64(numers, q), 1), q); + return _mm512_srli_epi64(t, shift); + } + else { + return _mm512_srli_epi64(q, more); + } + } +} + +__m512i libdivide_u64_branchfree_do_vector(__m512i numers, const struct libdivide_u64_branchfree_t *denom) { + __m512i q = libdivide_mullhi_u64_vector(numers, _mm512_set1_epi64(denom->magic)); + __m512i t = _mm512_add_epi64(_mm512_srli_epi64(_mm512_sub_epi64(numers, q), 1), q); + return _mm512_srli_epi64(t, denom->more); +} + +////////// SINT32 + +__m512i libdivide_s32_do_vector(__m512i numers, const struct libdivide_s32_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + uint32_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + uint32_t mask = (1U << shift) - 1; + __m512i roundToZeroTweak = _mm512_set1_epi32(mask); + // q = numer + ((numer >> 31) & roundToZeroTweak); + __m512i q = _mm512_add_epi32(numers, _mm512_and_si512(_mm512_srai_epi32(numers, 31), roundToZeroTweak)); + q = _mm512_srai_epi32(q, shift); + __m512i sign = _mm512_set1_epi32((int8_t)more >> 7); + // q = (q ^ sign) - sign; + q = _mm512_sub_epi32(_mm512_xor_si512(q, sign), sign); + return q; + } + else { + __m512i q = libdivide_mullhi_s32_vector(numers, _mm512_set1_epi32(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift + __m512i sign = _mm512_set1_epi32((int8_t)more >> 7); + // q += ((numer ^ sign) - sign); + q = _mm512_add_epi32(q, _mm512_sub_epi32(_mm512_xor_si512(numers, sign), sign)); + } + // q >>= shift + q = _mm512_srai_epi32(q, more & LIBDIVIDE_32_SHIFT_MASK); + q = _mm512_add_epi32(q, _mm512_srli_epi32(q, 31)); // q += (q < 0) + return q; + } +} + +__m512i libdivide_s32_branchfree_do_vector(__m512i numers, const struct libdivide_s32_branchfree_t *denom) { + int32_t magic = denom->magic; + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + // must be arithmetic shift + __m512i sign = _mm512_set1_epi32((int8_t)more >> 7); + __m512i q = libdivide_mullhi_s32_vector(numers, _mm512_set1_epi32(magic)); + q = _mm512_add_epi32(q, numers); // q += numers + + // If q is non-negative, we have nothing to do + // If q is negative, we want to add either (2**shift)-1 if d is + // a power of 2, or (2**shift) if it is not a power of 2 + uint32_t is_power_of_2 = (magic == 0); + __m512i q_sign = _mm512_srai_epi32(q, 31); // q_sign = q >> 31 + __m512i mask = _mm512_set1_epi32((1U << shift) - is_power_of_2); + q = _mm512_add_epi32(q, _mm512_and_si512(q_sign, mask)); // q = q + (q_sign & mask) + q = _mm512_srai_epi32(q, shift); // q >>= shift + q = _mm512_sub_epi32(_mm512_xor_si512(q, sign), sign); // q = (q ^ sign) - sign + return q; +} + +////////// SINT64 + +__m512i libdivide_s64_do_vector(__m512i numers, const struct libdivide_s64_t *denom) { + uint8_t more = denom->more; + int64_t magic = denom->magic; + if (magic == 0) { // shift path + uint32_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + uint64_t mask = (1ULL << shift) - 1; + __m512i roundToZeroTweak = _mm512_set1_epi64(mask); + // q = numer + ((numer >> 63) & roundToZeroTweak); + __m512i q = _mm512_add_epi64(numers, _mm512_and_si512(libdivide_s64_signbits(numers), roundToZeroTweak)); + q = libdivide_s64_shift_right_vector(q, shift); + __m512i sign = _mm512_set1_epi32((int8_t)more >> 7); + // q = (q ^ sign) - sign; + q = _mm512_sub_epi64(_mm512_xor_si512(q, sign), sign); + return q; + } + else { + __m512i q = libdivide_mullhi_s64_vector(numers, _mm512_set1_epi64(magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift + __m512i sign = _mm512_set1_epi32((int8_t)more >> 7); + // q += ((numer ^ sign) - sign); + q = _mm512_add_epi64(q, _mm512_sub_epi64(_mm512_xor_si512(numers, sign), sign)); + } + // q >>= denom->mult_path.shift + q = libdivide_s64_shift_right_vector(q, more & LIBDIVIDE_64_SHIFT_MASK); + q = _mm512_add_epi64(q, _mm512_srli_epi64(q, 63)); // q += (q < 0) + return q; + } +} + +__m512i libdivide_s64_branchfree_do_vector(__m512i numers, const struct libdivide_s64_branchfree_t *denom) { + int64_t magic = denom->magic; + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + // must be arithmetic shift + __m512i sign = _mm512_set1_epi32((int8_t)more >> 7); + + // libdivide_mullhi_s64(numers, magic); + __m512i q = libdivide_mullhi_s64_vector(numers, _mm512_set1_epi64(magic)); + q = _mm512_add_epi64(q, numers); // q += numers + + // If q is non-negative, we have nothing to do. + // If q is negative, we want to add either (2**shift)-1 if d is + // a power of 2, or (2**shift) if it is not a power of 2. + uint32_t is_power_of_2 = (magic == 0); + __m512i q_sign = libdivide_s64_signbits(q); // q_sign = q >> 63 + __m512i mask = _mm512_set1_epi64((1ULL << shift) - is_power_of_2); + q = _mm512_add_epi64(q, _mm512_and_si512(q_sign, mask)); // q = q + (q_sign & mask) + q = libdivide_s64_shift_right_vector(q, shift); // q >>= shift + q = _mm512_sub_epi64(_mm512_xor_si512(q, sign), sign); // q = (q ^ sign) - sign + return q; +} + +#elif defined(LIBDIVIDE_AVX2) + +static inline __m256i libdivide_u32_do_vector(__m256i numers, const struct libdivide_u32_t *denom); +static inline __m256i libdivide_s32_do_vector(__m256i numers, const struct libdivide_s32_t *denom); +static inline __m256i libdivide_u64_do_vector(__m256i numers, const struct libdivide_u64_t *denom); +static inline __m256i libdivide_s64_do_vector(__m256i numers, const struct libdivide_s64_t *denom); + +static inline __m256i libdivide_u32_branchfree_do_vector(__m256i numers, const struct libdivide_u32_branchfree_t *denom); +static inline __m256i libdivide_s32_branchfree_do_vector(__m256i numers, const struct libdivide_s32_branchfree_t *denom); +static inline __m256i libdivide_u64_branchfree_do_vector(__m256i numers, const struct libdivide_u64_branchfree_t *denom); +static inline __m256i libdivide_s64_branchfree_do_vector(__m256i numers, const struct libdivide_s64_branchfree_t *denom); + +//////// Internal Utility Functions + +// Implementation of _mm256_srai_epi64(v, 63) (from AVX512). +static inline __m256i libdivide_s64_signbits(__m256i v) { + __m256i hiBitsDuped = _mm256_shuffle_epi32(v, _MM_SHUFFLE(3, 3, 1, 1)); + __m256i signBits = _mm256_srai_epi32(hiBitsDuped, 31); + return signBits; +} + +// Implementation of _mm256_srai_epi64 (from AVX512). +static inline __m256i libdivide_s64_shift_right_vector(__m256i v, int amt) { + const int b = 64 - amt; + __m256i m = _mm256_set1_epi64x(1ULL << (b - 1)); + __m256i x = _mm256_srli_epi64(v, amt); + __m256i result = _mm256_sub_epi64(_mm256_xor_si256(x, m), m); + return result; +} + +// Here, b is assumed to contain one 32-bit value repeated. +static inline __m256i libdivide_mullhi_u32_vector(__m256i a, __m256i b) { + __m256i hi_product_0Z2Z = _mm256_srli_epi64(_mm256_mul_epu32(a, b), 32); + __m256i a1X3X = _mm256_srli_epi64(a, 32); + __m256i mask = _mm256_set_epi32(-1, 0, -1, 0, -1, 0, -1, 0); + __m256i hi_product_Z1Z3 = _mm256_and_si256(_mm256_mul_epu32(a1X3X, b), mask); + return _mm256_or_si256(hi_product_0Z2Z, hi_product_Z1Z3); +} + +// b is one 32-bit value repeated. +static inline __m256i libdivide_mullhi_s32_vector(__m256i a, __m256i b) { + __m256i hi_product_0Z2Z = _mm256_srli_epi64(_mm256_mul_epi32(a, b), 32); + __m256i a1X3X = _mm256_srli_epi64(a, 32); + __m256i mask = _mm256_set_epi32(-1, 0, -1, 0, -1, 0, -1, 0); + __m256i hi_product_Z1Z3 = _mm256_and_si256(_mm256_mul_epi32(a1X3X, b), mask); + return _mm256_or_si256(hi_product_0Z2Z, hi_product_Z1Z3); +} + +// Here, y is assumed to contain one 64-bit value repeated. +// https://stackoverflow.com/a/28827013 +static inline __m256i libdivide_mullhi_u64_vector(__m256i x, __m256i y) { + __m256i lomask = _mm256_set1_epi64x(0xffffffff); + __m256i xh = _mm256_shuffle_epi32(x, 0xB1); // x0l, x0h, x1l, x1h + __m256i yh = _mm256_shuffle_epi32(y, 0xB1); // y0l, y0h, y1l, y1h + __m256i w0 = _mm256_mul_epu32(x, y); // x0l*y0l, x1l*y1l + __m256i w1 = _mm256_mul_epu32(x, yh); // x0l*y0h, x1l*y1h + __m256i w2 = _mm256_mul_epu32(xh, y); // x0h*y0l, x1h*y0l + __m256i w3 = _mm256_mul_epu32(xh, yh); // x0h*y0h, x1h*y1h + __m256i w0h = _mm256_srli_epi64(w0, 32); + __m256i s1 = _mm256_add_epi64(w1, w0h); + __m256i s1l = _mm256_and_si256(s1, lomask); + __m256i s1h = _mm256_srli_epi64(s1, 32); + __m256i s2 = _mm256_add_epi64(w2, s1l); + __m256i s2h = _mm256_srli_epi64(s2, 32); + __m256i hi = _mm256_add_epi64(w3, s1h); + hi = _mm256_add_epi64(hi, s2h); + + return hi; +} + +// y is one 64-bit value repeated. +static inline __m256i libdivide_mullhi_s64_vector(__m256i x, __m256i y) { + __m256i p = libdivide_mullhi_u64_vector(x, y); + __m256i t1 = _mm256_and_si256(libdivide_s64_signbits(x), y); + __m256i t2 = _mm256_and_si256(libdivide_s64_signbits(y), x); + p = _mm256_sub_epi64(p, t1); + p = _mm256_sub_epi64(p, t2); + return p; +} + +////////// UINT32 + +__m256i libdivide_u32_do_vector(__m256i numers, const struct libdivide_u32_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return _mm256_srli_epi32(numers, more); + } + else { + __m256i q = libdivide_mullhi_u32_vector(numers, _mm256_set1_epi32(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // uint32_t t = ((numer - q) >> 1) + q; + // return t >> denom->shift; + uint32_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + __m256i t = _mm256_add_epi32(_mm256_srli_epi32(_mm256_sub_epi32(numers, q), 1), q); + return _mm256_srli_epi32(t, shift); + } + else { + return _mm256_srli_epi32(q, more); + } + } +} + +__m256i libdivide_u32_branchfree_do_vector(__m256i numers, const struct libdivide_u32_branchfree_t *denom) { + __m256i q = libdivide_mullhi_u32_vector(numers, _mm256_set1_epi32(denom->magic)); + __m256i t = _mm256_add_epi32(_mm256_srli_epi32(_mm256_sub_epi32(numers, q), 1), q); + return _mm256_srli_epi32(t, denom->more); +} + +////////// UINT64 + +__m256i libdivide_u64_do_vector(__m256i numers, const struct libdivide_u64_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return _mm256_srli_epi64(numers, more); + } + else { + __m256i q = libdivide_mullhi_u64_vector(numers, _mm256_set1_epi64x(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // uint32_t t = ((numer - q) >> 1) + q; + // return t >> denom->shift; + uint32_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + __m256i t = _mm256_add_epi64(_mm256_srli_epi64(_mm256_sub_epi64(numers, q), 1), q); + return _mm256_srli_epi64(t, shift); + } + else { + return _mm256_srli_epi64(q, more); + } + } +} + +__m256i libdivide_u64_branchfree_do_vector(__m256i numers, const struct libdivide_u64_branchfree_t *denom) { + __m256i q = libdivide_mullhi_u64_vector(numers, _mm256_set1_epi64x(denom->magic)); + __m256i t = _mm256_add_epi64(_mm256_srli_epi64(_mm256_sub_epi64(numers, q), 1), q); + return _mm256_srli_epi64(t, denom->more); +} + +////////// SINT32 + +__m256i libdivide_s32_do_vector(__m256i numers, const struct libdivide_s32_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + uint32_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + uint32_t mask = (1U << shift) - 1; + __m256i roundToZeroTweak = _mm256_set1_epi32(mask); + // q = numer + ((numer >> 31) & roundToZeroTweak); + __m256i q = _mm256_add_epi32(numers, _mm256_and_si256(_mm256_srai_epi32(numers, 31), roundToZeroTweak)); + q = _mm256_srai_epi32(q, shift); + __m256i sign = _mm256_set1_epi32((int8_t)more >> 7); + // q = (q ^ sign) - sign; + q = _mm256_sub_epi32(_mm256_xor_si256(q, sign), sign); + return q; + } + else { + __m256i q = libdivide_mullhi_s32_vector(numers, _mm256_set1_epi32(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift + __m256i sign = _mm256_set1_epi32((int8_t)more >> 7); + // q += ((numer ^ sign) - sign); + q = _mm256_add_epi32(q, _mm256_sub_epi32(_mm256_xor_si256(numers, sign), sign)); + } + // q >>= shift + q = _mm256_srai_epi32(q, more & LIBDIVIDE_32_SHIFT_MASK); + q = _mm256_add_epi32(q, _mm256_srli_epi32(q, 31)); // q += (q < 0) + return q; + } +} + +__m256i libdivide_s32_branchfree_do_vector(__m256i numers, const struct libdivide_s32_branchfree_t *denom) { + int32_t magic = denom->magic; + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + // must be arithmetic shift + __m256i sign = _mm256_set1_epi32((int8_t)more >> 7); + __m256i q = libdivide_mullhi_s32_vector(numers, _mm256_set1_epi32(magic)); + q = _mm256_add_epi32(q, numers); // q += numers + + // If q is non-negative, we have nothing to do + // If q is negative, we want to add either (2**shift)-1 if d is + // a power of 2, or (2**shift) if it is not a power of 2 + uint32_t is_power_of_2 = (magic == 0); + __m256i q_sign = _mm256_srai_epi32(q, 31); // q_sign = q >> 31 + __m256i mask = _mm256_set1_epi32((1U << shift) - is_power_of_2); + q = _mm256_add_epi32(q, _mm256_and_si256(q_sign, mask)); // q = q + (q_sign & mask) + q = _mm256_srai_epi32(q, shift); // q >>= shift + q = _mm256_sub_epi32(_mm256_xor_si256(q, sign), sign); // q = (q ^ sign) - sign + return q; +} + +////////// SINT64 + +__m256i libdivide_s64_do_vector(__m256i numers, const struct libdivide_s64_t *denom) { + uint8_t more = denom->more; + int64_t magic = denom->magic; + if (magic == 0) { // shift path + uint32_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + uint64_t mask = (1ULL << shift) - 1; + __m256i roundToZeroTweak = _mm256_set1_epi64x(mask); + // q = numer + ((numer >> 63) & roundToZeroTweak); + __m256i q = _mm256_add_epi64(numers, _mm256_and_si256(libdivide_s64_signbits(numers), roundToZeroTweak)); + q = libdivide_s64_shift_right_vector(q, shift); + __m256i sign = _mm256_set1_epi32((int8_t)more >> 7); + // q = (q ^ sign) - sign; + q = _mm256_sub_epi64(_mm256_xor_si256(q, sign), sign); + return q; + } + else { + __m256i q = libdivide_mullhi_s64_vector(numers, _mm256_set1_epi64x(magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift + __m256i sign = _mm256_set1_epi32((int8_t)more >> 7); + // q += ((numer ^ sign) - sign); + q = _mm256_add_epi64(q, _mm256_sub_epi64(_mm256_xor_si256(numers, sign), sign)); + } + // q >>= denom->mult_path.shift + q = libdivide_s64_shift_right_vector(q, more & LIBDIVIDE_64_SHIFT_MASK); + q = _mm256_add_epi64(q, _mm256_srli_epi64(q, 63)); // q += (q < 0) + return q; + } +} + +__m256i libdivide_s64_branchfree_do_vector(__m256i numers, const struct libdivide_s64_branchfree_t *denom) { + int64_t magic = denom->magic; + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + // must be arithmetic shift + __m256i sign = _mm256_set1_epi32((int8_t)more >> 7); + + // libdivide_mullhi_s64(numers, magic); + __m256i q = libdivide_mullhi_s64_vector(numers, _mm256_set1_epi64x(magic)); + q = _mm256_add_epi64(q, numers); // q += numers + + // If q is non-negative, we have nothing to do. + // If q is negative, we want to add either (2**shift)-1 if d is + // a power of 2, or (2**shift) if it is not a power of 2. + uint32_t is_power_of_2 = (magic == 0); + __m256i q_sign = libdivide_s64_signbits(q); // q_sign = q >> 63 + __m256i mask = _mm256_set1_epi64x((1ULL << shift) - is_power_of_2); + q = _mm256_add_epi64(q, _mm256_and_si256(q_sign, mask)); // q = q + (q_sign & mask) + q = libdivide_s64_shift_right_vector(q, shift); // q >>= shift + q = _mm256_sub_epi64(_mm256_xor_si256(q, sign), sign); // q = (q ^ sign) - sign + return q; +} + +#elif defined(LIBDIVIDE_SSE2) + +static inline __m128i libdivide_u32_do_vector(__m128i numers, const struct libdivide_u32_t *denom); +static inline __m128i libdivide_s32_do_vector(__m128i numers, const struct libdivide_s32_t *denom); +static inline __m128i libdivide_u64_do_vector(__m128i numers, const struct libdivide_u64_t *denom); +static inline __m128i libdivide_s64_do_vector(__m128i numers, const struct libdivide_s64_t *denom); + +static inline __m128i libdivide_u32_branchfree_do_vector(__m128i numers, const struct libdivide_u32_branchfree_t *denom); +static inline __m128i libdivide_s32_branchfree_do_vector(__m128i numers, const struct libdivide_s32_branchfree_t *denom); +static inline __m128i libdivide_u64_branchfree_do_vector(__m128i numers, const struct libdivide_u64_branchfree_t *denom); +static inline __m128i libdivide_s64_branchfree_do_vector(__m128i numers, const struct libdivide_s64_branchfree_t *denom); + +//////// Internal Utility Functions + +// Implementation of _mm_srai_epi64(v, 63) (from AVX512). +static inline __m128i libdivide_s64_signbits(__m128i v) { + __m128i hiBitsDuped = _mm_shuffle_epi32(v, _MM_SHUFFLE(3, 3, 1, 1)); + __m128i signBits = _mm_srai_epi32(hiBitsDuped, 31); + return signBits; +} + +// Implementation of _mm_srai_epi64 (from AVX512). +static inline __m128i libdivide_s64_shift_right_vector(__m128i v, int amt) { + const int b = 64 - amt; + __m128i m = _mm_set1_epi64x(1ULL << (b - 1)); + __m128i x = _mm_srli_epi64(v, amt); + __m128i result = _mm_sub_epi64(_mm_xor_si128(x, m), m); + return result; +} + +// Here, b is assumed to contain one 32-bit value repeated. +static inline __m128i libdivide_mullhi_u32_vector(__m128i a, __m128i b) { + __m128i hi_product_0Z2Z = _mm_srli_epi64(_mm_mul_epu32(a, b), 32); + __m128i a1X3X = _mm_srli_epi64(a, 32); + __m128i mask = _mm_set_epi32(-1, 0, -1, 0); + __m128i hi_product_Z1Z3 = _mm_and_si128(_mm_mul_epu32(a1X3X, b), mask); + return _mm_or_si128(hi_product_0Z2Z, hi_product_Z1Z3); +} + +// SSE2 does not have a signed multiplication instruction, but we can convert +// unsigned to signed pretty efficiently. Again, b is just a 32 bit value +// repeated four times. +static inline __m128i libdivide_mullhi_s32_vector(__m128i a, __m128i b) { + __m128i p = libdivide_mullhi_u32_vector(a, b); + // t1 = (a >> 31) & y, arithmetic shift + __m128i t1 = _mm_and_si128(_mm_srai_epi32(a, 31), b); + __m128i t2 = _mm_and_si128(_mm_srai_epi32(b, 31), a); + p = _mm_sub_epi32(p, t1); + p = _mm_sub_epi32(p, t2); + return p; +} + +// Here, y is assumed to contain one 64-bit value repeated. +// https://stackoverflow.com/a/28827013 +static inline __m128i libdivide_mullhi_u64_vector(__m128i x, __m128i y) { + __m128i lomask = _mm_set1_epi64x(0xffffffff); + __m128i xh = _mm_shuffle_epi32(x, 0xB1); // x0l, x0h, x1l, x1h + __m128i yh = _mm_shuffle_epi32(y, 0xB1); // y0l, y0h, y1l, y1h + __m128i w0 = _mm_mul_epu32(x, y); // x0l*y0l, x1l*y1l + __m128i w1 = _mm_mul_epu32(x, yh); // x0l*y0h, x1l*y1h + __m128i w2 = _mm_mul_epu32(xh, y); // x0h*y0l, x1h*y0l + __m128i w3 = _mm_mul_epu32(xh, yh); // x0h*y0h, x1h*y1h + __m128i w0h = _mm_srli_epi64(w0, 32); + __m128i s1 = _mm_add_epi64(w1, w0h); + __m128i s1l = _mm_and_si128(s1, lomask); + __m128i s1h = _mm_srli_epi64(s1, 32); + __m128i s2 = _mm_add_epi64(w2, s1l); + __m128i s2h = _mm_srli_epi64(s2, 32); + __m128i hi = _mm_add_epi64(w3, s1h); + hi = _mm_add_epi64(hi, s2h); + + return hi; +} + +// y is one 64-bit value repeated. +static inline __m128i libdivide_mullhi_s64_vector(__m128i x, __m128i y) { + __m128i p = libdivide_mullhi_u64_vector(x, y); + __m128i t1 = _mm_and_si128(libdivide_s64_signbits(x), y); + __m128i t2 = _mm_and_si128(libdivide_s64_signbits(y), x); + p = _mm_sub_epi64(p, t1); + p = _mm_sub_epi64(p, t2); + return p; +} + +////////// UINT32 + +__m128i libdivide_u32_do_vector(__m128i numers, const struct libdivide_u32_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return _mm_srli_epi32(numers, more); + } + else { + __m128i q = libdivide_mullhi_u32_vector(numers, _mm_set1_epi32(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // uint32_t t = ((numer - q) >> 1) + q; + // return t >> denom->shift; + uint32_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + __m128i t = _mm_add_epi32(_mm_srli_epi32(_mm_sub_epi32(numers, q), 1), q); + return _mm_srli_epi32(t, shift); + } + else { + return _mm_srli_epi32(q, more); + } + } +} + +__m128i libdivide_u32_branchfree_do_vector(__m128i numers, const struct libdivide_u32_branchfree_t *denom) { + __m128i q = libdivide_mullhi_u32_vector(numers, _mm_set1_epi32(denom->magic)); + __m128i t = _mm_add_epi32(_mm_srli_epi32(_mm_sub_epi32(numers, q), 1), q); + return _mm_srli_epi32(t, denom->more); +} + +////////// UINT64 + +__m128i libdivide_u64_do_vector(__m128i numers, const struct libdivide_u64_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + return _mm_srli_epi64(numers, more); + } + else { + __m128i q = libdivide_mullhi_u64_vector(numers, _mm_set1_epi64x(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // uint32_t t = ((numer - q) >> 1) + q; + // return t >> denom->shift; + uint32_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + __m128i t = _mm_add_epi64(_mm_srli_epi64(_mm_sub_epi64(numers, q), 1), q); + return _mm_srli_epi64(t, shift); + } + else { + return _mm_srli_epi64(q, more); + } + } +} + +__m128i libdivide_u64_branchfree_do_vector(__m128i numers, const struct libdivide_u64_branchfree_t *denom) { + __m128i q = libdivide_mullhi_u64_vector(numers, _mm_set1_epi64x(denom->magic)); + __m128i t = _mm_add_epi64(_mm_srli_epi64(_mm_sub_epi64(numers, q), 1), q); + return _mm_srli_epi64(t, denom->more); +} + +////////// SINT32 + +__m128i libdivide_s32_do_vector(__m128i numers, const struct libdivide_s32_t *denom) { + uint8_t more = denom->more; + if (!denom->magic) { + uint32_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + uint32_t mask = (1U << shift) - 1; + __m128i roundToZeroTweak = _mm_set1_epi32(mask); + // q = numer + ((numer >> 31) & roundToZeroTweak); + __m128i q = _mm_add_epi32(numers, _mm_and_si128(_mm_srai_epi32(numers, 31), roundToZeroTweak)); + q = _mm_srai_epi32(q, shift); + __m128i sign = _mm_set1_epi32((int8_t)more >> 7); + // q = (q ^ sign) - sign; + q = _mm_sub_epi32(_mm_xor_si128(q, sign), sign); + return q; + } + else { + __m128i q = libdivide_mullhi_s32_vector(numers, _mm_set1_epi32(denom->magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift + __m128i sign = _mm_set1_epi32((int8_t)more >> 7); + // q += ((numer ^ sign) - sign); + q = _mm_add_epi32(q, _mm_sub_epi32(_mm_xor_si128(numers, sign), sign)); + } + // q >>= shift + q = _mm_srai_epi32(q, more & LIBDIVIDE_32_SHIFT_MASK); + q = _mm_add_epi32(q, _mm_srli_epi32(q, 31)); // q += (q < 0) + return q; + } +} + +__m128i libdivide_s32_branchfree_do_vector(__m128i numers, const struct libdivide_s32_branchfree_t *denom) { + int32_t magic = denom->magic; + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK; + // must be arithmetic shift + __m128i sign = _mm_set1_epi32((int8_t)more >> 7); + __m128i q = libdivide_mullhi_s32_vector(numers, _mm_set1_epi32(magic)); + q = _mm_add_epi32(q, numers); // q += numers + + // If q is non-negative, we have nothing to do + // If q is negative, we want to add either (2**shift)-1 if d is + // a power of 2, or (2**shift) if it is not a power of 2 + uint32_t is_power_of_2 = (magic == 0); + __m128i q_sign = _mm_srai_epi32(q, 31); // q_sign = q >> 31 + __m128i mask = _mm_set1_epi32((1U << shift) - is_power_of_2); + q = _mm_add_epi32(q, _mm_and_si128(q_sign, mask)); // q = q + (q_sign & mask) + q = _mm_srai_epi32(q, shift); // q >>= shift + q = _mm_sub_epi32(_mm_xor_si128(q, sign), sign); // q = (q ^ sign) - sign + return q; +} + +////////// SINT64 + +__m128i libdivide_s64_do_vector(__m128i numers, const struct libdivide_s64_t *denom) { + uint8_t more = denom->more; + int64_t magic = denom->magic; + if (magic == 0) { // shift path + uint32_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + uint64_t mask = (1ULL << shift) - 1; + __m128i roundToZeroTweak = _mm_set1_epi64x(mask); + // q = numer + ((numer >> 63) & roundToZeroTweak); + __m128i q = _mm_add_epi64(numers, _mm_and_si128(libdivide_s64_signbits(numers), roundToZeroTweak)); + q = libdivide_s64_shift_right_vector(q, shift); + __m128i sign = _mm_set1_epi32((int8_t)more >> 7); + // q = (q ^ sign) - sign; + q = _mm_sub_epi64(_mm_xor_si128(q, sign), sign); + return q; + } + else { + __m128i q = libdivide_mullhi_s64_vector(numers, _mm_set1_epi64x(magic)); + if (more & LIBDIVIDE_ADD_MARKER) { + // must be arithmetic shift + __m128i sign = _mm_set1_epi32((int8_t)more >> 7); + // q += ((numer ^ sign) - sign); + q = _mm_add_epi64(q, _mm_sub_epi64(_mm_xor_si128(numers, sign), sign)); + } + // q >>= denom->mult_path.shift + q = libdivide_s64_shift_right_vector(q, more & LIBDIVIDE_64_SHIFT_MASK); + q = _mm_add_epi64(q, _mm_srli_epi64(q, 63)); // q += (q < 0) + return q; + } +} + +__m128i libdivide_s64_branchfree_do_vector(__m128i numers, const struct libdivide_s64_branchfree_t *denom) { + int64_t magic = denom->magic; + uint8_t more = denom->more; + uint8_t shift = more & LIBDIVIDE_64_SHIFT_MASK; + // must be arithmetic shift + __m128i sign = _mm_set1_epi32((int8_t)more >> 7); + + // libdivide_mullhi_s64(numers, magic); + __m128i q = libdivide_mullhi_s64_vector(numers, _mm_set1_epi64x(magic)); + q = _mm_add_epi64(q, numers); // q += numers + + // If q is non-negative, we have nothing to do. + // If q is negative, we want to add either (2**shift)-1 if d is + // a power of 2, or (2**shift) if it is not a power of 2. + uint32_t is_power_of_2 = (magic == 0); + __m128i q_sign = libdivide_s64_signbits(q); // q_sign = q >> 63 + __m128i mask = _mm_set1_epi64x((1ULL << shift) - is_power_of_2); + q = _mm_add_epi64(q, _mm_and_si128(q_sign, mask)); // q = q + (q_sign & mask) + q = libdivide_s64_shift_right_vector(q, shift); // q >>= shift + q = _mm_sub_epi64(_mm_xor_si128(q, sign), sign); // q = (q ^ sign) - sign + return q; +} + +#endif + +/////////// C++ stuff + +#ifdef __cplusplus + +// The C++ divider class is templated on both an integer type +// (like uint64_t) and an algorithm type. +// * BRANCHFULL is the default algorithm type. +// * BRANCHFREE is the branchfree algorithm type. +enum { + BRANCHFULL, + BRANCHFREE +}; + +#if defined(LIBDIVIDE_AVX512) + #define LIBDIVIDE_VECTOR_TYPE __m512i +#elif defined(LIBDIVIDE_AVX2) + #define LIBDIVIDE_VECTOR_TYPE __m256i +#elif defined(LIBDIVIDE_SSE2) + #define LIBDIVIDE_VECTOR_TYPE __m128i +#endif + +#if !defined(LIBDIVIDE_VECTOR_TYPE) + #define LIBDIVIDE_DIVIDE_VECTOR(ALGO) +#else + #define LIBDIVIDE_DIVIDE_VECTOR(ALGO) \ + LIBDIVIDE_VECTOR_TYPE divide(LIBDIVIDE_VECTOR_TYPE n) const { \ + return libdivide_##ALGO##_do_vector(n, &denom); \ + } +#endif + +// The DISPATCHER_GEN() macro generates C++ methods (for the given integer +// and algorithm types) that redirect to libdivide's C API. +#define DISPATCHER_GEN(T, ALGO) \ + libdivide_##ALGO##_t denom; \ + dispatcher() { } \ + dispatcher(T d) \ + : denom(libdivide_##ALGO##_gen(d)) \ + { } \ + T divide(T n) const { \ + return libdivide_##ALGO##_do(n, &denom); \ + } \ + LIBDIVIDE_DIVIDE_VECTOR(ALGO) \ + T recover() const { \ + return libdivide_##ALGO##_recover(&denom); \ + } + +// The dispatcher selects a specific division algorithm for a given +// type and ALGO using partial template specialization. +template struct dispatcher { }; + +template<> struct dispatcher { DISPATCHER_GEN(int32_t, s32) }; +template<> struct dispatcher { DISPATCHER_GEN(int32_t, s32_branchfree) }; +template<> struct dispatcher { DISPATCHER_GEN(uint32_t, u32) }; +template<> struct dispatcher { DISPATCHER_GEN(uint32_t, u32_branchfree) }; +template<> struct dispatcher { DISPATCHER_GEN(int64_t, s64) }; +template<> struct dispatcher { DISPATCHER_GEN(int64_t, s64_branchfree) }; +template<> struct dispatcher { DISPATCHER_GEN(uint64_t, u64) }; +template<> struct dispatcher { DISPATCHER_GEN(uint64_t, u64_branchfree) }; + +// This is the main divider class for use by the user (C++ API). +// The actual division algorithm is selected using the dispatcher struct +// based on the integer and algorithm template parameters. +template +class divider { +public: + // We leave the default constructor empty so that creating + // an array of dividers and then initializing them + // later doesn't slow us down. + divider() { } + + // Constructor that takes the divisor as a parameter + divider(T d) : div(d) { } + + // Divides n by the divisor + T divide(T n) const { + return div.divide(n); + } + + // Recovers the divisor, returns the value that was + // used to initialize this divider object. + T recover() const { + return div.recover(); + } + + bool operator==(const divider& other) const { + return div.denom.magic == other.denom.magic && + div.denom.more == other.denom.more; + } + + bool operator!=(const divider& other) const { + return !(*this == other); + } + +#if defined(LIBDIVIDE_VECTOR_TYPE) + // Treats the vector as packed integer values with the same type as + // the divider (e.g. s32, u32, s64, u64) and divides each of + // them by the divider, returning the packed quotients. + LIBDIVIDE_VECTOR_TYPE divide(LIBDIVIDE_VECTOR_TYPE n) const { + return div.divide(n); + } +#endif + +private: + // Storage for the actual divisor + dispatcher::value, + std::is_signed::value, sizeof(T), ALGO> div; +}; + +// Overload of operator / for scalar division +template +T operator/(T n, const divider& div) { + return div.divide(n); +} + +// Overload of operator /= for scalar division +template +T& operator/=(T& n, const divider& div) { + n = div.divide(n); + return n; +} + +#if defined(LIBDIVIDE_VECTOR_TYPE) + // Overload of operator / for vector division + template + LIBDIVIDE_VECTOR_TYPE operator/(LIBDIVIDE_VECTOR_TYPE n, const divider& div) { + return div.divide(n); + } + // Overload of operator /= for vector division + template + LIBDIVIDE_VECTOR_TYPE& operator/=(LIBDIVIDE_VECTOR_TYPE& n, const divider& div) { + n = div.divide(n); + return n; + } +#endif + +// libdivdie::branchfree_divider +template +using branchfree_divider = divider; + +} // namespace libdivide + +#endif // __cplusplus + +#endif // LIBDIVIDE_H diff --git a/src/locale/en.po b/src/locale/en.po index 30ebe4368..8dd08173d 100644 --- a/src/locale/en.po +++ b/src/locale/en.po @@ -466,7 +466,7 @@ msgid "" msgstr "" #: d_clisrv.c:1764 -msgid "has been kicked (Go away)\n" +msgid "has been kicked (No reason given)\n" msgstr "" #: d_clisrv.c:1768 @@ -474,7 +474,7 @@ msgid "left the game (Broke ping limit)\n" msgstr "" #: d_clisrv.c:1772 -msgid "left the game (Consistency failure)\n" +msgid "left the game (Synch failure)\n" msgstr "" #: d_clisrv.c:1778 @@ -501,7 +501,7 @@ msgid "left the game\n" msgstr "" #: d_clisrv.c:1798 -msgid "has been banned (Don't come back)\n" +msgid "has been banned (No reason given)\n" msgstr "" #: d_clisrv.c:1802 diff --git a/src/locale/srb2.pot b/src/locale/srb2.pot index 960c36dbe..cd2db750d 100644 --- a/src/locale/srb2.pot +++ b/src/locale/srb2.pot @@ -459,7 +459,7 @@ msgid "" msgstr "" #: d_clisrv.c:1889 -msgid "has been kicked (Go away)\n" +msgid "has been kicked (No reason given)\n" msgstr "" #: d_clisrv.c:1893 @@ -467,7 +467,7 @@ msgid "left the game (Broke ping limit)\n" msgstr "" #: d_clisrv.c:1897 -msgid "left the game (Consistency failure)\n" +msgid "left the game (Synch failure)\n" msgstr "" #: d_clisrv.c:1903 @@ -494,7 +494,7 @@ msgid "left the game\n" msgstr "" #: d_clisrv.c:1923 -msgid "has been banned (Don't come back)\n" +msgid "has been banned (No reason given)\n" msgstr "" #: d_clisrv.c:1927 diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 515f6f0ba..da3614271 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -28,6 +28,10 @@ #include "console.h" #include "d_netcmd.h" // IsPlayerAdmin #include "m_menu.h" // Player Setup menu color stuff +#include "m_misc.h" // M_MapNumber +#include "b_bot.h" // B_UpdateBotleader +#include "d_clisrv.h" // CL_RemovePlayer +#include "i_system.h" // I_GetPreciseTime, I_PreciseToMicros #include "lua_script.h" #include "lua_libs.h" @@ -155,6 +159,8 @@ static const struct { {META_PIVOTLIST, "spriteframepivot_t[]"}, {META_FRAMEPIVOT, "spriteframepivot_t"}, + {META_TAGLIST, "taglist"}, + {META_MOBJ, "mobj_t"}, {META_MAPTHING, "mapthing_t"}, @@ -182,10 +188,15 @@ static const struct { {META_MAPHEADER, "mapheader_t"}, {META_POLYOBJ, "polyobj_t"}, + {META_POLYOBJVERTICES, "polyobj_t.vertices"}, + {META_POLYOBJLINES, "polyobj_t.lines"}, {META_CVAR, "consvar_t"}, {META_SECTORLINES, "sector_t.lines"}, +#ifdef MUTABLE_TAGS + {META_SECTORTAGLIST, "sector_t.taglist"}, +#endif {META_SIDENUM, "line_t.sidenum"}, {META_LINEARGS, "line_t.args"}, {META_LINESTRINGARGS, "line_t.stringargs"}, @@ -207,6 +218,9 @@ static const struct { {META_ACTION, "action"}, {META_LUABANKS, "luabanks[]"}, + + {META_KEYEVENT, "keyevent_t"}, + {META_MOUSE, "mouse_t"}, {NULL, NULL} }; @@ -237,16 +251,10 @@ static const char *GetUserdataUType(lua_State *L) // or players[0].powers -> "player_t.powers" static int lib_userdataType(lua_State *L) { - int type; lua_settop(L, 1); // pop everything except arg 1 (in case somebody decided to add more) - type = lua_type(L, 1); - if (type == LUA_TLIGHTUSERDATA || type == LUA_TUSERDATA) - { - lua_pushstring(L, GetUserdataUType(L)); - return 1; - } - else - return luaL_typerror(L, 1, "userdata"); + luaL_checktype(L, 1, LUA_TUSERDATA); + lua_pushstring(L, GetUserdataUType(L)); + return 1; } // Takes a metatable as first and only argument @@ -358,6 +366,23 @@ static int lib_pGetColorAfter(lua_State *L) return 1; } +// M_MISC +////////////// + +static int lib_mMapNumber(lua_State *L) +{ + const char *arg = luaL_checkstring(L, 1); + size_t len = strlen(arg); + if (len == 2 || len == 5) { + char first = arg[len-2]; + char second = arg[len-1]; + lua_pushinteger(L, M_MapNumber(first, second)); + } else { + lua_pushinteger(L, 0); + } + return 1; +} + // M_RANDOM ////////////// @@ -1045,48 +1070,56 @@ static int lib_pSceneryXYMovement(lua_State *L) static int lib_pZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *ptmthing = tmthing; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_ZMovement(actor)); P_CheckPosition(actor, actor->x, actor->y); + P_SetTarget(&tmthing, ptmthing); return 1; } static int lib_pRingZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *ptmthing = tmthing; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_RingZMovement(actor); P_CheckPosition(actor, actor->x, actor->y); + P_SetTarget(&tmthing, ptmthing); return 0; } static int lib_pSceneryZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *ptmthing = tmthing; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); lua_pushboolean(L, P_SceneryZMovement(actor)); P_CheckPosition(actor, actor->x, actor->y); + P_SetTarget(&tmthing, ptmthing); return 1; } static int lib_pPlayerZMovement(lua_State *L) { mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + mobj_t *ptmthing = tmthing; NOHUD INLEVEL if (!actor) return LUA_ErrInvalid(L, "mobj_t"); P_PlayerZMovement(actor); P_CheckPosition(actor, actor->x, actor->y); + P_SetTarget(&tmthing, ptmthing); return 0; } @@ -1473,11 +1506,13 @@ static int lib_pSpawnSkidDust(lua_State *L) static int lib_pMovePlayer(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + mobj_t *ptmthing = tmthing; NOHUD INLEVEL if (!player) return LUA_ErrInvalid(L, "player_t"); P_MovePlayer(player); + P_SetTarget(&tmthing, ptmthing); return 0; } @@ -1666,6 +1701,26 @@ static int lib_pSwitchShield(lua_State *L) return 0; } +static int lib_pPlayerCanEnterSpinGaps(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + lua_pushboolean(L, P_PlayerCanEnterSpinGaps(player)); + return 1; +} + +static int lib_pPlayerShouldUseSpinHeight(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + lua_pushboolean(L, P_PlayerShouldUseSpinHeight(player)); + return 1; +} + // P_MAP /////////// @@ -1834,6 +1889,37 @@ static int lib_pDoSpring(lua_State *L) return 1; } +static int lib_pTryCameraMove(lua_State *L) +{ + camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); + fixed_t x = luaL_checkfixed(L, 2); + fixed_t y = luaL_checkfixed(L, 3); + + if (!cam) + return LUA_ErrInvalid(L, "camera_t"); + lua_pushboolean(L, P_TryCameraMove(x, y, cam)); + return 1; +} + +static int lib_pTeleportCameraMove(lua_State *L) +{ + camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); + fixed_t x = luaL_checkfixed(L, 2); + fixed_t y = luaL_checkfixed(L, 3); + fixed_t z = luaL_checkfixed(L, 4); + + if (!cam) + return LUA_ErrInvalid(L, "camera_t"); + cam->x = x; + cam->y = y; + cam->z = z; + P_CheckCameraPosition(x, y, cam); + cam->subsector = R_PointInSubsector(x, y); + cam->floorz = tmfloorz; + cam->ceilingz = tmceilingz; + return 0; +} + // P_INTER //////////// @@ -2116,6 +2202,31 @@ static int lib_pExplodeMissile(lua_State *L) return 0; } +static int lib_pMobjTouchingSectorSpecial(lua_State *L) +{ + mobj_t *mo = *((mobj_t**)luaL_checkudata(L, 1, META_MOBJ)); + INT32 section = (INT32)luaL_checkinteger(L, 2); + INT32 number = (INT32)luaL_checkinteger(L, 3); + //HUDSAFE + INLEVEL + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + LUA_PushUserdata(L, P_MobjTouchingSectorSpecial(mo, section, number), META_SECTOR); + return 1; +} + +static int lib_pMobjTouchingSectorSpecialFlag(lua_State *L) +{ + mobj_t *mo = *((mobj_t**)luaL_checkudata(L, 1, META_MOBJ)); + sectorspecialflags_t flag = (INT32)luaL_checkinteger(L, 2); + //HUDSAFE + INLEVEL + if (!mo) + return LUA_ErrInvalid(L, "mobj_t"); + LUA_PushUserdata(L, P_MobjTouchingSectorSpecialFlag(mo, flag), META_SECTOR); + return 1; +} + static int lib_pPlayerTouchingSectorSpecial(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -2129,6 +2240,18 @@ static int lib_pPlayerTouchingSectorSpecial(lua_State *L) return 1; } +static int lib_pPlayerTouchingSectorSpecialFlag(lua_State *L) +{ + player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + sectorspecialflags_t flag = (INT32)luaL_checkinteger(L, 2); + //HUDSAFE + INLEVEL + if (!player) + return LUA_ErrInvalid(L, "player_t"); + LUA_PushUserdata(L, P_PlayerTouchingSectorSpecialFlag(player, flag), META_SECTOR); + return 1; +} + static int lib_pFindLowestFloorSurrounding(lua_State *L) { sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR)); @@ -2260,23 +2383,13 @@ static int lib_pFadeLight(lua_State *L) INT32 speed = (INT32)luaL_checkinteger(L, 3); boolean ticbased = lua_optboolean(L, 4); boolean force = lua_optboolean(L, 5); + boolean relative = lua_optboolean(L, 6); NOHUD INLEVEL - P_FadeLight(tag, destvalue, speed, ticbased, force); + P_FadeLight(tag, destvalue, speed, ticbased, force, relative); return 0; } -static int lib_pThingOnSpecial3DFloor(lua_State *L) -{ - mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); - NOHUD - INLEVEL - if (!mo) - return LUA_ErrInvalid(L, "mobj_t"); - LUA_PushUserdata(L, P_ThingOnSpecial3DFloor(mo), META_SECTOR); - return 1; -} - static int lib_pIsFlagAtBase(lua_State *L) { mobjtype_t flag = luaL_checkinteger(L, 1); @@ -2489,6 +2602,17 @@ static int lib_pGetZAt(lua_State *L) return 1; } +static int lib_pButteredSlope(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + INLEVEL + if (!mobj) + return LUA_ErrInvalid(L, "mobj_t"); + P_ButteredSlope(mobj); + return 0; +} + // R_DEFS //////////// @@ -2803,46 +2927,13 @@ static int lib_sStopSoundByID(lua_State *L) static int lib_sChangeMusic(lua_State *L) { -#ifdef MUSICSLOT_COMPATIBILITY - const char *music_name; - UINT32 music_num, position, prefadems, fadeinms; - char music_compat_name[7]; + UINT32 position, prefadems, fadeinms; - boolean looping; - player_t *player = NULL; - UINT16 music_flags = 0; - //NOHUD - - if (lua_isnumber(L, 1)) - { - music_num = (UINT32)luaL_checkinteger(L, 1); - music_flags = (UINT16)(music_num & 0x0000FFFF); - if (music_flags && music_flags <= 1035) - snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags)); - else if (music_flags && music_flags <= 1050) - strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7); - else - music_compat_name[0] = 0; // becomes empty string - music_compat_name[6] = 0; - music_name = (const char *)&music_compat_name; - music_flags = 0; - } - else - { - music_num = 0; - music_name = luaL_checkstring(L, 1); - } - - looping = (boolean)lua_opttrueboolean(L, 2); - -#else const char *music_name = luaL_checkstring(L, 1); boolean looping = (boolean)lua_opttrueboolean(L, 2); player_t *player = NULL; UINT16 music_flags = 0; - //NOHUD -#endif if (!lua_isnone(L, 3) && lua_isuserdata(L, 3)) { player = *((player_t **)luaL_checkudata(L, 3, META_PLAYER)); @@ -2850,13 +2941,7 @@ static int lib_sChangeMusic(lua_State *L) return LUA_ErrInvalid(L, "player_t"); } -#ifdef MUSICSLOT_COMPATIBILITY - if (music_num) - music_flags = (UINT16)((music_num & 0x7FFF0000) >> 16); - else -#endif music_flags = (UINT16)luaL_optinteger(L, 4, 0); - position = (UINT32)luaL_optinteger(L, 5, 0); prefadems = (UINT32)luaL_optinteger(L, 6, 0); fadeinms = (UINT32)luaL_optinteger(L, 7, 0); @@ -3153,33 +3238,7 @@ static int lib_sMusicExists(lua_State *L) { boolean checkMIDI = lua_opttrueboolean(L, 2); boolean checkDigi = lua_opttrueboolean(L, 3); -#ifdef MUSICSLOT_COMPATIBILITY - const char *music_name; - UINT32 music_num; - char music_compat_name[7]; - UINT16 music_flags = 0; - NOHUD - if (lua_isnumber(L, 1)) - { - music_num = (UINT32)luaL_checkinteger(L, 1); - music_flags = (UINT16)(music_num & 0x0000FFFF); - if (music_flags && music_flags <= 1035) - snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags)); - else if (music_flags && music_flags <= 1050) - strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7); - else - music_compat_name[0] = 0; // becomes empty string - music_compat_name[6] = 0; - music_name = (const char *)&music_compat_name; - } - else - { - music_num = 0; - music_name = luaL_checkstring(L, 1); - } -#else const char *music_name = luaL_checkstring(L, 1); -#endif NOHUD lua_pushboolean(L, S_MusicExists(music_name, checkMIDI, checkDigi)); return 1; @@ -3402,6 +3461,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)) + strlcpy(player_names[newplayernum], luaL_checkstring(L, 3), sizeof(*player_names)); + + 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) @@ -3743,6 +3907,12 @@ static int lib_gTicsToMilliseconds(lua_State *L) return 1; } +static int lib_getTimeMicros(lua_State *L) +{ + lua_pushinteger(L, I_PreciseToMicros(I_GetPreciseTime())); + return 1; +} + static luaL_Reg lib[] = { {"print", lib_print}, {"chatprint", lib_chatprint}, @@ -3759,6 +3929,9 @@ static luaL_Reg lib[] = { {"M_GetColorAfter",lib_pGetColorAfter}, {"M_GetColorBefore",lib_pGetColorBefore}, + // m_misc + {"M_MapNumber",lib_mMapNumber}, + // m_random {"P_RandomFixed",lib_pRandomFixed}, {"P_RandomByte",lib_pRandomByte}, @@ -3867,6 +4040,8 @@ static luaL_Reg lib[] = { {"P_SpawnSpinMobj",lib_pSpawnSpinMobj}, {"P_Telekinesis",lib_pTelekinesis}, {"P_SwitchShield",lib_pSwitchShield}, + {"P_PlayerCanEnterSpinGaps",lib_pPlayerCanEnterSpinGaps}, + {"P_PlayerShouldUseSpinHeight",lib_pPlayerShouldUseSpinHeight}, // p_map {"P_CheckPosition",lib_pCheckPosition}, @@ -3881,6 +4056,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}, @@ -3905,7 +4082,10 @@ static luaL_Reg lib[] = { {"P_SetMobjStateNF",lib_pSetMobjStateNF}, {"P_DoSuperTransformation",lib_pDoSuperTransformation}, {"P_ExplodeMissile",lib_pExplodeMissile}, + {"P_MobjTouchingSectorSpecial",lib_pMobjTouchingSectorSpecial}, + {"P_MobjTouchingSectorSpecialFlag",lib_pMobjTouchingSectorSpecialFlag}, {"P_PlayerTouchingSectorSpecial",lib_pPlayerTouchingSectorSpecial}, + {"P_PlayerTouchingSectorSpecialFlag",lib_pPlayerTouchingSectorSpecialFlag}, {"P_FindLowestFloorSurrounding",lib_pFindLowestFloorSurrounding}, {"P_FindHighestFloorSurrounding",lib_pFindHighestFloorSurrounding}, {"P_FindNextHighestFloor",lib_pFindNextHighestFloor}, @@ -3917,7 +4097,6 @@ static luaL_Reg lib[] = { {"P_LinedefExecute",lib_pLinedefExecute}, {"P_SpawnLightningFlash",lib_pSpawnLightningFlash}, {"P_FadeLight",lib_pFadeLight}, - {"P_ThingOnSpecial3DFloor",lib_pThingOnSpecial3DFloor}, {"P_IsFlagAtBase",lib_pIsFlagAtBase}, {"P_SetupLevelSky",lib_pSetupLevelSky}, {"P_SetSkyboxMobj",lib_pSetSkyboxMobj}, @@ -3927,6 +4106,7 @@ static luaL_Reg lib[] = { // p_slopes {"P_GetZAt",lib_pGetZAt}, + {"P_ButteredSlope",lib_pButteredSlope}, // r_defs {"R_PointToAngle",lib_rPointToAngle}, @@ -3982,6 +4162,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}, @@ -4007,6 +4189,8 @@ static luaL_Reg lib[] = { {"G_TicsToCentiseconds",lib_gTicsToCentiseconds}, {"G_TicsToMilliseconds",lib_gTicsToMilliseconds}, + {"getTimeMicros",lib_getTimeMicros}, + {NULL, NULL} }; diff --git a/src/lua_blockmaplib.c b/src/lua_blockmaplib.c index 1949d56bb..8c63a9d6d 100644 --- a/src/lua_blockmaplib.c +++ b/src/lua_blockmaplib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2016-2020 by Iestyn "Monster Iestyn" Jealous. -// Copyright (C) 2016-2020 by Sonic Team Junior. +// Copyright (C) 2016-2022 by Iestyn "Monster Iestyn" Jealous. +// Copyright (C) 2016-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index 84bfeaee2..c8e914e6d 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -28,7 +28,7 @@ return luaL_error(L, "HUD rendering code should not call this function!"); #define NOHOOK if (!lua_lumploading)\ return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); -static const char *cvname = NULL; +static consvar_t *this_cvar; void Got_Luacmd(UINT8 **cp, INT32 playernum) { @@ -273,34 +273,29 @@ static int lib_comBufInsertText(lua_State *L) return 0; } -void LUA_CVarChanged(const char *name) +void LUA_CVarChanged(void *cvar) { - cvname = name; + this_cvar = cvar; } static void Lua_OnChange(void) { - I_Assert(gL != NULL); - I_Assert(cvname != NULL); - /// \todo Network this! XD_LUAVAR - lua_settop(gL, 0); // Just in case... lua_pushcfunction(gL, LUA_GetErrorMessage); + lua_insert(gL, 1); // Because LUA_Call wants it at index 1. // From CV_OnChange registry field, get the function for this cvar by name. lua_getfield(gL, LUA_REGISTRYINDEX, "CV_OnChange"); I_Assert(lua_istable(gL, -1)); - lua_getfield(gL, -1, cvname); // get function + lua_pushlightuserdata(gL, this_cvar); + lua_rawget(gL, -2); // get function - // From the CV_Vars registry field, get the cvar's userdata by name. - lua_getfield(gL, LUA_REGISTRYINDEX, "CV_Vars"); - I_Assert(lua_istable(gL, -1)); - lua_getfield(gL, -1, cvname); // get consvar_t* userdata. - lua_remove(gL, -2); // pop the CV_Vars table. + LUA_RawPushUserdata(gL, this_cvar); LUA_Call(gL, 1, 0, 1); // call function(cvar) lua_pop(gL, 1); // pop CV_OnChange table + lua_remove(gL, 1); // remove LUA_GetErrorMessage } static int lib_cvRegisterVar(lua_State *L) @@ -311,15 +306,12 @@ static int lib_cvRegisterVar(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); // Clear out all other possible arguments, leaving only the first one. NOHOOK - cvar = lua_newuserdata(L, sizeof(consvar_t)); - luaL_getmetatable(L, META_CVAR); - lua_setmetatable(L, -2); + cvar = ZZ_Calloc(sizeof(consvar_t)); + LUA_PushUserdata(L, cvar, META_CVAR); #define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to " LUA_QL("CV_RegisterVar") " (%s)", e); #define TYPEERROR(f, t) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t), luaL_typename(L, -1))) - memset(cvar, 0x00, sizeof(consvar_t)); // zero everything by default - lua_pushnil(L); while (lua_next(L, 1)) { // stack: cvar table, cvar userdata, key/index, value @@ -368,7 +360,7 @@ static int lib_cvRegisterVar(lua_State *L) lua_getfield(L, LUA_REGISTRYINDEX, "CV_PossibleValue"); I_Assert(lua_istable(L, 5)); - lua_pushvalue(L, 2); // cvar userdata + lua_pushlightuserdata(L, cvar); cvpv = lua_newuserdata(L, sizeof(CV_PossibleValue_t) * (count+1)); lua_rawset(L, 5); lua_pop(L, 1); // pop CV_PossibleValue registry table @@ -396,8 +388,9 @@ static int lib_cvRegisterVar(lua_State *L) TYPEERROR("func", LUA_TFUNCTION) lua_getfield(L, LUA_REGISTRYINDEX, "CV_OnChange"); I_Assert(lua_istable(L, 5)); + lua_pushlightuserdata(L, cvar); lua_pushvalue(L, 4); - lua_setfield(L, 5, cvar->name); + lua_rawset(L, 5); lua_pop(L, 1); cvar->func = Lua_OnChange; } @@ -414,19 +407,6 @@ static int lib_cvRegisterVar(lua_State *L) if ((cvar->flags & CV_CALL) && !cvar->func) return luaL_error(L, M_GetText("Variable %s has CV_CALL without a function\n"), cvar->name); - // stack: cvar table, cvar userdata - lua_getfield(L, LUA_REGISTRYINDEX, "CV_Vars"); - I_Assert(lua_istable(L, 3)); - - lua_getfield(L, 3, cvar->name); - if (lua_type(L, -1) != LUA_TNIL) - return luaL_error(L, M_GetText("Variable %s is already defined\n"), cvar->name); - lua_pop(L, 1); - - lua_pushvalue(L, 2); - lua_setfield(L, 3, cvar->name); - lua_pop(L, 1); - // actually time to register it to the console now! Finally! cvar->flags |= CV_MODIFIED; CV_RegisterVar(cvar); @@ -439,7 +419,8 @@ static int lib_cvRegisterVar(lua_State *L) static int lib_cvFindVar(lua_State *L) { - LUA_PushLightUserdata(L, CV_FindVar(luaL_checkstring(L,1)), META_CVAR); + const char *name = luaL_checkstring(L, 1); + LUA_PushUserdata(L, CV_FindVar(name), META_CVAR); return 1; } @@ -449,10 +430,10 @@ static int CVarSetFunction void (*Set)(consvar_t *, const char *), void (*SetValue)(consvar_t *, INT32) ){ - consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR); if (cvar->flags & CV_NOLUA) - 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)) { @@ -481,7 +462,7 @@ static int lib_cvStealthSet(lua_State *L) static int lib_cvAddValue(lua_State *L) { - consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR); if (cvar->flags & CV_NOLUA) return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); @@ -540,7 +521,7 @@ static luaL_Reg lib[] = { static int cvar_get(lua_State *L) { - consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + consvar_t *cvar = *(consvar_t **)luaL_checkudata(L, 1, META_CVAR); const char *field = luaL_checkstring(L, 2); if(fastcmp(field,"name")) diff --git a/src/lua_hook.h b/src/lua_hook.h index 5cfcb8360..fc6a5f4ee 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -12,109 +12,139 @@ #include "r_defs.h" #include "d_player.h" +#include "s_sound.h" +#include "d_event.h" -enum hook { - hook_NetVars=0, - hook_MapChange, - hook_MapLoad, - hook_PlayerJoin, - hook_PreThinkFrame, - hook_ThinkFrame, - hook_PostThinkFrame, - hook_MobjSpawn, - hook_MobjCollide, - hook_MobjLineCollide, - hook_MobjMoveCollide, - hook_TouchSpecial, - hook_MobjFuse, - hook_MobjThinker, - hook_BossThinker, - hook_ShouldDamage, - hook_MobjDamage, - hook_MobjDeath, - hook_BossDeath, - hook_MobjRemoved, - hook_JumpSpecial, - hook_AbilitySpecial, - hook_SpinSpecial, - hook_JumpSpinSpecial, - hook_BotTiccmd, - hook_BotAI, - hook_BotRespawn, - hook_LinedefExecute, - hook_PlayerMsg, - hook_HurtMsg, - hook_PlayerSpawn, - hook_ShieldSpawn, - hook_ShieldSpecial, - hook_MobjMoveBlocked, - hook_MapThingSpawn, - hook_FollowMobj, - hook_PlayerCanDamage, - hook_PlayerQuit, - hook_IntermissionThinker, - hook_TeamSwitch, - hook_ViewpointSwitch, - hook_SeenPlayer, - hook_PlayerThink, - hook_ShouldJingleContinue, - hook_GameQuit, - hook_PlayerCmd, - hook_MusicChange, +/* +Do you know what an 'X Macro' is? Such a macro is called over each element of +a list and expands the input. I use it for the hook lists because both an enum +and array of hook names need to be kept in order. The X Macro handles this +automatically. +*/ - hook_MAX // last hook -}; -extern const char *const hookNames[]; +#define MOBJ_HOOK_LIST(X) \ + X (MobjSpawn),/* P_SpawnMobj */\ + X (MobjCollide),/* PIT_CheckThing */\ + X (MobjLineCollide),/* ditto */\ + X (MobjMoveCollide),/* tritto */\ + X (TouchSpecial),/* P_TouchSpecialThing */\ + X (MobjFuse),/* when mobj->fuse runs out */\ + X (MobjThinker),/* P_MobjThinker, P_SceneryThinker */\ + X (BossThinker),/* P_GenericBossThinker */\ + X (ShouldDamage),/* P_DamageMobj (Should mobj take damage?) */\ + X (MobjDamage),/* P_DamageMobj (Mobj actually takes damage!) */\ + X (MobjDeath),/* P_KillMobj */\ + X (BossDeath),/* A_BossDeath */\ + X (MobjRemoved),/* P_RemoveMobj */\ + X (BotRespawn),/* B_CheckRespawn */\ + X (MobjMoveBlocked),/* P_XYMovement (when movement is blocked) */\ + X (MapThingSpawn),/* P_SpawnMapThing */\ + X (FollowMobj),/* P_PlayerAfterThink Smiles mobj-following */\ + +#define HOOK_LIST(X) \ + X (NetVars),/* add to archive table (netsave) */\ + X (MapChange),/* (before map load) */\ + X (MapLoad),\ + X (PlayerJoin),/* Got_AddPlayer */\ + X (PreThinkFrame)/* frame (before mobj and player thinkers) */,\ + X (ThinkFrame),/* frame (after mobj and player thinkers) */\ + X (PostThinkFrame),/* frame (at end of tick, ie after overlays, precipitation, specials) */\ + X (JumpSpecial),/* P_DoJumpStuff (Any-jumping) */\ + X (AbilitySpecial),/* P_DoJumpStuff (Double-jumping) */\ + X (SpinSpecial),/* P_DoSpinAbility (Spin button effect) */\ + X (JumpSpinSpecial),/* P_DoJumpStuff (Spin button effect (mid-air)) */\ + X (BotTiccmd),/* B_BuildTiccmd */\ + X (PlayerMsg),/* chat messages */\ + X (HurtMsg),/* imhurttin */\ + X (PlayerSpawn),/* G_SpawnPlayer */\ + X (ShieldSpawn),/* P_SpawnShieldOrb */\ + X (ShieldSpecial),/* shield abilities */\ + X (PlayerCanDamage),/* P_PlayerCanDamage */\ + X (PlayerQuit),\ + X (IntermissionThinker),/* Y_Ticker */\ + X (TeamSwitch),/* team switching in... uh... *what* speak, spit it the fuck out */\ + X (ViewpointSwitch),/* spy mode (no trickstabs) */\ + X (SeenPlayer),/* MT_NAMECHECK */\ + X (PlayerThink),/* P_PlayerThink */\ + X (GameQuit),\ + X (PlayerCmd),/* building the player's ticcmd struct (Ported from SRB2Kart) */\ + X (MusicChange),\ + X (PlayerHeight),/* override player height */\ + X (PlayerCanEnterSpinGaps),\ + X (KeyDown),\ + X (KeyUp),\ + +#define STRING_HOOK_LIST(X) \ + X (BotAI),/* B_BuildTailsTiccmd by skin name */\ + 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. +(Since each enumeration is not defined in the source code, but by the list +macros above, it is not greppable.) The name passed to the macro can also be +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 + +#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 LUAh_MapChange(INT16 mapnumber); // Hook for map change (before load) -void LUAh_MapLoad(void); // Hook for map load -void LUAh_PlayerJoin(int playernum); // Hook for Got_AddPlayer -void LUAh_PreThinkFrame(void); // Hook for frame (before mobj and player thinkers) -void LUAh_ThinkFrame(void); // Hook for frame (after mobj and player thinkers) -void LUAh_PostThinkFrame(void); // Hook for frame (at end of tick, ie after overlays, precipitation, specials) -boolean LUAh_MobjHook(mobj_t *mo, enum hook which); -boolean LUAh_PlayerHook(player_t *plr, enum hook which); -#define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type -UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which); -UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which); -#define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type -#define LUAh_MobjLineCollide(thing, line) LUAh_MobjLineCollideHook(thing, line, hook_MobjLineCollide) // Hook for PIT_CheckThing by (thing) mobj type -#define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type -boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type -#define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type -boolean LUAh_MobjThinker(mobj_t *mo); // Hook for P_MobjThinker or P_SceneryThinker by mobj type -#define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type -UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); // Hook for P_DamageMobj by mobj type (Should mobj take damage?) -boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) -boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for P_KillMobj by mobj type -#define LUAh_BossDeath(mo) LUAh_MobjHook(mo, hook_BossDeath) // Hook for A_BossDeath by mobj type -#define LUAh_MobjRemoved(mo) LUAh_MobjHook(mo, hook_MobjRemoved) // Hook for P_RemoveMobj by mobj type -#define LUAh_JumpSpecial(player) LUAh_PlayerHook(player, hook_JumpSpecial) // Hook for P_DoJumpStuff (Any-jumping) -#define LUAh_AbilitySpecial(player) LUAh_PlayerHook(player, hook_AbilitySpecial) // Hook for P_DoJumpStuff (Double-jumping) -#define LUAh_SpinSpecial(player) LUAh_PlayerHook(player, hook_SpinSpecial) // Hook for P_DoSpinAbility (Spin button effect) -#define LUAh_JumpSpinSpecial(player) LUAh_PlayerHook(player, hook_JumpSpinSpecial) // Hook for P_DoJumpStuff (Spin button effect (mid-air)) -boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd); // Hook for B_BuildTiccmd -boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_BuildTailsTiccmd by skin name -boolean LUAh_BotRespawn(mobj_t *sonic, mobj_t *tails); // Hook for B_CheckRespawn -boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors -boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages -boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); // Hook for hurt messages -#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer -#define LUAh_ShieldSpawn(player) LUAh_PlayerHook(player, hook_ShieldSpawn) // Hook for P_SpawnShieldOrb -#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities -#define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked) -boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type -boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following -UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage -void LUAh_PlayerQuit(player_t *plr, kickreason_t reason); // Hook for player quitting -void LUAh_IntermissionThinker(void); // Hook for Y_Ticker -boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); // Hook for team switching in... uh.... -UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); // Hook for spy mode -boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_NAMECHECK -#define LUAh_PlayerThink(player) LUAh_PlayerHook(player, hook_PlayerThink) // Hook for P_PlayerThink -boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing -void LUAh_GameQuit(boolean quitting); // Hook for game quitting -boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Hook for building player's ticcmd struct (Ported from SRB2Kart) -boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms); // Hook for music changes +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); +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 *); +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); +int LUA_HookHurtMsg(player_t *, mobj_t *inflictor, mobj_t *source, UINT8 damagetype); +int LUA_HookMapThingSpawn(mobj_t *, mapthing_t *); +int LUA_HookFollowMobj(player_t *, mobj_t *); +int LUA_HookPlayerCanDamage(player_t *, mobj_t *); +void LUA_HookPlayerQuit(player_t *, kickreason_t); +int LUA_HookTeamSwitch(player_t *, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble); +int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced); +int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend); +int LUA_HookShouldJingleContinue(player_t *, const char *musname); +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); diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 29c15a4de..48980f4a4 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -27,1947 +27,1150 @@ #include "d_netcmd.h" // for cv_perfstats #include "i_system.h" // I_GetPreciseTime -static UINT8 hooksAvailable[(hook_MAX/8)+1]; +/* ========================================================================= + ABSTRACTION + ========================================================================= */ -const char *const hookNames[hook_MAX+1] = { - "NetVars", - "MapChange", - "MapLoad", - "PlayerJoin", - "PreThinkFrame", - "ThinkFrame", - "PostThinkFrame", - "MobjSpawn", - "MobjCollide", - "MobjLineCollide", - "MobjMoveCollide", - "TouchSpecial", - "MobjFuse", - "MobjThinker", - "BossThinker", - "ShouldDamage", - "MobjDamage", - "MobjDeath", - "BossDeath", - "MobjRemoved", - "JumpSpecial", - "AbilitySpecial", - "SpinSpecial", - "JumpSpinSpecial", - "BotTiccmd", - "BotAI", - "BotRespawn", - "LinedefExecute", - "PlayerMsg", - "HurtMsg", - "PlayerSpawn", - "ShieldSpawn", - "ShieldSpecial", - "MobjMoveBlocked", - "MapThingSpawn", - "FollowMobj", - "PlayerCanDamage", - "PlayerQuit", - "IntermissionThinker", - "TeamSwitch", - "ViewpointSwitch", - "SeenPlayer", - "PlayerThink", - "ShouldJingleContinue", - "GameQuit", - "PlayerCmd", - "MusicChange", - NULL -}; +#define LIST(id, M) \ + static const char * const id [] = { M (TOSTR) NULL } -// Hook metadata -struct hook_s +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; + int *ids; +} hook_t; + +typedef struct { + int numGeneric; + int ref; +} 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. +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; + +static int errorRef; + +static boolean mobj_hook_available(int hook_type, mobjtype_t mobj_type) { - struct hook_s *next; - enum hook type; - UINT16 id; - union { - mobjtype_t mt; - char *str; - } s; - boolean error; -}; -typedef struct hook_s* hook_p; + return + ( + mobjHookIds [MT_NULL] [hook_type].numHooks > 0 || + mobjHookIds[mobj_type][hook_type].numHooks > 0 + ); +} -#define FMT_HOOKID "hook_%d" +static int hook_in_list +( + const char * const name, + const char * const * const list +){ + int type; -// For each mobj type, a linked list to its thinker and collision hooks. -// That way, we don't have to iterate through all the hooks. -// We could do that with all other mobj hooks, but it would probably just be -// a waste of memory since they are only called occasionally. Probably... -static hook_p mobjthinkerhooks[NUMMOBJTYPES]; -static hook_p mobjcollidehooks[NUMMOBJTYPES]; + for (type = 0; list[type] != NULL; ++type) + { + if (strcmp(name, list[type]) == 0) + break; + } -// For each mobj type, a linked list for other mobj hooks -static hook_p mobjhooks[NUMMOBJTYPES]; + return type; +} -// A linked list for player hooks -static hook_p playerhooks; - -// A linked list for linedef executor hooks -static hook_p linedefexecutorhooks; - -// For other hooks, a unique linked list -hook_p roothook; - -static void PushHook(lua_State *L, hook_p hookp) +static void get_table(lua_State *L) { - lua_pushfstring(L, FMT_HOOKID, hookp->id); - lua_gettable(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, -1); + lua_rawget(L, -3); + + if (lua_isnil(L, -1)) + { + lua_pop(L, 1); + lua_createtable(L, 1, 0); + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_rawset(L, -5); + } + + lua_remove(L, -2); +} + +static void add_hook_to_table(lua_State *L, int n) +{ + lua_pushnumber(L, nextid); + lua_rawseti(L, -2, n); +} + +static void add_string_hook(lua_State *L, int type) +{ + stringhook_t * hook = &stringHooks[type]; + + char * string = NULL; + + switch (type) + { + case STRING_HOOK(BotAI): + case STRING_HOOK(ShouldJingleContinue): + if (lua_isstring(L, 3)) + { // lowercase copy + string = Z_StrDup(lua_tostring(L, 3)); + strlwr(string); + } + break; + + case STRING_HOOK(LinedefExecute): + string = Z_StrDup(luaL_checkstring(L, 3)); + strupr(string); + break; + } + + if (hook->ref > 0) + lua_getref(L, hook->ref); + else + { + lua_newtable(L); + lua_pushvalue(L, -1); + hook->ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + + if (string) + { + lua_pushstring(L, string); + get_table(L); + add_hook_to_table(L, 1 + lua_objlen(L, -1)); + } + else + add_hook_to_table(L, ++hook->numGeneric); +} + +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++] = nextid; +} + +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]); +} + +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 struct hook_s hook = {NULL, 0, 0, {0}, false}; - static UINT32 nextid; - hook_p hookp, *lastp; - - hook.type = luaL_checkoption(L, 1, NULL, hookNames); - lua_remove(L, 1); - - luaL_checktype(L, 1, LUA_TFUNCTION); + const char * name; + int type; if (!lua_lumploading) return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); - switch(hook.type) + name = luaL_checkstring(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + + /* this is a very special case */ + if (( type = hook_in_list(name, stringHookNames) ) < STRING_HOOK(MAX)) { - // Take a mobjtype enum which this hook is specifically for. - case hook_MobjSpawn: - case hook_MobjCollide: - case hook_MobjLineCollide: - case hook_MobjMoveCollide: - case hook_TouchSpecial: - case hook_MobjFuse: - case hook_MobjThinker: - case hook_BossThinker: - case hook_ShouldDamage: - case hook_MobjDamage: - case hook_MobjDeath: - case hook_BossDeath: - case hook_MobjRemoved: - case hook_HurtMsg: - case hook_MobjMoveBlocked: - case hook_MapThingSpawn: - case hook_FollowMobj: - hook.s.mt = MT_NULL; - if (lua_isnumber(L, 2)) - hook.s.mt = lua_tonumber(L, 2); - luaL_argcheck(L, hook.s.mt < NUMMOBJTYPES, 2, "invalid mobjtype_t"); - break; - case hook_BotAI: - case hook_ShouldJingleContinue: - hook.s.str = NULL; - if (lua_isstring(L, 2)) - { // lowercase copy - hook.s.str = Z_StrDup(lua_tostring(L, 2)); - strlwr(hook.s.str); - } - break; - case hook_LinedefExecute: // Linedef executor functions - hook.s.str = Z_StrDup(luaL_checkstring(L, 2)); - strupr(hook.s.str); - break; - default: - break; + add_string_hook(L, type); } - lua_settop(L, 1); // lua stack contains only the function now. - - hooksAvailable[hook.type/8] |= 1<<(hook.type%8); - - // set hook.id to the highest id + 1 - hook.id = nextid++; - - // Special cases for some hook types (see the comments above mobjthinkerhooks declaration) - switch(hook.type) + else if (( type = hook_in_list(name, mobjHookNames) ) < MOBJ_HOOK(MAX)) { - case hook_MobjThinker: - lastp = &mobjthinkerhooks[hook.s.mt]; - break; - case hook_MobjCollide: - case hook_MobjLineCollide: - case hook_MobjMoveCollide: - lastp = &mobjcollidehooks[hook.s.mt]; - break; - case hook_MobjSpawn: - case hook_TouchSpecial: - case hook_MobjFuse: - case hook_BossThinker: - case hook_ShouldDamage: - case hook_MobjDamage: - case hook_MobjDeath: - case hook_BossDeath: - case hook_MobjRemoved: - case hook_MobjMoveBlocked: - case hook_MapThingSpawn: - case hook_FollowMobj: - lastp = &mobjhooks[hook.s.mt]; - break; - case hook_JumpSpecial: - case hook_AbilitySpecial: - case hook_SpinSpecial: - case hook_JumpSpinSpecial: - case hook_PlayerSpawn: - case hook_PlayerCanDamage: - case hook_TeamSwitch: - case hook_ViewpointSwitch: - case hook_SeenPlayer: - case hook_ShieldSpawn: - case hook_ShieldSpecial: - case hook_PlayerThink: - lastp = &playerhooks; - break; - case hook_LinedefExecute: - lastp = &linedefexecutorhooks; - break; - default: - lastp = &roothook; - break; + add_mobj_hook(L, type); + } + else if (( type = hook_in_list(name, hookNames) ) < HOOK(MAX)) + { + 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)); } - // iterate the hook metadata structs - // set lastp to the last hook struct's "next" pointer. - for (hookp = *lastp; hookp; hookp = hookp->next) - lastp = &hookp->next; - // allocate a permanent memory struct to stuff hook. - hookp = ZZ_Alloc(sizeof(struct hook_s)); - memcpy(hookp, &hook, sizeof(struct hook_s)); - // tack it onto the end of the linked list. - *lastp = hookp; + add_hook_ref(L, 2);/* the function */ - // set the hook function in the registry. - lua_pushfstring(L, FMT_HOOKID, hook.id); - lua_pushvalue(L, 1); - lua_settable(L, LUA_REGISTRYINDEX); return 0; } int LUA_HookLib(lua_State *L) { - memset(hooksAvailable,0,sizeof(UINT8[(hook_MAX/8)+1])); - roothook = NULL; + lua_pushcfunction(L, LUA_GetErrorMessage); + errorRef = luaL_ref(L, LUA_REGISTRYINDEX); + lua_register(L, "addHook", lib_addHook); + return 0; } -boolean LUAh_MobjHook(mobj_t *mo, enum hook which) +/* TODO: remove in next backwards incompatible release */ +int lib_hudadd(lua_State *L);/* yeah compiler */ +int lib_hudadd(lua_State *L) { - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) - return false; + if (!lua_lumploading) + return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); - I_Assert(mo->type < NUMMOBJTYPES); + luaL_checktype(L, 1, LUA_TFUNCTION); - if (!(mobjhooks[MT_NULL] || mobjhooks[mo->type])) - return false; + add_hud_hook(L, 2); + add_hook_ref(L, 1); + return 0; +} + +typedef struct Hook_State Hook_State; +typedef void (*Hook_Callback)(Hook_State *); + +struct Hook_State { + INT32 status;/* return status to calling function */ + void * userdata; + int hook_type; + mobjtype_t mobj_type;/* >0 if mobj hook */ + const char * string;/* used to fetch table, ran first if set */ + int top;/* index of last argument passed to hook */ + int id;/* id to fetch ref */ + int values;/* num arguments passed to hook */ + int results;/* num values returned by hook */ + Hook_Callback results_handler;/* callback when hook successfully returns */ +}; + +enum { + EINDEX = 1,/* error handler */ + SINDEX = 2,/* string itself is pushed in case of string hook */ +}; + +static void push_error_handler(void) +{ + lua_getref(gL, errorRef); +} + +/* repush hook string */ +static void push_string(void) +{ + lua_pushvalue(gL, SINDEX); +} + +static boolean begin_hook_values(Hook_State *hook) +{ + hook->top = lua_gettop(gL); + return true; +} + +static void start_hook_stack(void) +{ lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); + push_error_handler(); +} - // Look for all generic mobj hooks - for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) +static boolean init_hook_type +( + Hook_State * hook, + int status, + int hook_type, + mobjtype_t mobj_type, + const char * string, + int nonzero +){ + hook->status = status; + + if (nonzero) { - if (hookp->type != which) - continue; + start_hook_stack(); + hook->hook_type = hook_type; + hook->mobj_type = mobj_type; + hook->string = string; + return begin_hook_values(hook); + } + else + return false; +} - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, mo, META_MOBJ); - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; +static boolean prepare_hook +( + Hook_State * hook, + int default_status, + int hook_type +){ + return init_hook_type(hook, default_status, + hook_type, 0, NULL, + hookIds[hook_type].numHooks); +} + +static boolean prepare_mobj_hook +( + Hook_State * hook, + int default_status, + int hook_type, + mobjtype_t mobj_type +){ +#ifdef PARANOIA + if (mobj_type == MT_NULL) + I_Error("MT_NULL has been passed to a mobj hook\n"); +#endif + return init_hook_type(hook, default_status, + hook_type, mobj_type, NULL, + mobj_hook_available(hook_type, mobj_type)); +} + +static boolean prepare_string_hook +( + Hook_State * hook, + int default_status, + int hook_type, + const char * string +){ + if (init_hook_type(hook, default_status, + hook_type, 0, string, + stringHooks[hook_type].ref)) + { + lua_pushstring(gL, string); + return begin_hook_values(hook); + } + else + return false; +} + +static void init_hook_call +( + Hook_State * hook, + int results, + Hook_Callback results_handler +){ + const int top = lua_gettop(gL); + hook->values = (top - hook->top); + hook->top = top; + hook->results = results; + hook->results_handler = results_handler; +} + +static void get_hook(Hook_State *hook, const int *ids, int n) +{ + hook->id = ids[n]; + lua_getref(gL, hookRefs[hook->id]); +} + +static void get_hook_from_table(Hook_State *hook, int n) +{ + lua_rawgeti(gL, -1, n); + hook->id = lua_tonumber(gL, -1); + lua_pop(gL, 1); + lua_getref(gL, hookRefs[hook->id]); +} + +static int call_single_hook_no_copy(Hook_State *hook) +{ + if (lua_pcall(gL, hook->values, hook->results, EINDEX) == 0) + { + if (hook->results > 0) + { + (*hook->results_handler)(hook); + lua_pop(gL, hook->results); + } + } + else + { + /* print the error message once */ + if (cv_debug & DBG_LUA || !in_bit_array(hooksErrored, hook->id)) + { + CONS_Alert(CONS_WARNING, "%s\n", lua_tostring(gL, -1)); + set_bit_array(hooksErrored, hook->id); } - if (lua_toboolean(gL, -1)) - hooked = true; lua_pop(gL, 1); } - for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next) - { - if (hookp->type != which) - continue; + return 1; +} - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, mo, META_MOBJ); - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } +static int call_single_hook(Hook_State *hook) +{ + int i; + + for (i = -(hook->values) + 1; i <= 0; ++i) + lua_pushvalue(gL, hook->top + i); + + return call_single_hook_no_copy(hook); +} + +static int call_hook_table_for(Hook_State *hook, int n) +{ + int k; + + for (k = 1; k <= n; ++k) + { + get_hook_from_table(hook, k); + call_single_hook(hook); + } + + return n; +} + +static int call_hook_table(Hook_State *hook) +{ + return call_hook_table_for(hook, lua_objlen(gL, -1)); +} + +static int call_mapped(Hook_State *hook, const hook_t *map) +{ + int k; + + for (k = 0; k < map->numHooks; ++k) + { + get_hook(hook, map->ids, k); + call_single_hook(hook); + } + + return map->numHooks; +} + +static int call_string_hooks(Hook_State *hook) +{ + const stringhook_t *map = &stringHooks[hook->hook_type]; + + int calls = 0; + + lua_getref(gL, map->ref); + + /* call generic string hooks first */ + calls += call_hook_table_for(hook, map->numGeneric); + + push_string(); + lua_rawget(gL, -2); + calls += call_hook_table(hook); + + return calls; +} + +static int call_mobj_type_hooks(Hook_State *hook, mobjtype_t mobj_type) +{ + return call_mapped(hook, &mobjHookIds[mobj_type][hook->hook_type]); +} + +static int call_hooks +( + Hook_State * hook, + int results, + Hook_Callback results_handler +){ + int calls = 0; + + init_hook_call(hook, results, results_handler); + + if (hook->string) + { + calls += call_string_hooks(hook); + } + else if (hook->mobj_type > 0) + { + /* call generic mobj hooks first */ + calls += call_mobj_type_hooks(hook, MT_NULL); + calls += call_mobj_type_hooks(hook, hook->mobj_type); + + ps_lua_mobjhooks.value.i += calls; + } + else + calls += call_mapped(hook, &hookIds[hook->hook_type]); + + lua_settop(gL, 0); + + return calls; +} + +/* ========================================================================= + COMMON RESULT HANDLERS + ========================================================================= */ + +#define res_none NULL + +static void res_true(Hook_State *hook) +{ + if (lua_toboolean(gL, -1)) + hook->status = true; +} + +static void res_false(Hook_State *hook) +{ + if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1)) + hook->status = false; +} + +static void res_force(Hook_State *hook) +{ + if (!lua_isnil(gL, -1)) + { if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + hook->status = 1; // Force yes + else + hook->status = 2; // Force no } - - lua_settop(gL, 0); - return hooked; } -boolean LUAh_PlayerHook(player_t *plr, enum hook which) +/* ========================================================================= + GENERALISED HOOKS + ========================================================================= */ + +int LUA_HookMobj(mobj_t *mobj, int hook_type) { - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = playerhooks; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_mobj_hook(&hook, false, hook_type, mobj->type)) { - if (hookp->type != which) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, plr, META_PLAYER); - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, mobj, META_MOBJ); + call_hooks(&hook, 1, res_true); } - - lua_settop(gL, 0); - return hooked; + return hook.status; } -// Hook for map change (before load) -void LUAh_MapChange(INT16 mapnumber) +int LUA_Hook2Mobj(mobj_t *t1, mobj_t *t2, int hook_type) { - hook_p hookp; - if (!gL || !(hooksAvailable[hook_MapChange/8] & (1<<(hook_MapChange%8)))) - return; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - lua_pushinteger(gL, mapnumber); - - for (hookp = roothook; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_mobj_hook(&hook, 0, hook_type, t1->type)) { - if (hookp->type != hook_MapChange) - continue; - - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 0, 1)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - } + LUA_PushUserdata(gL, t1, META_MOBJ); + LUA_PushUserdata(gL, t2, META_MOBJ); + call_hooks(&hook, 1, res_force); } - - lua_settop(gL, 0); + return hook.status; } -// Hook for map load -void LUAh_MapLoad(void) +void LUA_HookVoid(int type) { - hook_p hookp; - if (!gL || !(hooksAvailable[hook_MapLoad/8] & (1<<(hook_MapLoad%8)))) - return; + Hook_State hook; + if (prepare_hook(&hook, 0, type)) + call_hooks(&hook, 0, res_none); +} - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - lua_pushinteger(gL, gamemap); - - for (hookp = roothook; hookp; hookp = hookp->next) +void LUA_HookInt(INT32 number, int hook_type) +{ + Hook_State hook; + if (prepare_hook(&hook, 0, hook_type)) { - if (hookp->type != hook_MapLoad) - continue; - - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 0, 1)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - } + lua_pushinteger(gL, number); + call_hooks(&hook, 0, res_none); } - - lua_settop(gL, 0); } -// Hook for Got_AddPlayer -void LUAh_PlayerJoin(int playernum) +void LUA_HookBool(boolean value, int hook_type) { - hook_p hookp; - if (!gL || !(hooksAvailable[hook_PlayerJoin/8] & (1<<(hook_PlayerJoin%8)))) - return; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - lua_pushinteger(gL, playernum); - - for (hookp = roothook; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, 0, hook_type)) { - if (hookp->type != hook_PlayerJoin) - continue; - - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 0, 1)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - } + lua_pushboolean(gL, value); + call_hooks(&hook, 0, res_none); } - - lua_settop(gL, 0); } -// Hook for frame (before mobj and player thinkers) -void LUAh_PreThinkFrame(void) +int LUA_HookPlayer(player_t *player, int hook_type) { - hook_p hookp; - if (!gL || !(hooksAvailable[hook_PreThinkFrame/8] & (1<<(hook_PreThinkFrame%8)))) - return; - - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, false, hook_type)) { - if (hookp->type != hook_PreThinkFrame) - continue; - - PushHook(gL, hookp); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } + LUA_PushUserdata(gL, player, META_PLAYER); + call_hooks(&hook, 1, res_true); } - - lua_pop(gL, 1); // Pop error handler + return hook.status; } -// Hook for frame (after mobj and player thinkers) -void LUAh_ThinkFrame(void) +int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type) { - hook_p hookp; + Hook_State hook; + if (prepare_hook(&hook, false, hook_type)) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, cmd, META_TICCMD); + + if (hook_type == HOOK(PlayerCmd)) + hook_cmd_running = true; + + call_hooks(&hook, 1, res_true); + + if (hook_type == HOOK(PlayerCmd)) + hook_cmd_running = false; + } + 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 + ========================================================================= */ + +void LUA_HookThinkFrame(void) +{ + const int type = HOOK(ThinkFrame); + // variables used by perf stats int hook_index = 0; - int time_taken = 0; - if (!gL || !(hooksAvailable[hook_ThinkFrame/8] & (1<<(hook_ThinkFrame%8)))) - return; + precise_t time_taken = 0; - lua_pushcfunction(gL, LUA_GetErrorMessage); + Hook_State hook; - for (hookp = roothook; hookp; hookp = hookp->next) + const hook_t * map = &hookIds[type]; + int k; + + if (prepare_hook(&hook, 0, type)) { - if (hookp->type != hook_ThinkFrame) - continue; + init_hook_call(&hook, 0, res_none); - if (cv_perfstats.value == 3) - time_taken = I_GetPreciseTime(); - PushHook(gL, hookp); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } - if (cv_perfstats.value == 3) + for (k = 0; k < map->numHooks; ++k) { - lua_Debug ar; - time_taken = I_GetPreciseTime() - time_taken; - // we need the function, let's just retrieve it again - PushHook(gL, hookp); - lua_getinfo(gL, ">S", &ar); - PS_SetThinkFrameHookInfo(hook_index, time_taken, ar.short_src); - hook_index++; - } - } + get_hook(&hook, map->ids, k); - lua_pop(gL, 1); // Pop error handler -} - -// Hook for frame (at end of tick, ie after overlays, precipitation, specials) -void LUAh_PostThinkFrame(void) -{ - hook_p hookp; - if (!gL || !(hooksAvailable[hook_PostThinkFrame/8] & (1<<(hook_PostThinkFrame%8)))) - return; - - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) - { - if (hookp->type != hook_PostThinkFrame) - continue; - - PushHook(gL, hookp); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } - } - - lua_pop(gL, 1); // Pop error handler -} - -// Hook for mobj collisions -UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) -{ - hook_p hookp; - UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) - return 0; - - I_Assert(thing1->type < NUMMOBJTYPES); - - if (!(mobjcollidehooks[MT_NULL] || mobjcollidehooks[thing1->type])) - return 0; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic mobj collision hooks - for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) - { - if (hookp->type != which) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); - } - - for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next) - { - if (hookp->type != which) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return shouldCollide; -} - -UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which) -{ - hook_p hookp; - UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[which/8] & (1<<(which%8)))) - return 0; - - I_Assert(thing->type < NUMMOBJTYPES); - - if (!(mobjcollidehooks[MT_NULL] || mobjcollidehooks[thing->type])) - return 0; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic mobj collision hooks - for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) - { - if (hookp->type != which) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, thing, META_MOBJ); - LUA_PushUserdata(gL, line, META_LINE); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); - } - - for (hookp = mobjcollidehooks[thing->type]; hookp; hookp = hookp->next) - { - if (hookp->type != which) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, thing, META_MOBJ); - LUA_PushUserdata(gL, line, META_LINE); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return shouldCollide; -} - -// Hook for mobj thinkers -boolean LUAh_MobjThinker(mobj_t *mo) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_MobjThinker/8] & (1<<(hook_MobjThinker%8)))) - return false; - - I_Assert(mo->type < NUMMOBJTYPES); - - if (!(mobjthinkerhooks[MT_NULL] || mobjthinkerhooks[mo->type])) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic mobj thinker hooks - for (hookp = mobjthinkerhooks[MT_NULL]; hookp; hookp = hookp->next) - { - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, mo, META_MOBJ); - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - for (hookp = mobjthinkerhooks[mo->type]; hookp; hookp = hookp->next) - { - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - LUA_PushUserdata(gL, mo, META_MOBJ); - PushHook(gL, hookp); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return hooked; -} - -// Hook for P_TouchSpecialThing by mobj type -boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_TouchSpecial/8] & (1<<(hook_TouchSpecial%8)))) - return false; - - I_Assert(special->type < NUMMOBJTYPES); - - if (!(mobjhooks[MT_NULL] || mobjhooks[special->type])) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic touch special hooks - for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_TouchSpecial) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_TouchSpecial) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return hooked; -} - -// Hook for P_DamageMobj by mobj type (Should mobj take damage?) -UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) -{ - hook_p hookp; - UINT8 shouldDamage = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_ShouldDamage/8] & (1<<(hook_ShouldDamage%8)))) - return 0; - - I_Assert(target->type < NUMMOBJTYPES); - - if (!(mobjhooks[MT_NULL] || mobjhooks[target->type])) - return 0; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic should damage hooks - for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_ShouldDamage) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); - } - - for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_ShouldDamage) - continue; - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return shouldDamage; -} - -// Hook for P_DamageMobj by mobj type (Mobj actually takes damage!) -boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_MobjDamage/8] & (1<<(hook_MobjDamage%8)))) - return false; - - I_Assert(target->type < NUMMOBJTYPES); - - if (!(mobjhooks[MT_NULL] || mobjhooks[target->type])) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic mobj damage hooks - for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_MobjDamage) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_MobjDamage) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return hooked; -} - -// Hook for P_KillMobj by mobj type -boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_MobjDeath/8] & (1<<(hook_MobjDeath%8)))) - return false; - - I_Assert(target->type < NUMMOBJTYPES); - - if (!(mobjhooks[MT_NULL] || mobjhooks[target->type])) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic mobj death hooks - for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_MobjDeath) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damagetype); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_MobjDeath) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damagetype); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return hooked; -} - -// Hook for B_BuildTiccmd -boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_BotTiccmd/8] & (1<<(hook_BotTiccmd%8)))) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) - { - if (hookp->type != hook_BotTiccmd) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, bot, META_PLAYER); - LUA_PushUserdata(gL, cmd, META_TICCMD); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return hooked; -} - -// Hook for B_BuildTailsTiccmd by skin name -boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_BotAI/8] & (1<<(hook_BotAI%8)))) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) - { - if (hookp->type != hook_BotAI - || (hookp->s.str && strcmp(hookp->s.str, ((skin_t*)tails->skin)->name))) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, sonic, META_MOBJ); - LUA_PushUserdata(gL, tails, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 8, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - - // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. - if (lua_istable(gL, 2+1)) { - boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; -#define CHECKFIELD(field) \ - lua_getfield(gL, 2+1, #field);\ - if (lua_toboolean(gL, -1))\ - field = true;\ - lua_pop(gL, 1); - - CHECKFIELD(forward) - CHECKFIELD(backward) - CHECKFIELD(left) - CHECKFIELD(right) - CHECKFIELD(strafeleft) - CHECKFIELD(straferight) - CHECKFIELD(jump) - CHECKFIELD(spin) -#undef CHECKFIELD - B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); - } else - B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8)); - - lua_pop(gL, 8); - hooked = true; - } - - lua_settop(gL, 0); - return hooked; -} - -// Hook for B_CheckRespawn -boolean LUAh_BotRespawn(mobj_t *sonic, mobj_t *tails) -{ - hook_p hookp; - UINT8 shouldRespawn = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_BotRespawn/8] & (1<<(hook_BotRespawn%8)))) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) - { - if (hookp->type != hook_BotRespawn) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, sonic, META_MOBJ); - LUA_PushUserdata(gL, tails, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldRespawn = 1; // Force yes - else - shouldRespawn = 2; // Force no - } - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return shouldRespawn; -} - -// Hook for linedef executors -boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_LinedefExecute/8] & (1<<(hook_LinedefExecute%8)))) - return 0; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next) - { - if (strcmp(hookp->s.str, line->stringargs[0])) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, line, META_LINE); - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, sector, META_SECTOR); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 0, 1)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - } - hooked = true; - } - - lua_settop(gL, 0); - return hooked; -} - - -boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) -{ - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_PlayerMsg/8] & (1<<(hook_PlayerMsg%8)))) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) - { - if (hookp->type != hook_PlayerMsg) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player - if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c - lua_pushinteger(gL, 3); // type - lua_pushnil(gL); // target - } else if (target == -1) { // sayteam - lua_pushinteger(gL, 1); // type - lua_pushnil(gL); // target - } else if (target == 0) { // say - lua_pushinteger(gL, 0); // type - lua_pushnil(gL); // target - } else { // sayto - lua_pushinteger(gL, 2); // type - LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target + if (cv_perfstats.value == 3) + { + lua_pushvalue(gL, -1);/* need the function again */ + time_taken = I_GetPreciseTime(); } - lua_pushstring(gL, msg); // msg - } - PushHook(gL, hookp); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - lua_settop(gL, 0); - return hooked; + call_single_hook(&hook); + + if (cv_perfstats.value == 3) + { + lua_Debug ar; + time_taken = I_GetPreciseTime() - time_taken; + lua_getinfo(gL, ">S", &ar); + PS_SetThinkFrameHookInfo(hook_index, time_taken, ar.short_src); + hook_index++; + } + } + + lua_settop(gL, 0); + } } - -// Hook for hurt messages -boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) +int LUA_HookMobjLineCollide(mobj_t *mobj, line_t *line) { - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_HurtMsg/8] & (1<<(hook_HurtMsg%8)))) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_mobj_hook(&hook, 0, MOBJ_HOOK(MobjLineCollide), mobj->type)) { - if (hookp->type != hook_HurtMsg - || (hookp->s.mt && !(inflictor && hookp->s.mt == inflictor->type))) - continue; + LUA_PushUserdata(gL, mobj, META_MOBJ); + LUA_PushUserdata(gL, line, META_LINE); + call_hooks(&hook, 1, res_force); + } + return hook.status; +} - if (lua_gettop(gL) == 1) +int LUA_HookTouchSpecial(mobj_t *special, mobj_t *toucher) +{ + Hook_State hook; + if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(TouchSpecial), special->type)) + { + LUA_PushUserdata(gL, special, META_MOBJ); + LUA_PushUserdata(gL, toucher, META_MOBJ); + call_hooks(&hook, 1, res_true); + } + return hook.status; +} + +static int damage_hook +( + mobj_t *target, + mobj_t *inflictor, + mobj_t *source, + INT32 damage, + UINT8 damagetype, + int hook_type, + Hook_Callback results_handler +){ + Hook_State hook; + if (prepare_mobj_hook(&hook, 0, hook_type, target->type)) + { + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + if (hook_type != MOBJ_HOOK(MobjDeath)) + lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); + call_hooks(&hook, 1, results_handler); + } + return hook.status; +} + +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), 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), 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), 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 { + mobj_t * tails; + ticcmd_t * cmd; +} BotAI_State; + +static boolean checkbotkey(const char *field) +{ + return lua_toboolean(gL, -1) && strcmp(lua_tostring(gL, -2), field) == 0; +} + +static void res_botai(Hook_State *hook) +{ + BotAI_State *botai = hook->userdata; + + int k[8]; + + int fields = 0; + + // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. + if (lua_istable(gL, -8)) { + lua_pushnil(gL); // key + while (lua_next(gL, -9)) { +#define CHECK(n, f) (checkbotkey(f) ? (k[(n)-1] = 1) : 0) + if ( + CHECK(1, "forward") || CHECK(2, "backward") || + CHECK(3, "left") || CHECK(4, "right") || + CHECK(5, "strafeleft") || CHECK(6, "straferight") || + CHECK(7, "jump") || CHECK(8, "spin") + ){ + if (8 <= ++fields) + { + lua_pop(gL, 2); // pop key and value + break; + } + } + + lua_pop(gL, 1); // pop value +#undef CHECK + } + } else { + while (fields < 8) { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damagetype); + k[fields] = lua_toboolean(gL, -8 + fields); + fields++; } - PushHook(gL, hookp); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); } - lua_settop(gL, 0); - return hooked; + B_KeysToTiccmd(botai->tails, botai->cmd, + k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7]); + + hook->status = true; } -void LUAh_NetArchiveHook(lua_CFunction archFunc) +int LUA_HookBotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) { - hook_p hookp; - int errorhandlerindex; - if (!gL || !(hooksAvailable[hook_NetVars/8] & (1<<(hook_NetVars%8)))) - return; + const char *skin = ((skin_t *)tails->skin)->name; - // stack: tables - I_Assert(lua_gettop(gL) > 0); - I_Assert(lua_istable(gL, -1)); + Hook_State hook; + BotAI_State botai; - lua_pushcfunction(gL, LUA_GetErrorMessage); - errorhandlerindex = lua_gettop(gL); - - // tables becomes an upvalue of archFunc - lua_pushvalue(gL, -2); - lua_pushcclosure(gL, archFunc, 1); - // stack: tables, archFunc - - for (hookp = roothook; hookp; hookp = hookp->next) + if (prepare_string_hook(&hook, false, STRING_HOOK(BotAI), skin)) { - if (hookp->type != hook_NetVars) - continue; + LUA_PushUserdata(gL, sonic, META_MOBJ); + LUA_PushUserdata(gL, tails, META_MOBJ); - PushHook(gL, hookp); - lua_pushvalue(gL, -2); // archFunc - if (lua_pcall(gL, 1, 0, errorhandlerindex)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - } + botai.tails = tails; + botai.cmd = cmd; + + hook.userdata = &botai; + + call_hooks(&hook, 8, res_botai); } - lua_pop(gL, 2); // Pop archFunc and error handler - // stack: tables + return hook.status; } -boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing) +void LUA_HookLinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) { - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_MapThingSpawn/8] & (1<<(hook_MapThingSpawn%8)))) - return false; - - if (!(mobjhooks[MT_NULL] || mobjhooks[mo->type])) - return false; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic mobj map thing spawn hooks - for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_string_hook + (&hook, 0, STRING_HOOK(LinedefExecute), line->stringargs[0])) { - if (hookp->type != hook_MapThingSpawn) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, mthing, META_MAPTHING); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, line, META_LINE); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, sector, META_SECTOR); + ps_lua_mobjhooks.value.i += call_hooks(&hook, 0, res_none); } - - for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_MapThingSpawn) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, mthing, META_MAPTHING); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return hooked; } -// Hook for P_PlayerAfterThink Smiles mobj-following -boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj) +int LUA_HookPlayerMsg(int source, int target, int flags, char *msg) { - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_FollowMobj/8] & (1<<(hook_FollowMobj%8)))) - return 0; - - if (!(mobjhooks[MT_NULL] || mobjhooks[mobj->type])) - return 0; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - // Look for all generic mobj follow item hooks - for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, false, HOOK(PlayerMsg))) { - if (hookp->type != hook_FollowMobj) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, mobj, META_MOBJ); + LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player + if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c + lua_pushinteger(gL, 3); // type + lua_pushnil(gL); // target + } else if (target == -1) { // sayteam + lua_pushinteger(gL, 1); // type + lua_pushnil(gL); // target + } else if (target == 0) { // say + lua_pushinteger(gL, 0); // type + lua_pushnil(gL); // target + } else { // sayto + lua_pushinteger(gL, 2); // type + LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + lua_pushstring(gL, msg); // msg + call_hooks(&hook, 1, res_true); } - - for (hookp = mobjhooks[mobj->type]; hookp; hookp = hookp->next) - { - if (hookp->type != hook_FollowMobj) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, mobj, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); - } - - lua_settop(gL, 0); - return hooked; + return hook.status; } -// Hook for P_PlayerCanDamage -UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj) +int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 damagetype) { - hook_p hookp; - UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_PlayerCanDamage/8] & (1<<(hook_PlayerCanDamage%8)))) - return 0; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = playerhooks; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, false, HOOK(HurtMsg))) { - if (hookp->type != hook_PlayerCanDamage) - continue; - - ps_lua_mobjhooks++; - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, mobj, META_MOBJ); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); + call_hooks(&hook, 1, res_true); } - - lua_settop(gL, 0); - return shouldCollide; + return hook.status; } -void LUAh_PlayerQuit(player_t *plr, kickreason_t reason) +void LUA_HookNetArchive(lua_CFunction archFunc) { - hook_p hookp; - if (!gL || !(hooksAvailable[hook_PlayerQuit/8] & (1<<(hook_PlayerQuit%8)))) - return; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) + const hook_t * map = &hookIds[HOOK(NetVars)]; + Hook_State hook; + /* this is a remarkable case where the stack isn't reset */ + if (map->numHooks > 0) { - if (hookp->type != hook_PlayerQuit) - continue; + // stack: tables + I_Assert(lua_gettop(gL) > 0); + I_Assert(lua_istable(gL, -1)); - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit - lua_pushinteger(gL, reason); // Reason for quitting - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 0, 1)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - } + 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, 0, res_none); + call_mapped(&hook, map); + + lua_pop(gL, 1); // pop archFunc + lua_remove(gL, EINDEX); // pop error handler + // stack: tables } - - lua_settop(gL, 0); } -// Hook for Y_Ticker -void LUAh_IntermissionThinker(void) +int LUA_HookMapThingSpawn(mobj_t *mobj, mapthing_t *mthing) { - hook_p hookp; - if (!gL || !(hooksAvailable[hook_IntermissionThinker/8] & (1<<(hook_IntermissionThinker%8)))) - return; - - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(MapThingSpawn), mobj->type)) { - if (hookp->type != hook_IntermissionThinker) - continue; - - PushHook(gL, hookp); - if (lua_pcall(gL, 0, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } + LUA_PushUserdata(gL, mobj, META_MOBJ); + LUA_PushUserdata(gL, mthing, META_MAPTHING); + call_hooks(&hook, 1, res_true); } - - lua_pop(gL, 1); // Pop error handler + return hook.status; } -// Hook for team switching -// It's just an edit of LUAh_ViewpointSwitch. -boolean LUAh_TeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble) +int LUA_HookFollowMobj(player_t *player, mobj_t *mobj) { - hook_p hookp; - boolean canSwitchTeam = true; - if (!gL || !(hooksAvailable[hook_TeamSwitch/8] & (1<<(hook_TeamSwitch%8)))) - return true; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = playerhooks; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(FollowMobj), mobj->type)) { - if (hookp->type != hook_TeamSwitch) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - lua_pushinteger(gL, newteam); - lua_pushboolean(gL, fromspectators); - lua_pushboolean(gL, tryingautobalance); - lua_pushboolean(gL, tryingscramble); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1)) - canSwitchTeam = false; // Can't switch team - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, mobj, META_MOBJ); + call_hooks(&hook, 1, res_true); } - - lua_settop(gL, 0); - return canSwitchTeam; + return hook.status; } -// Hook for spy mode -UINT8 LUAh_ViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced) +int LUA_HookPlayerCanDamage(player_t *player, mobj_t *mobj) { - hook_p hookp; - UINT8 canSwitchView = 0; // 0 = default, 1 = force yes, 2 = force no. - if (!gL || !(hooksAvailable[hook_ViewpointSwitch/8] & (1<<(hook_ViewpointSwitch%8)))) - return 0; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - hud_running = true; // local hook - - for (hookp = playerhooks; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, 0, HOOK(PlayerCanDamage))) { - if (hookp->type != hook_ViewpointSwitch) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, newdisplayplayer, META_PLAYER); - lua_pushboolean(gL, forced); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave canSwitchView = 0. - if (lua_toboolean(gL, -1)) - canSwitchView = 1; // Force viewpoint switch - else - canSwitchView = 2; // Skip viewpoint switch - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, mobj, META_MOBJ); + call_hooks(&hook, 1, res_force); } - - lua_settop(gL, 0); - - hud_running = false; - - return canSwitchView; + return hook.status; } -// Hook for MT_NAMECHECK -boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend) +void LUA_HookPlayerQuit(player_t *plr, kickreason_t reason) { - hook_p hookp; - boolean hasSeenPlayer = true; - if (!gL || !(hooksAvailable[hook_SeenPlayer/8] & (1<<(hook_SeenPlayer%8)))) - return true; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - hud_running = true; // local hook - - for (hookp = playerhooks; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, 0, HOOK(PlayerQuit))) { - if (hookp->type != hook_SeenPlayer) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, seenfriend, META_PLAYER); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1) && !lua_toboolean(gL, -1)) - hasSeenPlayer = false; // Hasn't seen player - lua_pop(gL, 1); + LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit + lua_pushinteger(gL, reason); // Reason for quitting + call_hooks(&hook, 0, res_none); } - - lua_settop(gL, 0); - - hud_running = false; - - return hasSeenPlayer; } -boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname) +int LUA_HookTeamSwitch(player_t *player, int newteam, boolean fromspectators, boolean tryingautobalance, boolean tryingscramble) { - hook_p hookp; - boolean keepplaying = false; - if (!gL || !(hooksAvailable[hook_ShouldJingleContinue/8] & (1<<(hook_ShouldJingleContinue%8)))) - return true; - - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - hud_running = true; // local hook - - for (hookp = roothook; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, true, HOOK(TeamSwitch))) { - if (hookp->type != hook_ShouldJingleContinue - || (hookp->s.str && strcmp(hookp->s.str, musname))) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - lua_pushstring(gL, musname); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1) && lua_toboolean(gL, -1)) - keepplaying = true; // Keep playing this boolean - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + lua_pushinteger(gL, newteam); + lua_pushboolean(gL, fromspectators); + lua_pushboolean(gL, tryingautobalance); + lua_pushboolean(gL, tryingscramble); + call_hooks(&hook, 1, res_false); } - - lua_settop(gL, 0); - - hud_running = false; - - return keepplaying; + return hook.status; } -// Hook for game quitting -void LUAh_GameQuit(boolean quitting) +int LUA_HookViewpointSwitch(player_t *player, player_t *newdisplayplayer, boolean forced) { - hook_p hookp; - if (!gL || !(hooksAvailable[hook_GameQuit/8] & (1<<(hook_GameQuit%8)))) - return; - - lua_pushcfunction(gL, LUA_GetErrorMessage); - - for (hookp = roothook; hookp; hookp = hookp->next) + Hook_State hook; + if (prepare_hook(&hook, 0, HOOK(ViewpointSwitch))) { - if (hookp->type != hook_GameQuit) - continue; + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, newdisplayplayer, META_PLAYER); + lua_pushboolean(gL, forced); - PushHook(gL, hookp); - lua_pushboolean(gL, quitting); - if (lua_pcall(gL, 1, 0, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } + hud_running = true; // local hook + call_hooks(&hook, 1, res_force); + hud_running = false; } - - lua_pop(gL, 1); // Pop error handler + return hook.status; +} + +int LUA_HookSeenPlayer(player_t *player, player_t *seenfriend) +{ + Hook_State hook; + if (prepare_hook(&hook, true, HOOK(SeenPlayer))) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, seenfriend, META_PLAYER); + + hud_running = true; // local hook + call_hooks(&hook, 1, res_false); + hud_running = false; + } + return hook.status; +} + +int LUA_HookShouldJingleContinue(player_t *player, const char *musname) +{ + Hook_State hook; + if (prepare_string_hook + (&hook, false, STRING_HOOK(ShouldJingleContinue), musname)) + { + LUA_PushUserdata(gL, player, META_PLAYER); + push_string(); + + hud_running = true; // local hook + call_hooks(&hook, 1, res_true); + hud_running = false; + } + return hook.status; } -// Hook for building player's ticcmd struct (Ported from SRB2Kart) boolean hook_cmd_running = false; -boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd) + +static void update_music_name(struct MusicChange *musicchange) { - hook_p hookp; - boolean hooked = false; - if (!gL || !(hooksAvailable[hook_PlayerCmd/8] & (1<<(hook_PlayerCmd%8)))) - return false; + size_t length; + const char * new = lua_tolstring(gL, -6, &length); - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); - - hook_cmd_running = true; - for (hookp = roothook; hookp; hookp = hookp->next) + if (length < 7) { - if (hookp->type != hook_PlayerCmd) - continue; - - if (lua_gettop(gL) == 1) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, cmd, META_TICCMD); - } - PushHook(gL, hookp); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 1)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + strcpy(musicchange->newname, new); + lua_pushvalue(gL, -6);/* may as well keep it for next call */ + } + else + { + memcpy(musicchange->newname, new, 6); + musicchange->newname[6] = '\0'; + lua_pushlstring(gL, new, 6); } - lua_settop(gL, 0); - hook_cmd_running = false; - return hooked; + lua_replace(gL, -7); } -// Hook for music changes -boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, - UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms) +static void res_musicchange(Hook_State *hook) { - hook_p hookp; - boolean hooked = false; + struct MusicChange *musicchange = hook->userdata; - if (!gL || !(hooksAvailable[hook_MusicChange/8] & (1<<(hook_MusicChange%8)))) - return false; + // output 1: true, false, or string musicname override + if (lua_isstring(gL, -6)) + update_music_name(musicchange); + else if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6)) + hook->status = true; - lua_settop(gL, 0); - lua_pushcfunction(gL, LUA_GetErrorMessage); + // output 2: mflags override + if (lua_isnumber(gL, -5)) + *musicchange->mflags = lua_tonumber(gL, -5); + // output 3: looping override + if (lua_isboolean(gL, -4)) + *musicchange->looping = lua_toboolean(gL, -4); + // output 4: position override + if (lua_isnumber(gL, -3)) + *musicchange->position = lua_tonumber(gL, -3); + // output 5: prefadems override + if (lua_isnumber(gL, -2)) + *musicchange->prefadems = lua_tonumber(gL, -2); + // output 6: fadeinms override + if (lua_isnumber(gL, -1)) + *musicchange->fadeinms = lua_tonumber(gL, -1); +} - for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MusicChange) +int LUA_HookMusicChange(const char *oldname, struct MusicChange *param) +{ + const int type = HOOK(MusicChange); + const hook_t * map = &hookIds[type]; + + Hook_State hook; + + int k; + + if (prepare_hook(&hook, false, type)) + { + init_hook_call(&hook, 6, res_musicchange); + hook.values = 7;/* values pushed later */ + hook.userdata = param; + + lua_pushstring(gL, oldname);/* the only constant value */ + lua_pushstring(gL, param->newname);/* semi constant */ + + for (k = 0; k < map->numHooks; ++k) { - PushHook(gL, hookp); - lua_pushstring(gL, oldname); - lua_pushstring(gL, newname); - lua_pushinteger(gL, *mflags); - lua_pushboolean(gL, *looping); - lua_pushinteger(gL, *position); - lua_pushinteger(gL, *prefadems); - lua_pushinteger(gL, *fadeinms); - if (lua_pcall(gL, 7, 6, 1)) { - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); - lua_pop(gL, 1); - continue; - } + get_hook(&hook, map->ids, k); - // output 1: true, false, or string musicname override - if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6)) - hooked = true; - else if (lua_isstring(gL, -6)) - strncpy(newname, lua_tostring(gL, -6), 7); - // output 2: mflags override - if (lua_isnumber(gL, -5)) - *mflags = lua_tonumber(gL, -5); - // output 3: looping override - if (lua_isboolean(gL, -4)) - *looping = lua_toboolean(gL, -4); - // output 4: position override - if (lua_isboolean(gL, -3)) - *position = lua_tonumber(gL, -3); - // output 5: prefadems override - if (lua_isboolean(gL, -2)) - *prefadems = lua_tonumber(gL, -2); - // output 6: fadeinms override - if (lua_isboolean(gL, -1)) - *fadeinms = lua_tonumber(gL, -1); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + lua_pushinteger(gL, *param->mflags); + lua_pushboolean(gL, *param->looping); + lua_pushinteger(gL, *param->position); + lua_pushinteger(gL, *param->prefadems); + lua_pushinteger(gL, *param->fadeinms); - lua_pop(gL, 7); // Pop returned values and error handler + call_single_hook_no_copy(&hook); } - lua_settop(gL, 0); - newname[6] = 0; - return hooked; + lua_settop(gL, 0); + } + + return hook.status; +} + +static void res_playerheight(Hook_State *hook) +{ + if (!lua_isnil(gL, -1)) + { + fixed_t returnedheight = lua_tonumber(gL, -1); + // 0 height has... strange results, but it's not problematic like negative heights are. + // when an object's height is set to a negative number directly with lua, it's forced to 0 instead. + // here, I think it's better to ignore negatives so that they don't replace any results of previous hooks! + if (returnedheight >= 0) + hook->status = returnedheight; + } +} + +fixed_t LUA_HookPlayerHeight(player_t *player) +{ + Hook_State hook; + if (prepare_hook(&hook, -1, HOOK(PlayerHeight))) + { + LUA_PushUserdata(gL, player, META_PLAYER); + call_hooks(&hook, 1, res_playerheight); + } + return hook.status; +} + +int LUA_HookPlayerCanEnterSpinGaps(player_t *player) +{ + Hook_State hook; + if (prepare_hook(&hook, 0, HOOK(PlayerCanEnterSpinGaps))) + { + LUA_PushUserdata(gL, player, META_PLAYER); + call_hooks(&hook, 1, res_force); + } + return hook.status; } diff --git a/src/lua_hud.h b/src/lua_hud.h index 4a7c596c8..ad2b51d3e 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2014-2016 by John "JTE" Muniz. -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -13,6 +13,7 @@ enum hud { hud_stagetitle = 0, hud_textspectator, + hud_crosshair, // Singleplayer / Co-op hud_score, hud_time, @@ -36,7 +37,9 @@ enum hud { hud_tabemblems, // Intermission hud_intermissiontally, + hud_intermissiontitletext, hud_intermissionmessages, + hud_intermissionemeralds, hud_MAX }; @@ -44,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(void); +void LUA_SetHudHook(int hook); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index e58cd4a58..c7f2bbc28 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2014-2016 by John "JTE" Muniz. -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -23,22 +23,23 @@ #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", "textspectator", + "crosshair", "score", "time", @@ -62,7 +63,9 @@ static const char *const hud_disable_options[] = { "tabemblems", "intermissiontally", + "intermissiontitletext", "intermissionmessages", + "intermissionemeralds", NULL}; enum hudinfo { @@ -92,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, @@ -381,6 +369,74 @@ static int camera_get(lua_State *L) return 1; } +static int camera_set(lua_State *L) +{ + camera_t *cam = *((camera_t **)luaL_checkudata(L, 1, META_CAMERA)); + enum cameraf field = luaL_checkoption(L, 2, NULL, camera_opt); + + I_Assert(cam != NULL); + + switch(field) + { + case camera_subsector: + case camera_floorz: + case camera_ceilingz: + case camera_x: + case camera_y: + return luaL_error(L, LUA_QL("camera_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("P_TryCameraMove") " or " LUA_QL("P_TeleportCameraMove") " instead.", camera_opt[field]); + case camera_chase: { + INT32 chase = luaL_checkboolean(L, 3); + if (cam == &camera) + CV_SetValue(&cv_chasecam, chase); + else if (cam == &camera2) + CV_SetValue(&cv_chasecam2, chase); + else // ??? this should never happen, but ok + cam->chase = chase; + break; + } + case camera_aiming: + cam->aiming = luaL_checkangle(L, 3); + break; + case camera_z: + cam->z = luaL_checkfixed(L, 3); + P_CheckCameraPosition(cam->x, cam->y, cam); + cam->floorz = tmfloorz; + cam->ceilingz = tmceilingz; + break; + case camera_angle: + cam->angle = luaL_checkangle(L, 3); + break; + case camera_radius: + cam->radius = luaL_checkfixed(L, 3); + if (cam->radius < 0) + cam->radius = 0; + P_CheckCameraPosition(cam->x, cam->y, cam); + cam->floorz = tmfloorz; + cam->ceilingz = tmceilingz; + break; + case camera_height: + cam->height = luaL_checkfixed(L, 3); + if (cam->height < 0) + cam->height = 0; + P_CheckCameraPosition(cam->x, cam->y, cam); + cam->floorz = tmfloorz; + cam->ceilingz = tmceilingz; + break; + case camera_momx: + cam->momx = luaL_checkfixed(L, 3); + break; + case camera_momy: + cam->momy = luaL_checkfixed(L, 3); + break; + case camera_momz: + cam->momz = luaL_checkfixed(L, 3); + break; + default: + return luaL_error(L, LUA_QL("camera_t") " has no field named " LUA_QS, camera_opt[field]); + } + return 0; +} + // // lib_draw // @@ -660,6 +716,45 @@ static int libd_drawStretched(lua_State *L) return 0; } +static int libd_drawCropped(lua_State *L) +{ + fixed_t x, y, hscale, vscale, sx, sy, w, h; + INT32 flags; + patch_t *patch; + const UINT8 *colormap = NULL; + + HUDONLY + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + hscale = luaL_checkinteger(L, 3); + if (hscale < 0) + return luaL_error(L, "negative horizontal scale"); + vscale = luaL_checkinteger(L, 4); + if (vscale < 0) + return luaL_error(L, "negative vertical scale"); + patch = *((patch_t **)luaL_checkudata(L, 5, META_PATCH)); + flags = luaL_checkinteger(L, 6); + if (!lua_isnoneornil(L, 7)) + colormap = *((UINT8 **)luaL_checkudata(L, 7, META_COLORMAP)); + sx = luaL_checkinteger(L, 8); + if (sx < 0) // Don't crash. Now, we could do "x-=sx*FRACUNIT; sx=0;" here... + return luaL_error(L, "negative crop sx"); + sy = luaL_checkinteger(L, 9); + if (sy < 0) // ...but it's more truthful to just deny it, as negative values would crash + return luaL_error(L, "negative crop sy"); + w = luaL_checkinteger(L, 10); + if (w < 0) // Again, don't crash + return luaL_error(L, "negative crop w"); + h = luaL_checkinteger(L, 11); + if (h < 0) + return luaL_error(L, "negative crop h"); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + + V_DrawCroppedPatch(x, y, hscale, vscale, flags, patch, colormap, sx, sy, w, h); + return 0; +} + static int libd_drawNum(lua_State *L) { INT32 x, y, flags, num; @@ -856,6 +951,26 @@ static int libd_drawScaledNameTag(lua_State *L) return 0; } +static int libd_drawLevelTitle(lua_State *L) +{ + INT32 x; + INT32 y; + const char *str; + INT32 flags; + + HUDONLY + + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + str = luaL_checkstring(L, 3); + flags = luaL_optinteger(L, 4, 0); + + flags &= ~V_PARAMMASK; // Don't let crashes happen. + + V_DrawLevelTitle(x, y, flags, str); + return 0; +} + static int libd_stringWidth(lua_State *L) { const char *str = luaL_checkstring(L, 1); @@ -885,6 +1000,20 @@ static int libd_nameTagWidth(lua_State *L) return 1; } +static int libd_levelTitleWidth(lua_State *L) +{ + HUDONLY + lua_pushinteger(L, V_LevelNameWidth(luaL_checkstring(L, 1))); + return 1; +} + +static int libd_levelTitleHeight(lua_State *L) +{ + HUDONLY + lua_pushinteger(L, V_LevelNameHeight(luaL_checkstring(L, 1))); + return 1; +} + static int libd_getColormap(lua_State *L) { INT32 skinnum = TC_DEFAULT; @@ -1084,16 +1213,20 @@ 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}, {"drawString", libd_drawString}, {"drawNameTag", libd_drawNameTag}, {"drawScaledNameTag", libd_drawScaledNameTag}, + {"drawLevelTitle", libd_drawLevelTitle}, {"fadeScreen", libd_fadeScreen}, // misc {"stringWidth", libd_stringWidth}, {"nameTagWidth", libd_nameTagWidth}, + {"levelTitleWidth", libd_levelTitleWidth}, + {"levelTitleHeight", libd_levelTitleHeight}, // m_random {"RandomFixed",libd_RandomFixed}, {"RandomByte",libd_RandomByte}, @@ -1112,6 +1245,8 @@ static luaL_Reg lib_draw[] = { {NULL, NULL} }; +static int lib_draw_ref; + // // lib_hud // @@ -1146,28 +1281,7 @@ static int lib_hudenabled(lua_State *L) // add a HUD element for rendering -static int lib_hudadd(lua_State *L) -{ - enum hudhook field; - - luaL_checktype(L, 1, LUA_TFUNCTION); - field = luaL_checkoption(L, 2, "game", hudhook_opt); - - if (!lua_lumploading) - return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); - - lua_getfield(L, LUA_REGISTRYINDEX, "HUD"); - I_Assert(lua_istable(L, -1)); - lua_rawgeti(L, -1, field+2); // HUD[2+] - I_Assert(lua_istable(L, -1)); - lua_remove(L, -2); - - lua_pushvalue(L, 1); - lua_rawseti(L, -2, (int)(lua_objlen(L, -2) + 1)); - - hudAvailable |= 1<chatcolor); else if (fastcmp(field,"accessible")) lua_pushboolean(L, info->accessible); - else + else { CONS_Debug(DBG_LUA, M_GetText("'%s' has no field named '%s'; returning nil.\n"), "skincolor_t", field); + return 0; + } return 1; } diff --git a/src/lua_inputlib.c b/src/lua_inputlib.c new file mode 100644 index 000000000..1710b0355 --- /dev/null +++ b/src/lua_inputlib.c @@ -0,0 +1,270 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2021-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file lua_inputlib.c +/// \brief input library for Lua scripting + +#include "doomdef.h" +#include "fastcmp.h" +#include "g_input.h" +#include "g_game.h" +#include "hu_stuff.h" +#include "i_system.h" + +#include "lua_script.h" +#include "lua_libs.h" + +boolean mousegrabbedbylua = true; + +/////////////// +// FUNCTIONS // +/////////////// + +static int lib_gameControlDown(lua_State *L) +{ + int i = luaL_checkinteger(L, 1); + if (i < 0 || i >= NUM_GAMECONTROLS) + return luaL_error(L, "GC_* constant %d out of range (0 - %d)", i, NUM_GAMECONTROLS-1); + lua_pushinteger(L, PLAYER1INPUTDOWN(i)); + return 1; +} + +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); + lua_pushinteger(L, PLAYER2INPUTDOWN(i)); + return 1; +} + +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); + lua_pushinteger(L, gamecontrol[i][0]); + lua_pushinteger(L, gamecontrol[i][1]); + return 2; +} + +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); + lua_pushinteger(L, gamecontrolbis[i][0]); + lua_pushinteger(L, gamecontrolbis[i][1]); + return 2; +} + +static int lib_joyAxis(lua_State *L) +{ + int i = luaL_checkinteger(L, 1); + lua_pushinteger(L, JoyAxis(i)); + return 1; +} + +static int lib_joy2Axis(lua_State *L) +{ + int i = luaL_checkinteger(L, 1); + lua_pushinteger(L, Joy2Axis(i)); + return 1; +} + +static int lib_keyNumToName(lua_State *L) +{ + int i = luaL_checkinteger(L, 1); + lua_pushstring(L, G_KeyNumToName(i)); + return 1; +} + +static int lib_keyNameToNum(lua_State *L) +{ + const char *str = luaL_checkstring(L, 1); + lua_pushinteger(L, G_KeyNameToNum(str)); + return 1; +} + +static int lib_keyNumPrintable(lua_State *L) +{ + int i = luaL_checkinteger(L, 1); + lua_pushboolean(L, i >= 32 && i <= 127); + return 1; +} + +static int lib_shiftKeyNum(lua_State *L) +{ + int i = luaL_checkinteger(L, 1); + if (i >= 32 && i <= 127) + lua_pushinteger(L, shiftxform[i]); + return 1; +} + +static int lib_getMouseGrab(lua_State *L) +{ + lua_pushboolean(L, mousegrabbedbylua); + return 1; +} + +static int lib_setMouseGrab(lua_State *L) +{ + mousegrabbedbylua = luaL_checkboolean(L, 1); + I_UpdateMouseGrab(); + return 0; +} + +static int lib_getCursorPosition(lua_State *L) +{ + int x, y; + I_GetCursorPosition(&x, &y); + lua_pushinteger(L, x); + lua_pushinteger(L, y); + return 2; +} + +static luaL_Reg lib[] = { + {"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} +}; + +/////////////////// +// gamekeydown[] // +/////////////////// + +static int lib_getGameKeyDown(lua_State *L) +{ + int i = luaL_checkinteger(L, 2); + if (i < 0 || i >= NUMINPUTS) + return luaL_error(L, "gamekeydown[] index %d out of range (0 - %d)", i, NUMINPUTS-1); + lua_pushboolean(L, gamekeydown[i]); + return 1; +} + +static int lib_setGameKeyDown(lua_State *L) +{ + int i = luaL_checkinteger(L, 2); + boolean j = luaL_checkboolean(L, 3); + if (i < 0 || i >= NUMINPUTS) + return luaL_error(L, "gamekeydown[] index %d out of range (0 - %d)", i, NUMINPUTS-1); + gamekeydown[i] = j; + return 0; +} + +static int lib_lenGameKeyDown(lua_State *L) +{ + lua_pushinteger(L, NUMINPUTS); + 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 // +/////////// + +static int mouse_get(lua_State *L) +{ + mouse_t *m = *((mouse_t **)luaL_checkudata(L, 1, META_MOUSE)); + const char *field = luaL_checkstring(L, 2); + + I_Assert(m != NULL); + + if (fastcmp(field,"dx")) + lua_pushinteger(L, m->dx); + else if (fastcmp(field,"dy")) + lua_pushinteger(L, m->dy); + else if (fastcmp(field,"mlookdy")) + lua_pushinteger(L, m->mlookdy); + else if (fastcmp(field,"rdx")) + lua_pushinteger(L, m->rdx); + else if (fastcmp(field,"rdy")) + lua_pushinteger(L, m->rdy); + else if (fastcmp(field,"buttons")) + lua_pushinteger(L, m->buttons); + else + return luaL_error(L, "mouse_t has no field named %s", field); + + return 1; +} + +// #mouse -> 1 or 2 +static int mouse_num(lua_State *L) +{ + mouse_t *m = *((mouse_t **)luaL_checkudata(L, 1, META_MOUSE)); + + I_Assert(m != NULL); + + lua_pushinteger(L, m == &mouse ? 1 : 2); + return 1; +} + +int LUA_InputLib(lua_State *L) +{ + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, lib_getGameKeyDown); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_setGameKeyDown); + lua_setfield(L, -2, "__newindex"); + + lua_pushcfunction(L, lib_lenGameKeyDown); + lua_setfield(L, -2, "__len"); + 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"); + + lua_pushcfunction(L, mouse_num); + lua_setfield(L, -2, "__len"); + lua_pop(L, 1); + + luaL_register(L, "input", lib); + return 0; +} diff --git a/src/lua_libs.h b/src/lua_libs.h index 54ac89bcc..b4a891edb 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -12,6 +12,10 @@ extern lua_State *gL; +extern boolean mousegrabbedbylua; + +#define MUTABLE_TAGS + #define LREG_VALID "VALID_USERDATA" #define LREG_EXTVARS "LUA_VARS" #define LREG_STATEACTION "STATE_ACTION" @@ -27,6 +31,8 @@ extern lua_State *gL; #define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]" #define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*" +#define META_TAGLIST "TAGLIST" + #define META_MOBJ "MOBJ_T*" #define META_MAPTHING "MAPTHING_T*" @@ -58,6 +64,9 @@ extern lua_State *gL; #define META_CVAR "CONSVAR_T*" #define META_SECTORLINES "SECTOR_T*LINES" +#ifdef MUTABLE_TAGS +#define META_SECTORTAGLIST "sector_t.taglist" +#endif #define META_SIDENUM "LINE_T*SIDENUM" #define META_LINEARGS "LINE_T*ARGS" #define META_LINESTRINGARGS "LINE_T*STRINGARGS" @@ -81,6 +90,9 @@ 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); int LUA_EnumLib(lua_State *L); @@ -95,6 +107,8 @@ int LUA_PlayerLib(lua_State *L); int LUA_SkinLib(lua_State *L); int LUA_ThinkerLib(lua_State *L); int LUA_MapLib(lua_State *L); +int LUA_TagLib(lua_State *L); int LUA_PolyObjLib(lua_State *L); int LUA_BlockmapLib(lua_State *L); int LUA_HudLib(lua_State *L); +int LUA_InputLib(lua_State *L); diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 83744c74d..0c3440426 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -35,15 +35,27 @@ enum sector_e { sector_floorpic, sector_ceilingpic, sector_lightlevel, + sector_floorlightlevel, + sector_floorlightabsolute, + sector_ceilinglightlevel, + sector_ceilinglightabsolute, sector_special, sector_tag, + sector_taglist, sector_thinglist, sector_heightsec, sector_camsec, sector_lines, sector_ffloors, sector_fslope, - sector_cslope + sector_cslope, + sector_flags, + sector_specialflags, + sector_damagetype, + sector_triggertag, + sector_triggerer, + sector_friction, + sector_gravity, }; static const char *const sector_opt[] = { @@ -53,8 +65,13 @@ static const char *const sector_opt[] = { "floorpic", "ceilingpic", "lightlevel", + "floorlightlevel", + "floorlightabsolute", + "ceilinglightlevel", + "ceilinglightabsolute", "special", "tag", + "taglist", "thinglist", "heightsec", "camsec", @@ -62,6 +79,13 @@ static const char *const sector_opt[] = { "ffloors", "f_slope", "c_slope", + "flags", + "specialflags", + "damagetype", + "triggertag", + "triggerer", + "friction", + "gravity", NULL}; enum subsector_e { @@ -86,9 +110,11 @@ enum line_e { line_v2, line_dx, line_dy, + line_angle, line_flags, line_special, line_tag, + line_taglist, line_args, line_stringargs, line_sidenum, @@ -110,9 +136,11 @@ static const char *const line_opt[] = { "v2", "dx", "dy", + "angle", "flags", "special", "tag", + "taglist", "args", "stringargs", "sidenum", @@ -192,6 +220,13 @@ enum ffloor_e { ffloor_next, ffloor_prev, ffloor_alpha, + ffloor_blend, + ffloor_bustflags, + ffloor_busttype, + ffloor_busttag, + ffloor_sinkspeed, + ffloor_friction, + ffloor_bouncestrength, }; static const char *const ffloor_opt[] = { @@ -210,6 +245,13 @@ static const char *const ffloor_opt[] = { "next", "prev", "alpha", + "blend", + "bustflags", + "busttype", + "busttag", + "sinkspeed", + "friction", + "bouncestrength", NULL}; #ifdef HAVE_LUA_SEGS @@ -575,11 +617,26 @@ static int sector_get(lua_State *L) case sector_lightlevel: lua_pushinteger(L, sector->lightlevel); return 1; + case sector_floorlightlevel: + lua_pushinteger(L, sector->floorlightlevel); + return 1; + case sector_floorlightabsolute: + lua_pushboolean(L, sector->floorlightabsolute); + return 1; + case sector_ceilinglightlevel: + lua_pushinteger(L, sector->ceilinglightlevel); + return 1; + case sector_ceilinglightabsolute: + lua_pushboolean(L, sector->ceilinglightabsolute); + return 1; case sector_special: lua_pushinteger(L, sector->special); return 1; case sector_tag: - lua_pushinteger(L, Tag_FGet(§or->tags)); + lua_pushinteger(L, (UINT16)Tag_FGet(§or->tags)); + return 1; + case sector_taglist: + LUA_PushUserdata(L, §or->tags, META_SECTORTAGLIST); return 1; case sector_thinglist: // thinglist lua_pushcfunction(L, lib_iterateSectorThinglist); @@ -610,6 +667,27 @@ static int sector_get(lua_State *L) case sector_cslope: // c_slope LUA_PushUserdata(L, sector->c_slope, META_SLOPE); return 1; + case sector_flags: // flags + lua_pushinteger(L, sector->flags); + return 1; + case sector_specialflags: // specialflags + lua_pushinteger(L, sector->specialflags); + return 1; + case sector_damagetype: // damagetype + lua_pushinteger(L, (UINT8)sector->damagetype); + return 1; + case sector_triggertag: // triggertag + lua_pushinteger(L, (INT16)sector->triggertag); + return 1; + case sector_triggerer: // triggerer + lua_pushinteger(L, (UINT8)sector->triggerer); + return 1; + case sector_friction: // friction + lua_pushfixed(L, sector->friction); + return 1; + case sector_gravity: // gravity + lua_pushfixed(L, sector->gravity); + return 1; } return 0; } @@ -637,6 +715,7 @@ static int sector_set(lua_State *L) case sector_ffloors: // ffloors case sector_fslope: // f_slope case sector_cslope: // c_slope + case sector_friction: // friction default: return luaL_error(L, "sector_t field " LUA_QS " cannot be set.", sector_opt[field]); case sector_floorheight: { // floorheight @@ -676,12 +755,45 @@ static int sector_set(lua_State *L) case sector_lightlevel: sector->lightlevel = (INT16)luaL_checkinteger(L, 3); break; + case sector_floorlightlevel: + sector->floorlightlevel = (INT16)luaL_checkinteger(L, 3); + break; + case sector_floorlightabsolute: + sector->floorlightabsolute = luaL_checkboolean(L, 3); + break; + case sector_ceilinglightlevel: + sector->ceilinglightlevel = (INT16)luaL_checkinteger(L, 3); + break; + case sector_ceilinglightabsolute: + sector->ceilinglightabsolute = luaL_checkboolean(L, 3); + break; case sector_special: sector->special = (INT16)luaL_checkinteger(L, 3); break; case sector_tag: Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); break; + case sector_taglist: + return LUA_ErrSetDirectly(L, "sector_t", "taglist"); + case sector_flags: + sector->flags = luaL_checkinteger(L, 3); + CheckForReverseGravity |= (sector->flags & MSF_GRAVITYFLIP); + break; + case sector_specialflags: + sector->specialflags = luaL_checkinteger(L, 3); + break; + case sector_damagetype: + sector->damagetype = (UINT8)luaL_checkinteger(L, 3); + break; + case sector_triggertag: + sector->triggertag = (INT16)luaL_checkinteger(L, 3); + break; + case sector_triggerer: + sector->triggerer = (UINT8)luaL_checkinteger(L, 3); + break; + case sector_gravity: + sector->gravity = luaL_checkfixed(L, 3); + break; } return 0; } @@ -812,6 +924,9 @@ static int line_get(lua_State *L) case line_dy: lua_pushfixed(L, line->dy); return 1; + case line_angle: + lua_pushangle(L, line->angle); + return 1; case line_flags: lua_pushinteger(L, line->flags); return 1; @@ -819,8 +934,22 @@ static int line_get(lua_State *L) lua_pushinteger(L, line->special); return 1; case line_tag: + // HELLO + // THIS IS LJ SONIC + // HOW IS YOUR DAY? + // BY THE WAY WHEN 2.3 OR 3.0 OR 4.0 OR SRB3 OR SRB4 OR WHATEVER IS OUT + // YOU SHOULD REMEMBER TO CHANGE THIS SO IT ALWAYS RETURNS A UNSIGNED VALUE + // HAVE A NICE DAY + // + // + // + // + // you are ugly lua_pushinteger(L, Tag_FGet(&line->tags)); return 1; + case line_taglist: + LUA_PushUserdata(L, &line->tags, META_TAGLIST); + return 1; case line_args: LUA_PushUserdata(L, line->args, META_LINEARGS); return 1; @@ -1385,25 +1514,15 @@ static int lib_iterateSectors(lua_State *L) static int lib_getSector(lua_State *L) { - int field; INLEVEL - lua_settop(L, 2); - lua_remove(L, 1); // dummy userdata table is unused. - if (lua_isnumber(L, 1)) + if (lua_isnumber(L, 2)) { - size_t i = lua_tointeger(L, 1); + size_t i = lua_tointeger(L, 2); if (i >= numsectors) return 0; LUA_PushUserdata(L, §ors[i], META_SECTOR); return 1; } - field = luaL_checkoption(L, 1, NULL, array_opt); - switch(field) - { - case 0: // iterate - lua_pushcfunction(L, lib_iterateSectors); - return 1; - } return 0; } @@ -1489,25 +1608,15 @@ static int lib_iterateLines(lua_State *L) static int lib_getLine(lua_State *L) { - int field; INLEVEL - lua_settop(L, 2); - lua_remove(L, 1); // dummy userdata table is unused. - if (lua_isnumber(L, 1)) + if (lua_isnumber(L, 2)) { - size_t i = lua_tointeger(L, 1); + size_t i = lua_tointeger(L, 2); if (i >= numlines) return 0; LUA_PushUserdata(L, &lines[i], META_LINE); return 1; } - field = luaL_checkoption(L, 1, NULL, array_opt); - switch(field) - { - case 0: // iterate - lua_pushcfunction(L, lib_iterateLines); - return 1; - } return 0; } @@ -1804,6 +1913,27 @@ static int ffloor_get(lua_State *L) case ffloor_alpha: lua_pushinteger(L, ffloor->alpha); return 1; + case ffloor_blend: + lua_pushinteger(L, ffloor->blend); + return 1; + case ffloor_bustflags: + lua_pushinteger(L, ffloor->bustflags); + return 1; + case ffloor_busttype: + lua_pushinteger(L, ffloor->busttype); + return 1; + case ffloor_busttag: + lua_pushinteger(L, ffloor->busttag); + return 1; + case ffloor_sinkspeed: + lua_pushfixed(L, ffloor->sinkspeed); + return 1; + case ffloor_friction: + lua_pushfixed(L, ffloor->friction); + return 1; + case ffloor_bouncestrength: + lua_pushfixed(L, ffloor->bouncestrength); + return 1; } return 0; } @@ -1882,6 +2012,9 @@ static int ffloor_set(lua_State *L) case ffloor_alpha: ffloor->alpha = (INT32)luaL_checkinteger(L, 3); break; + case ffloor_blend: + ffloor->blend = (INT32)luaL_checkinteger(L, 3); + break; } return 0; } @@ -2360,15 +2493,13 @@ int LUA_MapLib(lua_State *L) //lua_setfield(L, -2, "__len"); lua_pop(L, 1); - lua_newuserdata(L, 0); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lib_getSector); - lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, lib_numsectors); - lua_setfield(L, -2, "__len"); - lua_setmetatable(L, -2); - lua_setglobal(L, "sectors"); + LUA_PushTaggableObjectArray(L, "sectors", + lib_iterateSectors, + lib_getSector, + lib_numsectors, + tags_sectors, + &numsectors, §ors, + sizeof (sector_t), META_SECTOR); lua_newuserdata(L, 0); lua_createtable(L, 0, 2); @@ -2380,15 +2511,13 @@ int LUA_MapLib(lua_State *L) lua_setmetatable(L, -2); lua_setglobal(L, "subsectors"); - lua_newuserdata(L, 0); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lib_getLine); - lua_setfield(L, -2, "__index"); - - lua_pushcfunction(L, lib_numlines); - lua_setfield(L, -2, "__len"); - lua_setmetatable(L, -2); - lua_setglobal(L, "lines"); + LUA_PushTaggableObjectArray(L, "lines", + lib_iterateLines, + lib_getLine, + lib_numlines, + tags_lines, + &numlines, &lines, + sizeof (line_t), META_LINE); lua_newuserdata(L, 0); lua_createtable(L, 0, 2); diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c index 10ba42ee0..c7501da60 100644 --- a/src/lua_mathlib.c +++ b/src/lua_mathlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,6 +15,8 @@ #include "tables.h" #include "p_local.h" #include "doomstat.h" // for ALL7EMERALDS +#include "r_main.h" // for R_PointToDist2 +#include "m_easing.h" #include "lua_script.h" #include "lua_libs.h" @@ -86,6 +88,18 @@ static int lib_finetangent(lua_State *L) return 1; } +static int lib_fixedasin(lua_State *L) +{ + lua_pushangle(L, -FixedAcos(luaL_checkfixed(L, 1)) + ANGLE_90); + return 1; +} + +static int lib_fixedacos(lua_State *L) +{ + lua_pushangle(L, FixedAcos(luaL_checkfixed(L, 1))); + return 1; +} + // Fixed math //////////////// @@ -129,7 +143,7 @@ static int lib_fixedsqrt(lua_State *L) static int lib_fixedhypot(lua_State *L) { - lua_pushfixed(L, FixedHypot(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2))); + lua_pushfixed(L, R_PointToDist2(0, 0, luaL_checkfixed(L, 1), luaL_checkfixed(L, 2))); return 1; } @@ -184,13 +198,15 @@ static int lib_coloropposite(lua_State *L) return 2; } -static luaL_Reg lib[] = { +static luaL_Reg lib_math[] = { {"abs", lib_abs}, {"min", lib_min}, {"max", lib_max}, {"sin", lib_finesine}, {"cos", lib_finecosine}, {"tan", lib_finetangent}, + {"asin", lib_fixedasin}, + {"acos", lib_fixedacos}, {"FixedAngle", lib_fixedangle}, {"fixangle" , lib_fixedangle}, {"AngleFixed", lib_anglefixed}, @@ -222,9 +238,123 @@ static luaL_Reg lib[] = { {NULL, NULL} }; +// +// Easing functions +// + +#define EASINGFUNC(easetype) \ +{ \ + fixed_t start = 0; \ + fixed_t end = FRACUNIT; \ + fixed_t t = luaL_checkfixed(L, 1); \ + int n = lua_gettop(L); \ + if (n == 2) \ + end = luaL_checkfixed(L, 2); \ + else if (n >= 3) \ + { \ + start = luaL_checkfixed(L, 2); \ + end = luaL_checkfixed(L, 3); \ + } \ + lua_pushfixed(L, (Easing_ ## easetype)(t, start, end)); \ + return 1; \ +} \ + +static int lib_easelinear(lua_State *L) { EASINGFUNC(Linear) } + +static int lib_easeinsine(lua_State *L) { EASINGFUNC(InSine) } +static int lib_easeoutsine(lua_State *L) { EASINGFUNC(OutSine) } +static int lib_easeinoutsine(lua_State *L) { EASINGFUNC(InOutSine) } + +static int lib_easeinquad(lua_State *L) { EASINGFUNC(InQuad) } +static int lib_easeoutquad(lua_State *L) { EASINGFUNC(OutQuad) } +static int lib_easeinoutquad(lua_State *L) { EASINGFUNC(InOutQuad) } + +static int lib_easeincubic(lua_State *L) { EASINGFUNC(InCubic) } +static int lib_easeoutcubic(lua_State *L) { EASINGFUNC(OutCubic) } +static int lib_easeinoutcubic(lua_State *L) { EASINGFUNC(InOutCubic) } + +static int lib_easeinquart(lua_State *L) { EASINGFUNC(InQuart) } +static int lib_easeoutquart(lua_State *L) { EASINGFUNC(OutQuart) } +static int lib_easeinoutquart(lua_State *L) { EASINGFUNC(InOutQuart) } + +static int lib_easeinquint(lua_State *L) { EASINGFUNC(InQuint) } +static int lib_easeoutquint(lua_State *L) { EASINGFUNC(OutQuint) } +static int lib_easeinoutquint(lua_State *L) { EASINGFUNC(InOutQuint) } + +static int lib_easeinexpo(lua_State *L) { EASINGFUNC(InExpo) } +static int lib_easeoutexpo(lua_State *L) { EASINGFUNC(OutExpo) } +static int lib_easeinoutexpo(lua_State *L) { EASINGFUNC(InOutExpo) } + +#undef EASINGFUNC + +#define EASINGFUNC(easetype) \ +{ \ + boolean useparam = false; \ + fixed_t param = 0; \ + fixed_t start = 0; \ + fixed_t end = FRACUNIT; \ + fixed_t t = luaL_checkfixed(L, 1); \ + int n = lua_gettop(L); \ + if (n == 2) \ + end = luaL_checkfixed(L, 2); \ + else if (n >= 3) \ + { \ + start = (fixed_t)luaL_optinteger(L, 2, start); \ + end = (fixed_t)luaL_optinteger(L, 3, end); \ + if ((n >= 4) && (useparam = (!lua_isnil(L, 4)))) \ + param = luaL_checkfixed(L, 4); \ + } \ + if (useparam) \ + lua_pushfixed(L, (Easing_ ## easetype ## Parameterized)(t, start, end, param)); \ + else \ + lua_pushfixed(L, (Easing_ ## easetype)(t, start, end)); \ + return 1; \ +} \ + +static int lib_easeinback(lua_State *L) { EASINGFUNC(InBack) } +static int lib_easeoutback(lua_State *L) { EASINGFUNC(OutBack) } +static int lib_easeinoutback(lua_State *L) { EASINGFUNC(InOutBack) } + +#undef EASINGFUNC + +static luaL_Reg lib_ease[] = { + {"linear", lib_easelinear}, + + {"insine", lib_easeinsine}, + {"outsine", lib_easeoutsine}, + {"inoutsine", lib_easeinoutsine}, + + {"inquad", lib_easeinquad}, + {"outquad", lib_easeoutquad}, + {"inoutquad", lib_easeinoutquad}, + + {"incubic", lib_easeincubic}, + {"outcubic", lib_easeoutcubic}, + {"inoutcubic", lib_easeinoutcubic}, + + {"inquart", lib_easeinquart}, + {"outquart", lib_easeoutquart}, + {"inoutquart", lib_easeinoutquart}, + + {"inquint", lib_easeinquint}, + {"outquint", lib_easeoutquint}, + {"inoutquint", lib_easeinoutquint}, + + {"inexpo", lib_easeinexpo}, + {"outexpo", lib_easeoutexpo}, + {"inoutexpo", lib_easeinoutexpo}, + + {"inback", lib_easeinback}, + {"outback", lib_easeoutback}, + {"inoutback", lib_easeinoutback}, + + {NULL, NULL} +}; + int LUA_MathLib(lua_State *L) { lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_register(L, NULL, lib); + luaL_register(L, NULL, lib_math); + luaL_register(L, "ease", lib_ease); return 0; } diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 7aae18c90..953b39000 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -12,6 +12,7 @@ #include "doomdef.h" #include "fastcmp.h" +#include "r_data.h" #include "r_skins.h" #include "p_local.h" #include "g_game.h" @@ -22,8 +23,6 @@ #include "lua_hud.h" // hud_running errors #include "lua_hook.h" // hook_cmd_running errors -static const char *const array_opt[] ={"iterate",NULL}; - enum mobj_e { mobj_valid = 0, mobj_x, @@ -656,8 +655,13 @@ static int mobj_set(lua_State *L) break; } case mobj_blendmode: - mo->blendmode = (INT32)luaL_checkinteger(L, 3); + { + INT32 blendmode = (INT32)luaL_checkinteger(L, 3); + if (blendmode < 0 || blendmode > AST_OVERLAY) + return luaL_error(L, "mobj.blendmode %d out of range (0 - %d).", blendmode, AST_OVERLAY); + mo->blendmode = blendmode; break; + } case mobj_bnext: return NOSETPOS; case mobj_bprev: @@ -904,6 +908,11 @@ static int mapthing_get(lua_State *L) number = mt->extrainfo; else if(fastcmp(field,"tag")) number = Tag_FGet(&mt->tags); + else if(fastcmp(field,"taglist")) + { + LUA_PushUserdata(L, &mt->tags, META_TAGLIST); + return 1; + } else if(fastcmp(field,"args")) { LUA_PushUserdata(L, mt->args, META_THINGARGS); @@ -966,6 +975,8 @@ static int mapthing_set(lua_State *L) } else if (fastcmp(field,"tag")) Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); + else if (fastcmp(field,"taglist")) + return LUA_ErrSetDirectly(L, "mapthing_t", "taglist"); else if(fastcmp(field,"mobj")) mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); else @@ -1003,25 +1014,15 @@ static int lib_iterateMapthings(lua_State *L) static int lib_getMapthing(lua_State *L) { - int field; INLEVEL - lua_settop(L, 2); - lua_remove(L, 1); // dummy userdata table is unused. - if (lua_isnumber(L, 1)) + if (lua_isnumber(L, 2)) { - size_t i = lua_tointeger(L, 1); + size_t i = lua_tointeger(L, 2); if (i >= nummapthings) return 0; LUA_PushUserdata(L, &mapthings[i], META_MAPTHING); return 1; } - field = luaL_checkoption(L, 1, NULL, array_opt); - switch(field) - { - case 0: // iterate - lua_pushcfunction(L, lib_iterateMapthings); - return 1; - } return 0; } @@ -1068,14 +1069,13 @@ int LUA_MobjLib(lua_State *L) lua_setfield(L, -2, "__len"); lua_pop(L,1); - lua_newuserdata(L, 0); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lib_getMapthing); - lua_setfield(L, -2, "__index"); + LUA_PushTaggableObjectArray(L, "mapthings", + lib_iterateMapthings, + lib_getMapthing, + lib_nummapthings, + tags_mapthings, + &nummapthings, &mapthings, + sizeof (mapthing_t), META_MAPTHING); - lua_pushcfunction(L, lib_nummapthings); - lua_setfield(L, -2, "__len"); - lua_setmetatable(L, -2); - lua_setglobal(L, "mapthings"); return 0; } diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 0eb54808f..58cfab76c 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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")) @@ -795,6 +812,7 @@ static int power_len(lua_State *L) } #define NOFIELD luaL_error(L, LUA_QL("ticcmd_t") " has no field named " LUA_QS, field) +#define NOSET luaL_error(L, LUA_QL("ticcmd_t") " field " LUA_QS " should not be set directly.", field) static int ticcmd_get(lua_State *L) { @@ -813,6 +831,8 @@ static int ticcmd_get(lua_State *L) lua_pushinteger(L, cmd->aiming); else if (fastcmp(field,"buttons")) lua_pushinteger(L, cmd->buttons); + else if (fastcmp(field,"latency")) + lua_pushinteger(L, cmd->latency); else return NOFIELD; @@ -839,6 +859,8 @@ static int ticcmd_set(lua_State *L) cmd->aiming = (INT16)luaL_checkinteger(L, 3); else if (fastcmp(field,"buttons")) cmd->buttons = (UINT16)luaL_checkinteger(L, 3); + else if (fastcmp(field,"latency")) + return NOSET; else return NOFIELD; @@ -846,6 +868,7 @@ static int ticcmd_set(lua_State *L) } #undef NOFIELD +#undef NOSET int LUA_PlayerLib(lua_State *L) { diff --git a/src/lua_polyobjlib.c b/src/lua_polyobjlib.c index 365d97056..a91c354f4 100644 --- a/src/lua_polyobjlib.c +++ b/src/lua_polyobjlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by Iestyn "Monster Iestyn" Jealous. -// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2020-2022 by Iestyn "Monster Iestyn" Jealous. +// Copyright (C) 2020-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -244,13 +244,14 @@ static int lib_polyobj_rotate(lua_State *L) { polyobj_t *po = *((polyobj_t **)luaL_checkudata(L, 1, META_POLYOBJ)); angle_t delta = luaL_checkangle(L, 2); - UINT8 turnthings = (UINT8)luaL_optinteger(L, 3, 0); // don't turn anything by default? (could change this if not desired) - boolean checkmobjs = lua_opttrueboolean(L, 4); + boolean turnplayers = lua_opttrueboolean(L, 3); + boolean turnothers = lua_opttrueboolean(L, 4); + boolean checkmobjs = lua_opttrueboolean(L, 5); NOHUD INLEVEL if (!po) return LUA_ErrInvalid(L, "polyobj_t"); - lua_pushboolean(L, Polyobj_rotate(po, delta, turnthings, checkmobjs)); + lua_pushboolean(L, Polyobj_rotate(po, delta, turnplayers, turnothers, checkmobjs)); return 1; } @@ -417,7 +418,7 @@ static int lib_getPolyObject(lua_State *L) { i = luaL_checkinteger(L, 2); if (i < 0 || i >= numPolyObjects) - return luaL_error(L, "PolyObjects[] index %d out of range (0 - %d)", i, numPolyObjects-1); + return luaL_error(L, "polyobjects[] index %d out of range (0 - %d)", i, numPolyObjects-1); LUA_PushUserdata(L, &PolyObjects[i], META_POLYOBJ); return 1; } @@ -481,6 +482,6 @@ int LUA_PolyObjLib(lua_State *L) lua_pushcfunction(L, lib_numPolyObjects); lua_setfield(L, -2, "__len"); lua_setmetatable(L, -2); - lua_setglobal(L, "PolyObjects"); + lua_setglobal(L, "polyobjects"); return 0; } diff --git a/src/lua_script.c b/src/lua_script.c index eb4737f76..a36e5bf98 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -20,11 +20,12 @@ #include "r_state.h" #include "r_sky.h" #include "g_game.h" +#include "g_input.h" #include "f_finale.h" #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 @@ -53,9 +54,11 @@ static lua_CFunction liblist[] = { LUA_SkinLib, // skin_t, skins[] LUA_ThinkerLib, // thinker_t LUA_MapLib, // line_t, side_t, sector_t, subsector_t + LUA_TagLib, // tags LUA_PolyObjLib, // polyobj_t LUA_BlockmapLib, // blockmap stuff LUA_HudLib, // HUD stuff + LUA_InputLib, // inputs NULL }; @@ -183,6 +186,9 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"modeattacking")) { lua_pushboolean(L, modeattacking); return 1; + } else if (fastcmp(word,"metalrecording")) { + lua_pushboolean(L, metalrecording); + return 1; } else if (fastcmp(word,"splitscreen")) { lua_pushboolean(L, splitscreen); return 1; @@ -332,7 +338,7 @@ int LUA_PushGlobals(lua_State *L, const char *word) return 1; // local player variables, by popular request } else if (fastcmp(word,"consoleplayer")) { // player controlling console (aka local player 1) - if (consoleplayer < 0 || !playeringame[consoleplayer]) + if (!addedtogame || consoleplayer < 0 || !playeringame[consoleplayer]) return 0; LUA_PushUserdata(L, &players[consoleplayer], META_PLAYER); return 1; @@ -379,6 +385,22 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word, "gamestate")) { lua_pushinteger(L, gamestate); return 1; + } else if (fastcmp(word, "stagefailed")) { + lua_pushboolean(L, stagefailed); + } else if (fastcmp(word, "mouse")) { + LUA_PushUserdata(L, &mouse, META_MOUSE); + return 1; + } 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; } @@ -428,6 +450,8 @@ int LUA_CheckGlobals(lua_State *L, const char *word) } else if (fastcmp(word, "mapmusflags")) mapmusflags = (UINT16)luaL_checkinteger(L, 2); + else if (fastcmp(word, "stagefailed")) + stagefailed = luaL_checkboolean(L, 2); else return 0; @@ -713,51 +737,42 @@ fixed_t LUA_EvalMath(const char *word) return res; } -/* -LUA_PushUserdata but no userdata is created. -You can't invalidate it therefore. -*/ - -void LUA_PushLightUserdata (lua_State *L, void *data, const char *meta) -{ - if (data) - { - lua_pushlightuserdata(L, data); - luaL_getmetatable(L, meta); - /* - The metatable is the last value on the stack, so this - applies it to the second value, which is the userdata. - */ - lua_setmetatable(L, -2); - } - else - lua_pushnil(L); -} - // Takes a pointer, any pointer, and a metatable name // Creates a userdata for that pointer with the given metatable // Pushes it to the stack and stores it in the registry. void LUA_PushUserdata(lua_State *L, void *data, const char *meta) { + if (LUA_RawPushUserdata(L, data) == LPUSHED_NEW) + { + luaL_getmetatable(L, meta); + lua_setmetatable(L, -2); + } +} + +// Same as LUA_PushUserdata but don't set a metatable yet. +lpushed_t LUA_RawPushUserdata(lua_State *L, void *data) +{ + lpushed_t status = LPUSHED_NIL; + void **userdata; if (!data) { // push a NULL lua_pushnil(L); - return; + return status; } lua_getfield(L, LUA_REGISTRYINDEX, LREG_VALID); I_Assert(lua_istable(L, -1)); + lua_pushlightuserdata(L, data); lua_rawget(L, -2); + if (lua_isnil(L, -1)) { // no userdata? deary me, we'll have to make one. lua_pop(L, 1); // pop the nil // create the userdata userdata = lua_newuserdata(L, sizeof(void *)); *userdata = data; - luaL_getmetatable(L, meta); - lua_setmetatable(L, -2); // Set it in the registry so we can find it again lua_pushlightuserdata(L, data); // k (store the userdata via the data's pointer) @@ -765,8 +780,15 @@ void LUA_PushUserdata(lua_State *L, void *data, const char *meta) lua_rawset(L, -4); // stack is left with the userdata on top, as if getting it had originally succeeded. + + status = LPUSHED_NEW; } + else + status = LPUSHED_EXISTING; + lua_remove(L, -2); // remove LREG_VALID + + return status; } // When userdata is freed, use this function to remove it from Lua. @@ -826,6 +848,7 @@ void LUA_InvalidateLevel(void) { LUA_InvalidateUserdata(§ors[i]); LUA_InvalidateUserdata(§ors[i].lines); + LUA_InvalidateUserdata(§ors[i].tags); if (sectors[i].ffloors) { for (rover = sectors[i].ffloors; rover; rover = rover->next) @@ -835,6 +858,9 @@ void LUA_InvalidateLevel(void) for (i = 0; i < numlines; i++) { 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++) @@ -847,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]); @@ -866,7 +899,12 @@ void LUA_InvalidateMapthings(void) return; for (i = 0; i < nummapthings; i++) + { LUA_InvalidateUserdata(&mapthings[i]); + LUA_InvalidateUserdata(&mapthings[i].tags); + LUA_InvalidateUserdata(mapthings[i].args); + LUA_InvalidateUserdata(mapthings[i].stringargs); + } } void LUA_InvalidatePlayer(player_t *player) @@ -909,6 +947,7 @@ enum ARCH_SLOPE, ARCH_MAPHEADER, ARCH_SKINCOLOR, + ARCH_MOUSE, ARCH_TEND=0xFF, }; @@ -936,6 +975,7 @@ static const struct { {META_SLOPE, ARCH_SLOPE}, {META_MAPHEADER, ARCH_MAPHEADER}, {META_SKINCOLOR, ARCH_SKINCOLOR}, + {META_MOUSE, ARCH_MOUSE}, {NULL, ARCH_NULL} }; @@ -1243,7 +1283,6 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) } break; } - case ARCH_SKINCOLOR: { skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex)); @@ -1251,6 +1290,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) WRITEUINT16(save_p, info - skincolors); break; } + case ARCH_MOUSE: + { + mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex)); + WRITEUINT8(save_p, ARCH_MOUSE); + WRITEUINT8(save_p, m == &mouse ? 1 : 2); + break; + } default: WRITEUINT8(save_p, ARCH_NULL); return 2; @@ -1346,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); } @@ -1502,6 +1540,9 @@ static UINT8 UnArchiveValue(int TABLESINDEX) case ARCH_SKINCOLOR: LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR); break; + case ARCH_MOUSE: + LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE); + break; case ARCH_TEND: return 1; } @@ -1628,7 +1669,7 @@ void LUA_Archive(void) WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. - LUAh_NetArchiveHook(NetArchive); // call the NetArchive hook in archive mode + LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode ArchiveTables(); if (gL) @@ -1663,7 +1704,7 @@ void LUA_UnArchive(void) } } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. - LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode + LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode UnArchiveTables(); if (gL) @@ -1681,3 +1722,36 @@ int Lua_optoption(lua_State *L, int narg, return i; return -1; } + +void LUA_PushTaggableObjectArray +( lua_State *L, + const char *field, + lua_CFunction iterator, + lua_CFunction indexer, + lua_CFunction counter, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char *meta) +{ + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, iterator); + lua_setfield(L, -2, "iterate"); + + LUA_InsertTaggroupIterator(L, garray, + max_elements, element_array, sizeof_element, meta); + + lua_createtable(L, 0, 1); + lua_pushcfunction(L, indexer); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, counter); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, field); +} diff --git a/src/lua_script.h b/src/lua_script.h index 79ba0bb38..e586b04a8 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -10,10 +10,14 @@ /// \file lua_script.h /// \brief Lua scripting basics +#ifndef LUA_SCRIPT_H +#define LUA_SCRIPT_H + #include "m_fixed.h" #include "doomtype.h" #include "d_player.h" #include "g_state.h" +#include "taglist.h" #include "blua/lua.h" #include "blua/lualib.h" @@ -46,28 +50,59 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump, boolean noresults); void LUA_DumpFile(const char *filename); #endif fixed_t LUA_EvalMath(const char *word); -void LUA_PushLightUserdata(lua_State *L, void *data, const char *meta); -void LUA_PushUserdata(lua_State *L, void *data, const char *meta); -void LUA_InvalidateUserdata(void *data); -void LUA_InvalidateLevel(void); -void LUA_InvalidateMapthings(void); -void LUA_InvalidatePlayer(player_t *player); void LUA_Step(void); void LUA_Archive(void); void LUA_UnArchive(void); int LUA_PushGlobals(lua_State *L, const char *word); int LUA_CheckGlobals(lua_State *L, const char *word); void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c -void LUA_CVarChanged(const char *name); // lua_consolelib.c +void LUA_CVarChanged(void *cvar); // lua_consolelib.c int Lua_optoption(lua_State *L, int narg, const char *def, const char *const lst[]); -void LUAh_NetArchiveHook(lua_CFunction archFunc); +void LUA_HookNetArchive(lua_CFunction archFunc); + +void LUA_PushTaggableObjectArray +( lua_State *L, + const char *field, + lua_CFunction iterator, + lua_CFunction indexer, + lua_CFunction counter, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char *meta); + +void LUA_InsertTaggroupIterator +( lua_State *L, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char * meta); + +typedef enum { + LPUSHED_NIL, + LPUSHED_NEW, + LPUSHED_EXISTING, +} lpushed_t; + +void LUA_PushUserdata(lua_State *L, void *data, const char *meta); +lpushed_t LUA_RawPushUserdata(lua_State *L, void *data); + +void LUA_InvalidateUserdata(void *data); + +void LUA_InvalidateLevel(void); +void LUA_InvalidateMapthings(void); +void LUA_InvalidatePlayer(player_t *player); // Console wrapper void COM_Lua_f(void); #define LUA_ErrInvalid(L, type) luaL_error(L, "accessed " type " doesn't exist anymore, please check 'valid' before using " type "."); +#define LUA_ErrSetDirectly(L, type, field) luaL_error(L, type " field " LUA_QL(field) " cannot be set directly.") + // Deprecation warnings // Shows once upon use. Then doesn't show again. #define LUA_Deprecated(L,this_func,use_instead)\ @@ -98,3 +133,5 @@ void COM_Lua_f(void); #define INLEVEL if (! ISINLEVEL)\ return luaL_error(L, "This can only be used in a level!"); + +#endif/*LUA_SCRIPT_H*/ diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c index 56be6bf4f..9c7c4ad03 100644 --- a/src/lua_skinlib.c +++ b/src/lua_skinlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2014-2016 by John "JTE" Muniz. -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -53,7 +53,6 @@ enum skin { skin_contspeed, skin_contangle, skin_soundsid, - skin_availability, skin_sprites }; static const char *const skin_opt[] = { @@ -91,7 +90,6 @@ static const char *const skin_opt[] = { "contspeed", "contangle", "soundsid", - "availability", "sprites", NULL}; @@ -209,11 +207,8 @@ static int skin_get(lua_State *L) case skin_soundsid: LUA_PushUserdata(L, skin->soundsid, META_SOUNDSID); break; - case skin_availability: - lua_pushinteger(L, skin->availability); - break; case skin_sprites: - LUA_PushLightUserdata(L, skin->sprites, META_SKINSPRITES); + LUA_PushUserdata(L, skin->sprites, META_SKINSPRITES); break; } return 1; @@ -336,13 +331,13 @@ static const char *const sprites_opt[] = { // skin.sprites[i] -> sprites[i] static int lib_getSkinSprite(lua_State *L) { - spritedef_t *sprites = (spritedef_t *)luaL_checkudata(L, 1, META_SKINSPRITES); + spritedef_t *sprites = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITES); playersprite_t i = luaL_checkinteger(L, 2); if (i < 0 || i >= NUMPLAYERSPRITES*2) return luaL_error(L, LUA_QL("skin_t") " field 'sprites' index %d out of range (0 - %d)", i, (NUMPLAYERSPRITES*2)-1); - LUA_PushLightUserdata(L, &sprites[i], META_SKINSPRITESLIST); + LUA_PushUserdata(L, &sprites[i], META_SKINSPRITESLIST); return 1; } @@ -355,7 +350,7 @@ static int lib_numSkinsSprites(lua_State *L) static int sprite_get(lua_State *L) { - spritedef_t *sprite = (spritedef_t *)luaL_checkudata(L, 1, META_SKINSPRITESLIST); + spritedef_t *sprite = *(spritedef_t **)luaL_checkudata(L, 1, META_SKINSPRITESLIST); enum spritesopt field = luaL_checkoption(L, 2, NULL, sprites_opt); switch (field) diff --git a/src/lua_taglib.c b/src/lua_taglib.c new file mode 100644 index 000000000..b69416362 --- /dev/null +++ b/src/lua_taglib.c @@ -0,0 +1,451 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020-2022 by James R. +// Copyright (C) 2020-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file lua_taglib.c +/// \brief tag list iterator for Lua scripting + +#include "doomdef.h" +#include "taglist.h" +#include "r_state.h" + +#include "lua_script.h" +#include "lua_libs.h" + +#ifdef MUTABLE_TAGS +#include "z_zone.h" +#endif + +static int tag_iterator(lua_State *L) +{ + INT32 tag = lua_isnil(L, 2) ? -1 : lua_tonumber(L, 2); + do + { + if (++tag >= MAXTAGS) + return 0; + } + while (! in_bit_array(tags_available, tag)) ; + lua_pushnumber(L, tag); + return 1; +} + +enum { +#define UPVALUE lua_upvalueindex + up_garray = UPVALUE(1), + up_max_elements = UPVALUE(2), + up_element_array = UPVALUE(3), + up_sizeof_element = UPVALUE(4), + up_meta = UPVALUE(5), +#undef UPVALUE +}; + +static INT32 next_element(lua_State *L, const mtag_t tag, const size_t p) +{ + taggroup_t ** garray = lua_touserdata(L, up_garray); + const size_t * max_elements = lua_touserdata(L, up_max_elements); + return Taggroup_Iterate(garray, *max_elements, tag, p); +} + +static void push_element(lua_State *L, void *element) +{ + if (LUA_RawPushUserdata(L, element) == LPUSHED_NEW) + { + lua_pushvalue(L, up_meta); + lua_setmetatable(L, -2); + } +} + +static void push_next_element(lua_State *L, const INT32 element) +{ + char * element_array = *(char **)lua_touserdata(L, up_element_array); + const size_t sizeof_element = lua_tonumber(L, up_sizeof_element); + push_element(L, &element_array[element * sizeof_element]); +} + +struct element_iterator_state { + mtag_t tag; + size_t p; +}; + +static int element_iterator(lua_State *L) +{ + struct element_iterator_state * state = lua_touserdata(L, 1); + if (lua_isnoneornil(L, 3)) + state->p = 0; + lua_pushnumber(L, ++state->p); + lua_gettable(L, 1); + return 1; +} + +static int lib_iterateTags(lua_State *L) +{ + if (lua_gettop(L) < 2) + { + lua_pushcfunction(L, tag_iterator); + return 1; + } + else + return tag_iterator(L); +} + +static int lib_numTags(lua_State *L) +{ + lua_pushnumber(L, num_tags); + return 1; +} + +static int lib_getTaggroup(lua_State *L) +{ + struct element_iterator_state *state; + + mtag_t tag; + + if (lua_gettop(L) > 1) + return luaL_error(L, "too many arguments"); + + if (lua_isnoneornil(L, 1)) + { + tag = MTAG_GLOBAL; + } + else + { + tag = lua_tonumber(L, 1); + luaL_argcheck(L, tag >= -1, 1, "tag out of range"); + } + + state = lua_newuserdata(L, sizeof *state); + state->tag = tag; + state->p = 0; + + lua_pushvalue(L, lua_upvalueindex(1)); + lua_setmetatable(L, -2); + + return 1; +} + +static int lib_getTaggroupElement(lua_State *L) +{ + const size_t p = luaL_checknumber(L, 2) - 1; + const mtag_t tag = *(mtag_t *)lua_touserdata(L, 1); + const INT32 element = next_element(L, tag, p); + + if (element == -1) + return 0; + else + { + push_next_element(L, element); + return 1; + } +} + +static int lib_numTaggroupElements(lua_State *L) +{ + const mtag_t tag = *(mtag_t *)lua_touserdata(L, 1); + if (tag == MTAG_GLOBAL) + lua_pushnumber(L, *(size_t *)lua_touserdata(L, up_max_elements)); + else + { + const taggroup_t ** garray = lua_touserdata(L, up_garray); + lua_pushnumber(L, Taggroup_Count(garray[tag])); + } + return 1; +} + +#ifdef MUTABLE_TAGS +static int meta_ref[2]; +#endif + +static int has_valid_field(lua_State *L) +{ + int equal; + lua_rawgeti(L, LUA_ENVIRONINDEX, 1); + equal = lua_rawequal(L, 2, -1); + lua_pop(L, 1); + return equal; +} + +static taglist_t * valid_taglist(lua_State *L, int idx, boolean getting) +{ + taglist_t *list = *(taglist_t **)lua_touserdata(L, idx); + + if (list == NULL) + { + if (getting && has_valid_field(L)) + lua_pushboolean(L, 0); + else + LUA_ErrInvalid(L, "taglist");/* doesn't actually return */ + return NULL; + } + else + return list; +} + +static taglist_t * check_taglist(lua_State *L, int idx) +{ + if (lua_isuserdata(L, idx) && lua_getmetatable(L, idx)) + { + lua_getref(L, meta_ref[0]); + lua_getref(L, meta_ref[1]); + + if (lua_rawequal(L, -3, -2) || lua_rawequal(L, -3, -1)) + { + lua_pop(L, 3); + return valid_taglist(L, idx, false); + } + } + + return luaL_argerror(L, idx, "must be a tag list"), NULL; +} + +static int taglist_get(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, true); + + if (list == NULL)/* valid check */ + return 1; + + if (lua_isnumber(L, 2)) + { + const size_t i = lua_tonumber(L, 2); + + if (list && i <= list->count) + { + lua_pushnumber(L, list->tags[i - 1]); + return 1; + } + else + return 0; + } + else if (has_valid_field(L)) + { + lua_pushboolean(L, 1); + return 1; + } + else + { + lua_getmetatable(L, 1); + lua_replace(L, 1); + lua_rawget(L, 1); + return 1; + } +} + +static int taglist_len(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, false); + lua_pushnumber(L, list->count); + return 1; +} + +static int taglist_equal(lua_State *L) +{ + const taglist_t *lhs = check_taglist(L, 1); + const taglist_t *rhs = check_taglist(L, 2); + lua_pushboolean(L, Tag_Compare(lhs, rhs)); + return 1; +} + +static int taglist_iterator(lua_State *L) +{ + const taglist_t *list = valid_taglist(L, 1, false); + const size_t i = 1 + lua_tonumber(L, lua_upvalueindex(1)); + if (i <= list->count) + { + lua_pushnumber(L, list->tags[i - 1]); + /* watch me exploit an upvalue as a control because + I want to use the control as the value */ + lua_pushnumber(L, i); + lua_replace(L, lua_upvalueindex(1)); + return 1; + } + else + return 0; +} + +static int taglist_iterate(lua_State *L) +{ + check_taglist(L, 1); + lua_pushnumber(L, 0); + lua_pushcclosure(L, taglist_iterator, 1); + lua_pushvalue(L, 1); + return 2; +} + +static int taglist_find(lua_State *L) +{ + const taglist_t *list = check_taglist(L, 1); + const mtag_t tag = luaL_checknumber(L, 2); + lua_pushboolean(L, Tag_Find(list, tag)); + return 1; +} + +static int taglist_shares(lua_State *L) +{ + const taglist_t *lhs = check_taglist(L, 1); + const taglist_t *rhs = check_taglist(L, 2); + lua_pushboolean(L, Tag_Share(lhs, rhs)); + return 1; +} + +/* only sector tags are mutable... */ + +#ifdef MUTABLE_TAGS +static size_t sector_of_taglist(taglist_t *list) +{ + return (sector_t *)((char *)list - offsetof (sector_t, tags)) - sectors; +} + +static int this_taglist(lua_State *L) +{ + lua_settop(L, 1); + return 1; +} + +static int taglist_add(lua_State *L) +{ + taglist_t *list = *(taglist_t **)luaL_checkudata(L, 1, META_SECTORTAGLIST); + const mtag_t tag = luaL_checknumber(L, 2); + + if (! Tag_Find(list, tag)) + { + Taggroup_Add(tags_sectors, tag, sector_of_taglist(list)); + Tag_Add(list, tag); + } + + return this_taglist(L); +} + +static int taglist_remove(lua_State *L) +{ + taglist_t *list = *(taglist_t **)luaL_checkudata(L, 1, META_SECTORTAGLIST); + const mtag_t tag = luaL_checknumber(L, 2); + + size_t i; + + for (i = 0; i < list->count; ++i) + { + if (list->tags[i] == tag) + { + if (list->count > 1) + { + memmove(&list->tags[i], &list->tags[i + 1], + (list->count - 1 - i) * sizeof (mtag_t)); + list->tags = Z_Realloc(list->tags, + (--list->count) * sizeof (mtag_t), PU_LEVEL, NULL); + Taggroup_Remove(tags_sectors, tag, sector_of_taglist(list)); + } + else/* reset to default tag */ + Tag_SectorFSet(sector_of_taglist(list), 0); + break; + } + } + + return this_taglist(L); +} +#endif/*MUTABLE_TAGS*/ + +void LUA_InsertTaggroupIterator +( lua_State *L, + taggroup_t *garray[], + size_t * max_elements, + void * element_array, + size_t sizeof_element, + const char * meta) +{ + lua_createtable(L, 0, 3); + lua_pushlightuserdata(L, garray); + lua_pushlightuserdata(L, max_elements); + + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_pushlightuserdata(L, element_array); + lua_pushnumber(L, sizeof_element); + luaL_getmetatable(L, meta); + lua_pushcclosure(L, lib_getTaggroupElement, 5); + lua_setfield(L, -4, "__index"); + + lua_pushcclosure(L, lib_numTaggroupElements, 2); + lua_setfield(L, -2, "__len"); + + lua_pushcfunction(L, element_iterator); + lua_setfield(L, -2, "__call"); + lua_pushcclosure(L, lib_getTaggroup, 1); + lua_setfield(L, -2, "tagged"); +} + +static luaL_Reg taglist_lib[] = { + {"iterate", taglist_iterate}, + {"find", taglist_find}, + {"shares", taglist_shares}, +#ifdef MUTABLE_TAGS + {"add", taglist_add}, + {"remove", taglist_remove}, +#endif + {0} +}; + +static void open_taglist(lua_State *L) +{ + luaL_register(L, "taglist", taglist_lib); + + lua_getfield(L, -1, "find"); + lua_setfield(L, -2, "has"); +} + +#define new_literal(L, s) \ + (lua_pushliteral(L, s), luaL_ref(L, -2)) + +#ifdef MUTABLE_TAGS +static int +#else +static void +#endif +set_taglist_metatable(lua_State *L, const char *meta) +{ + luaL_newmetatable(L, meta); + lua_pushcfunction(L, taglist_get); + lua_createtable(L, 0, 1); + new_literal(L, "valid"); + lua_setfenv(L, -2); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, taglist_len); + lua_setfield(L, -2, "__len"); + + lua_pushcfunction(L, taglist_equal); + lua_setfield(L, -2, "__eq"); +#ifdef MUTABLE_TAGS + return luaL_ref(L, LUA_REGISTRYINDEX); +#endif +} + +int LUA_TagLib(lua_State *L) +{ + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_createtable(L, 0, 1); + lua_pushcfunction(L, lib_iterateTags); + lua_setfield(L, -2, "iterate"); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_numTags); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "tags"); + + open_taglist(L); + +#ifdef MUTABLE_TAGS + meta_ref[0] = set_taglist_metatable(L, META_TAGLIST); + meta_ref[1] = set_taglist_metatable(L, META_SECTORTAGLIST); +#else + set_taglist_metatable(L, META_TAGLIST); +#endif + + return 0; +} diff --git a/src/lua_thinkerlib.c b/src/lua_thinkerlib.c index 82baa6469..963fdbd5a 100644 --- a/src/lua_thinkerlib.c +++ b/src/lua_thinkerlib.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_aatree.c b/src/m_aatree.c index c0bb739f8..522e38a53 100644 --- a/src/m_aatree.c +++ b/src/m_aatree.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_aatree.h b/src/m_aatree.h index b784eb17a..ed011644e 100644 --- a/src/m_aatree.h +++ b/src/m_aatree.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_anigif.c b/src/m_anigif.c index 41f99254e..b3a1d0fe2 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. // Copyright (C) 2013 by "Ninji". -// Copyright (C) 2013-2020 by Sonic Team Junior. +// Copyright (C) 2013-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_anigif.h b/src/m_anigif.h index abe05dd96..ad64dff7b 100644 --- a/src/m_anigif.h +++ b/src/m_anigif.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2013-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 2013-2020 by Sonic Team Junior. +// Copyright (C) 2013-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_argv.c b/src/m_argv.c index 7d43d96bc..1444f0c38 100644 --- a/src/m_argv.c +++ b/src/m_argv.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_argv.h b/src/m_argv.h index 92770f4e9..cdb6aa246 100644 --- a/src/m_argv.h +++ b/src/m_argv.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_bbox.c b/src/m_bbox.c index 02d534164..7fde0c171 100644 --- a/src/m_bbox.c +++ b/src/m_bbox.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_bbox.h b/src/m_bbox.h index 9b63c61b6..588000fae 100644 --- a/src/m_bbox.h +++ b/src/m_bbox.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_cheat.c b/src/m_cheat.c index 6e0fb8c5c..40b9a1230 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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); @@ -539,7 +539,7 @@ void Command_Teleport_f(void) // Flagging a player's ambush will make them start on the ceiling // Objectflip inverts - if (!!(mt->options & MTF_AMBUSH) ^ !!(mt->options & MTF_OBJECTFLIP)) + if (!!(mt->args[0]) ^ !!(mt->options & MTF_OBJECTFLIP)) intz = ss->sector->ceilingheight - p->mo->height - offset; else intz = ss->sector->floorheight + offset; @@ -1004,7 +1004,7 @@ static void OP_CycleThings(INT32 amt) } while (mobjinfo[op_currentthing].doomednum == -1 || op_currentthing == MT_NIGHTSDRONE - || mobjinfo[op_currentthing].flags & (MF_AMBIENT|MF_NOSECTOR) + || mobjinfo[op_currentthing].flags & MF_NOSECTOR || (states[mobjinfo[op_currentthing].spawnstate].sprite == SPR_NULL && states[mobjinfo[op_currentthing].seestate].sprite == SPR_NULL) ); @@ -1137,7 +1137,7 @@ void OP_ResetObjectplace(void) // // Main meat of objectplace: handling functions // -void OP_NightsObjectplace(player_t *player) +/*void OP_NightsObjectplace(player_t *player) { ticcmd_t *cmd = &player->cmd; mapthing_t *mt; @@ -1283,14 +1283,14 @@ void OP_NightsObjectplace(player_t *player) mt = OP_CreateNewMapThing(player, (UINT16)cv_mapthingnum.value, false); mt->angle = angle; - if (mt->type >= 600 && mt->type <= 609) // Placement patterns + if (mt->type >= 600 && mt->type <= 611) // Placement patterns P_SpawnItemPattern(mt, false); - else if (mt->type == 1705 || mt->type == 1713) // NiGHTS Hoops + else if (mt->type == 1713) // NiGHTS Hoops P_SpawnHoop(mt); else P_SpawnMapThing(mt); } -} +}*/ // // OP_ObjectplaceMovement @@ -1414,9 +1414,9 @@ void OP_ObjectplaceMovement(player_t *player) return; mt = OP_CreateNewMapThing(player, (UINT16)spawnthing, ceiling); - if (mt->type >= 600 && mt->type <= 609) // Placement patterns + if (mt->type >= 600 && mt->type <= 611) // Placement patterns P_SpawnItemPattern(mt, false); - else if (mt->type == 1705 || mt->type == 1713) // NiGHTS Hoops + else if (mt->type == 1713) // NiGHTS Hoops P_SpawnHoop(mt); else P_SpawnMapThing(mt); @@ -1428,14 +1428,14 @@ void OP_ObjectplaceMovement(player_t *player) // // Objectplace related commands. // -void Command_Writethings_f(void) +/*void Command_Writethings_f(void) { REQUIRE_INLEVEL; REQUIRE_SINGLEPLAYER; REQUIRE_OBJECTPLACE; P_WriteThings(); -} +}*/ void Command_ObjectPlace_f(void) { diff --git a/src/m_cheat.h b/src/m_cheat.h index ac2540408..086117579 100644 --- a/src/m_cheat.h +++ b/src/m_cheat.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -26,7 +26,7 @@ void cht_Init(void); // ObjectPlace // void Command_ObjectPlace_f(void); -void Command_Writethings_f(void); +//void Command_Writethings_f(void); extern consvar_t cv_opflags, cv_ophoopflags, cv_mapthingnum, cv_speed; //extern consvar_t cv_snapto, cv_grid; @@ -38,7 +38,7 @@ extern UINT32 op_displayflags; boolean OP_FreezeObjectplace(void); void OP_ResetObjectplace(void); -void OP_NightsObjectplace(player_t *player); +//void OP_NightsObjectplace(player_t *player); void OP_ObjectplaceMovement(player_t *player); // diff --git a/src/m_cond.c b/src/m_cond.c index 36fcd7cf2..1406317c5 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -496,6 +496,64 @@ UINT8 M_GotHighEnoughRings(INT32 trings) return false; } +// Gets the skin number for a SECRET_SKIN unlockable. +INT32 M_UnlockableSkinNum(unlockable_t *unlock) +{ + if (unlock->type != SECRET_SKIN) + { + // This isn't a skin unlockable... + return -1; + } + + if (unlock->stringVar && strcmp(unlock->stringVar, "")) + { + // Get the skin from the string. + INT32 skinnum = R_SkinAvailable(unlock->stringVar); + if (skinnum != -1) + { + return skinnum; + } + } + + if (unlock->variable >= 0 && unlock->variable < numskins) + { + // Use the number directly. + return unlock->variable; + } + + // Invalid skin unlockable. + return -1; +} + +// Gets the skin number for a ET_SKIN emblem. +INT32 M_EmblemSkinNum(emblem_t *emblem) +{ + if (emblem->type != ET_SKIN) + { + // This isn't a skin emblem... + return -1; + } + + if (emblem->stringVar && strcmp(emblem->stringVar, "")) + { + // Get the skin from the string. + INT32 skinnum = R_SkinAvailable(emblem->stringVar); + if (skinnum != -1) + { + return skinnum; + } + } + + if (emblem->var >= 0 && emblem->var < numskins) + { + // Use the number directly. + return emblem->var; + } + + // Invalid skin emblem. + return -1; +} + // ---------------- // Misc Emblem shit // ---------------- diff --git a/src/m_cond.h b/src/m_cond.h index 9bb162ff3..f36c80009 100644 --- a/src/m_cond.h +++ b/src/m_cond.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 2012-2020 by Sonic Team Junior. +// Copyright (C) 2012-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -92,6 +92,7 @@ typedef struct UINT8 sprite; ///< emblem sprite to use, 0 - 25 UINT16 color; ///< skincolor to use INT32 var; ///< If needed, specifies information on the target amount to achieve (or target skin) + char *stringVar; ///< String version char hint[110]; ///< Hint for emblem hints menu UINT8 collected; ///< Do you have this emblem? } emblem_t; @@ -116,6 +117,7 @@ typedef struct UINT8 showconditionset; INT16 type; INT16 variable; + char *stringVar; UINT8 nocecho; UINT8 nochecklist; UINT8 unlocked; @@ -132,6 +134,7 @@ typedef struct #define SECRET_WARP 2 // Selectable warp #define SECRET_SOUNDTEST 3 // Sound Test #define SECRET_CREDITS 4 // Enables Credits +#define SECRET_SKIN 5 // Unlocks a skin // If you have more secrets than these variables allow in your game, // you seriously need to get a life. @@ -185,4 +188,7 @@ UINT8 M_GotHighEnoughScore(INT32 tscore); UINT8 M_GotLowEnoughTime(INT32 tictime); UINT8 M_GotHighEnoughRings(INT32 trings); +INT32 M_UnlockableSkinNum(unlockable_t *unlock); +INT32 M_EmblemSkinNum(emblem_t *emblem); + #define M_Achieved(a) ((a) >= MAXCONDITIONSETS || conditionSets[a].achieved) diff --git a/src/m_dllist.h b/src/m_dllist.h index 680c2cd80..d8ca6648a 100644 --- a/src/m_dllist.h +++ b/src/m_dllist.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2005 by James Haley -// Copyright (C) 2005-2020 by Sonic Team Junior. +// Copyright (C) 2005-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_easing.c b/src/m_easing.c new file mode 100644 index 000000000..0f1cc1d02 --- /dev/null +++ b/src/m_easing.c @@ -0,0 +1,430 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020-2022 by Jaime "Lactozilla" Passos. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file m_easing.c +/// \brief Easing functions +/// Referenced from https://easings.net/ + +#include "m_easing.h" +#include "tables.h" +#include "doomdef.h" + +/* + For the computation of the logarithm, we choose, by trial and error, from among + a sequence of particular factors those, that when multiplied with the function + argument, normalize it to unity. For every factor chosen, we add up the + corresponding logarithm value stored in a table. The sum then corresponds to + the logarithm of the function argument. + + For the integer portion, we would want to choose + 2^i, i = 1, 2, 4, 8, ... + and for the factional part we choose + 1+2^-i, i = 1, 2, 3, 4, 5 ... + + The algorithm for the exponential is closely related and quite literally the inverse + of the logarithm algorithm. From among the sequence of tabulated logarithms for our + chosen factors, we pick those that when subtracted from the function argument ultimately + reduce it to zero. Starting with unity, we multiply with all the factors whose logarithms + we have subtracted in the process. The resulting product corresponds to the result of the exponentiation. + + Logarithms of values greater than unity can be computed by applying the algorithm to the reciprocal + of the function argument (with the negation of the result as appropriate), likewise exponentiation with + negative function arguments requires us negate the function argument and compute the reciprocal at the end. +*/ + +static fixed_t logtabdec[FRACBITS] = +{ + 0x95c1, 0x526a, 0x2b80, 0x1663, + 0xb5d, 0x5b9, 0x2e0, 0x170, + 0xb8, 0x5c, 0x2e, 0x17, + 0x0b, 0x06, 0x03, 0x01 +}; + +static fixed_t fixlog2(fixed_t a) +{ + UINT32 x = a, y = 0; + INT32 t, i, shift = 8; + + if (x > FRACUNIT) + x = FixedDiv(FRACUNIT, x); + + // Integer part + // 1<<19 = 0x80000 + // 1<<18 = 0x40000 + // 1<<17 = 0x20000 + // 1<<16 = 0x10000 + +#define dologtab(i) \ + t = (x << shift); \ + if (t < FRACUNIT) \ + { \ + x = t; \ + y += (1 << (19 - i)); \ + } \ + shift /= 2; + + dologtab(0) + dologtab(1) + dologtab(2) + dologtab(3) + +#undef dologtab + + // Decimal part + for (i = 0; i < FRACBITS; i++) + { + t = x + (x >> (i + 1)); + if (t < FRACUNIT) + { + x = t; + y += logtabdec[i]; + } + } + + if (a <= FRACUNIT) + return -y; + + return y; +} + +// Notice how this is symmetric to fixlog2. +static INT32 fixexp(fixed_t a) +{ + UINT32 x, y; + fixed_t t, i, shift = 8; + + // Underflow prevention. + if (a <= -15 * FRACUNIT) + return 0; + + x = (a < 0) ? (-a) : (a); + y = FRACUNIT; + + // Integer part (see fixlog2) +#define dologtab(i) \ + t = x - (1 << (19 - i)); \ + if (t >= 0) \ + { \ + x = t; \ + y <<= shift; \ + } \ + shift /= 2; + + dologtab(0) + dologtab(1) + dologtab(2) + dologtab(3) + +#undef dologtab + + // Decimal part + for (i = 0; i < FRACBITS; i++) + { + t = (x - logtabdec[i]); + if (t >= 0) + { + x = t; + y += (y >> (i + 1)); + } + } + + if (a < 0) + return FixedDiv(FRACUNIT, y); + + return y; +} + +#define fixpow(x, y) fixexp(FixedMul((y), fixlog2(x))) +#define fixintmul(x, y) FixedMul((x) * FRACUNIT, y) +#define fixintdiv(x, y) FixedDiv(x, (y) * FRACUNIT) +#define fixinterp(start, end, t) FixedMul((FRACUNIT - (t)), start) + FixedMul(t, end) + +// ================== +// EASING FUNCTIONS +// ================== + +#define EASINGFUNC(type) fixed_t Easing_ ## type (fixed_t t, fixed_t start, fixed_t end) + +// +// Linear +// + +EASINGFUNC(Linear) +{ + return fixinterp(start, end, t); +} + +// +// Sine +// + +// This is equivalent to calculating (x * pi) and converting the result from radians into degrees. +#define fixang(x) FixedMul((x), 180*FRACUNIT) + +EASINGFUNC(InSine) +{ + fixed_t c = fixang(t / 2); + fixed_t x = FRACUNIT - FINECOSINE(FixedAngle(c)>>ANGLETOFINESHIFT); + return fixinterp(start, end, x); +} + +EASINGFUNC(OutSine) +{ + fixed_t c = fixang(t / 2); + fixed_t x = FINESINE(FixedAngle(c)>>ANGLETOFINESHIFT); + return fixinterp(start, end, x); +} + +EASINGFUNC(InOutSine) +{ + fixed_t c = fixang(t); + fixed_t x = -(FINECOSINE(FixedAngle(c)>>ANGLETOFINESHIFT) - FRACUNIT) / 2; + return fixinterp(start, end, x); +} + +#undef fixang + +// +// Quad +// + +EASINGFUNC(InQuad) +{ + return fixinterp(start, end, FixedMul(t, t)); +} + +EASINGFUNC(OutQuad) +{ + return fixinterp(start, end, FRACUNIT - FixedMul(FRACUNIT - t, FRACUNIT - t)); +} + +EASINGFUNC(InOutQuad) +{ + fixed_t x = t < (FRACUNIT/2) + ? fixintmul(2, FixedMul(t, t)) + : FRACUNIT - fixpow(FixedMul(-2*FRACUNIT, t) + 2*FRACUNIT, 2*FRACUNIT) / 2; + return fixinterp(start, end, x); +} + +// +// Cubic +// + +EASINGFUNC(InCubic) +{ + fixed_t x = FixedMul(t, FixedMul(t, t)); + return fixinterp(start, end, x); +} + +EASINGFUNC(OutCubic) +{ + return fixinterp(start, end, FRACUNIT - fixpow(FRACUNIT - t, 3*FRACUNIT)); +} + +EASINGFUNC(InOutCubic) +{ + fixed_t x = t < (FRACUNIT/2) + ? fixintmul(4, FixedMul(t, FixedMul(t, t))) + : FRACUNIT - fixpow(fixintmul(-2, t) + 2*FRACUNIT, 3*FRACUNIT) / 2; + return fixinterp(start, end, x); +} + +// +// "Quart" +// + +EASINGFUNC(InQuart) +{ + fixed_t x = FixedMul(FixedMul(t, t), FixedMul(t, t)); + return fixinterp(start, end, x); +} + +EASINGFUNC(OutQuart) +{ + fixed_t x = FRACUNIT - fixpow(FRACUNIT - t, 4 * FRACUNIT); + return fixinterp(start, end, x); +} + +EASINGFUNC(InOutQuart) +{ + fixed_t x = t < (FRACUNIT/2) + ? fixintmul(8, FixedMul(FixedMul(t, t), FixedMul(t, t))) + : FRACUNIT - fixpow(fixintmul(-2, t) + 2*FRACUNIT, 4*FRACUNIT) / 2; + return fixinterp(start, end, x); +} + +// +// "Quint" +// + +EASINGFUNC(InQuint) +{ + fixed_t x = FixedMul(t, FixedMul(FixedMul(t, t), FixedMul(t, t))); + return fixinterp(start, end, x); +} + +EASINGFUNC(OutQuint) +{ + fixed_t x = FRACUNIT - fixpow(FRACUNIT - t, 5 * FRACUNIT); + return fixinterp(start, end, x); +} + +EASINGFUNC(InOutQuint) +{ + fixed_t x = t < (FRACUNIT/2) + ? FixedMul(16*FRACUNIT, FixedMul(t, FixedMul(FixedMul(t, t), FixedMul(t, t)))) + : FRACUNIT - fixpow(fixintmul(-2, t) + 2*FRACUNIT, 5*FRACUNIT) / 2; + return fixinterp(start, end, x); +} + +// +// Exponential +// + +EASINGFUNC(InExpo) +{ + fixed_t x = (!t) ? 0 : fixpow(2*FRACUNIT, fixintmul(10, t) - 10*FRACUNIT); + return fixinterp(start, end, x); +} + +EASINGFUNC(OutExpo) +{ + fixed_t x = (t >= FRACUNIT) ? FRACUNIT + : FRACUNIT - fixpow(2*FRACUNIT, fixintmul(-10, t)); + return fixinterp(start, end, x); +} + +EASINGFUNC(InOutExpo) +{ + fixed_t x; + + if (!t) + x = 0; + else if (t >= FRACUNIT) + x = FRACUNIT; + else + { + if (t < FRACUNIT / 2) + { + x = fixpow(2*FRACUNIT, fixintmul(20, t) - 10*FRACUNIT); + x = fixintdiv(x, 2); + } + else + { + x = fixpow(2*FRACUNIT, fixintmul(-20, t) + 10*FRACUNIT); + x = fixintdiv((2*FRACUNIT) - x, 2); + } + } + + return fixinterp(start, end, x); +} + +// +// "Back" +// + +#define EASEBACKCONST1 111514 // 1.70158 +#define EASEBACKCONST2 99942 // 1.525 + +static fixed_t EaseInBack(fixed_t t, fixed_t start, fixed_t end, fixed_t c1) +{ + const fixed_t c3 = c1 + FRACUNIT; + fixed_t x = FixedMul(FixedMul(t, t), FixedMul(c3, t) - c1); + return fixinterp(start, end, x); +} + +EASINGFUNC(InBack) +{ + return EaseInBack(t, start, end, EASEBACKCONST1); +} + +static fixed_t EaseOutBack(fixed_t t, fixed_t start, fixed_t end, fixed_t c1) +{ + const fixed_t c3 = c1 + FRACUNIT; + fixed_t x; + t -= FRACUNIT; + x = FRACUNIT + FixedMul(FixedMul(t, t), FixedMul(c3, t) + c1); + return fixinterp(start, end, x); +} + +EASINGFUNC(OutBack) +{ + return EaseOutBack(t, start, end, EASEBACKCONST1); +} + +static fixed_t EaseInOutBack(fixed_t t, fixed_t start, fixed_t end, fixed_t c2) +{ + fixed_t x, y; + const fixed_t f2 = 2*FRACUNIT; + + if (t < FRACUNIT / 2) + { + x = fixpow(FixedMul(t, f2), f2); + y = FixedMul(c2 + FRACUNIT, FixedMul(t, f2)); + x = FixedMul(x, y - c2); + } + else + { + x = fixpow(-(FixedMul(t, f2) - f2), f2); + y = FixedMul(c2 + FRACUNIT, FixedMul(t, f2) - f2); + x = FixedMul(x, y + c2); + x += f2; + } + + x /= 2; + + return fixinterp(start, end, x); +} + +EASINGFUNC(InOutBack) +{ + return EaseInOutBack(t, start, end, EASEBACKCONST2); +} + +#undef EASINGFUNC +#define EASINGFUNC(type) fixed_t Easing_ ## type (fixed_t t, fixed_t start, fixed_t end, fixed_t param) + +EASINGFUNC(InBackParameterized) +{ + return EaseInBack(t, start, end, param); +} + +EASINGFUNC(OutBackParameterized) +{ + return EaseOutBack(t, start, end, param); +} + +EASINGFUNC(InOutBackParameterized) +{ + return EaseInOutBack(t, start, end, param); +} + +#undef EASINGFUNC + +// Function list + +#define EASINGFUNC(type) Easing_ ## type +#define COMMA , + +easingfunc_t easing_funclist[EASE_MAX] = +{ + EASINGFUNCLIST(COMMA) +}; + +// Function names + +#undef EASINGFUNC +#define EASINGFUNC(type) #type + +const char *easing_funcnames[EASE_MAX] = +{ + EASINGFUNCLIST(COMMA) +}; + +#undef COMMA +#undef EASINGFUNC diff --git a/src/m_easing.h b/src/m_easing.h new file mode 100644 index 000000000..229222a15 --- /dev/null +++ b/src/m_easing.h @@ -0,0 +1,101 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020-2022 by Jaime "Lactozilla" Passos. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file m_easing.h +/// \brief Easing functions + +#ifndef __M_EASING_H__ +#define __M_EASING_H__ + +#include "doomtype.h" +#include "m_fixed.h" + +typedef enum +{ + EASE_LINEAR = 0, + + EASE_INSINE, + EASE_OUTSINE, + EASE_INOUTSINE, + + EASE_INQUAD, + EASE_OUTQUAD, + EASE_INOUTQUAD, + + EASE_INCUBIC, + EASE_OUTCUBIC, + EASE_INOUTCUBIC, + + EASE_INQUART, + EASE_OUTQUART, + EASE_INOUTQUART, + + EASE_INQUINT, + EASE_OUTQUINT, + EASE_INOUTQUINT, + + EASE_INEXPO, + EASE_OUTEXPO, + EASE_INOUTEXPO, + + EASE_INBACK, + EASE_OUTBACK, + EASE_INOUTBACK, + + EASE_MAX, +} easing_t; + +typedef fixed_t (*easingfunc_t)(fixed_t, fixed_t, fixed_t); + +extern easingfunc_t easing_funclist[EASE_MAX]; +extern const char *easing_funcnames[EASE_MAX]; + +#define EASINGFUNCLIST(sep) \ + EASINGFUNC(Linear) sep /* Easing_Linear */ \ + \ + EASINGFUNC(InSine) sep /* Easing_InSine */ \ + EASINGFUNC(OutSine) sep /* Easing_OutSine */ \ + EASINGFUNC(InOutSine) sep /* Easing_InOutSine */ \ + \ + EASINGFUNC(InQuad) sep /* Easing_InQuad */ \ + EASINGFUNC(OutQuad) sep /* Easing_OutQuad */ \ + EASINGFUNC(InOutQuad) sep /* Easing_InOutQuad */ \ + \ + EASINGFUNC(InCubic) sep /* Easing_InCubic */ \ + EASINGFUNC(OutCubic) sep /* Easing_OutCubic */ \ + EASINGFUNC(InOutCubic) sep /* Easing_InOutCubic */ \ + \ + EASINGFUNC(InQuart) sep /* Easing_InQuart */ \ + EASINGFUNC(OutQuart) sep /* Easing_OutQuart */ \ + EASINGFUNC(InOutQuart) sep /* Easing_InOutQuart */ \ + \ + EASINGFUNC(InQuint) sep /* Easing_InQuint */ \ + EASINGFUNC(OutQuint) sep /* Easing_OutQuint */ \ + EASINGFUNC(InOutQuint) sep /* Easing_InOutQuint */ \ + \ + EASINGFUNC(InExpo) sep /* Easing_InExpo */ \ + EASINGFUNC(OutExpo) sep /* Easing_OutExpo */ \ + EASINGFUNC(InOutExpo) sep /* Easing_InOutExpo */ \ + \ + EASINGFUNC(InBack) sep /* Easing_InBack */ \ + EASINGFUNC(OutBack) sep /* Easing_OutBack */ \ + EASINGFUNC(InOutBack) sep /* Easing_InOutBack */ + +#define EASINGFUNC(type) fixed_t Easing_ ## type (fixed_t t, fixed_t start, fixed_t end); + +EASINGFUNCLIST() + +#undef EASINGFUNC +#define EASINGFUNC(type) fixed_t Easing_ ## type (fixed_t t, fixed_t start, fixed_t end, fixed_t param); + +EASINGFUNC(InBackParameterized) /* Easing_InBackParameterized */ +EASINGFUNC(OutBackParameterized) /* Easing_OutBackParameterized */ +EASINGFUNC(InOutBackParameterized) /* Easing_InOutBackParameterized */ + +#undef EASINGFUNC +#endif diff --git a/src/m_fixed.c b/src/m_fixed.c index eb10fd5f8..70b7623da 100644 --- a/src/m_fixed.c +++ b/src/m_fixed.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_fixed.h b/src/m_fixed.h index 289ca442a..fe5efc551 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -71,7 +71,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FloatToFixed(float f) value [eax] \ modify exact [eax edx] #elif defined (__GNUC__) && defined (__i386__) && !defined (NOASM) - // DJGPP, i386 linux, cygwin or mingw + // i386 linux, cygwin or mingw FUNCMATH FUNCINLINE static inline fixed_t FixedMul(fixed_t a, fixed_t b) // asm { fixed_t ret; diff --git a/src/m_menu.c b/src/m_menu.c index 1de5bc4bb..9daab767f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -62,6 +62,8 @@ #include "i_joy.h" // for joystick menu controls +#include "p_saveg.h" // Only for NEWSKINSAVES + // Condition Sets #include "m_cond.h" @@ -1104,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[] = @@ -1322,7 +1324,7 @@ static menuitem_t OP_Camera2ExtendedOptionsMenu[] = enum { op_video_resolution = 1, -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) +#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) op_video_fullscreen, #endif op_video_vsync, @@ -1334,7 +1336,7 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_HEADER, NULL, "Screen", NULL, 0}, {IT_STRING | IT_CALL, NULL, "Set Resolution...", M_VideoModeMenu, 6}, -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) +#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 11}, #endif {IT_STRING | IT_CVAR, NULL, "Vertical Sync", &cv_vidwait, 16}, @@ -1453,7 +1455,7 @@ static menuitem_t OP_OpenGLOptionsMenu[] = #ifdef ALAM_LIGHTING {IT_SUBMENU|IT_STRING, NULL, "Lighting...", &OP_OpenGLLightingDef, 144}, #endif -#if defined (_WINDOWS) && (!((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL))) +#if defined (_WINDOWS) && (!(defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL))) {IT_STRING|IT_CVAR, NULL, "Fullscreen", &cv_fullscreen, 154}, #endif }; @@ -1612,53 +1614,54 @@ static menuitem_t OP_ServerOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21}, {IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26}, {IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31}, + {IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36}, #endif - {IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 36}, - {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 41}, + {IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41}, + {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46}, - {IT_HEADER, NULL, "Characters", NULL, 50}, - {IT_STRING | IT_CVAR, NULL, "Force a character", &cv_forceskin, 56}, - {IT_STRING | IT_CVAR, NULL, "Restrict character changes", &cv_restrictskinchange, 61}, + {IT_HEADER, NULL, "Characters", NULL, 55}, + {IT_STRING | IT_CVAR, NULL, "Force a character", &cv_forceskin, 61}, + {IT_STRING | IT_CVAR, NULL, "Restrict character changes", &cv_restrictskinchange, 66}, - {IT_HEADER, NULL, "Items", NULL, 70}, - {IT_STRING | IT_CVAR, NULL, "Item respawn delay", &cv_itemrespawntime, 76}, - {IT_STRING | IT_SUBMENU, NULL, "Mystery Item Monitor Toggles...", &OP_MonitorToggleDef, 81}, + {IT_HEADER, NULL, "Items", NULL, 75}, + {IT_STRING | IT_CVAR, NULL, "Item respawn delay", &cv_itemrespawntime, 81}, + {IT_STRING | IT_SUBMENU, NULL, "Mystery Item Monitor Toggles...", &OP_MonitorToggleDef, 86}, - {IT_HEADER, NULL, "Cooperative", NULL, 90}, - {IT_STRING | IT_CVAR, NULL, "Players required for exit", &cv_playersforexit, 96}, - {IT_STRING | IT_CVAR, NULL, "Starposts", &cv_coopstarposts, 101}, - {IT_STRING | IT_CVAR, NULL, "Life sharing", &cv_cooplives, 106}, - {IT_STRING | IT_CVAR, NULL, "Post-goal free roaming", &cv_exitmove, 111}, + {IT_HEADER, NULL, "Cooperative", NULL, 95}, + {IT_STRING | IT_CVAR, NULL, "Players required for exit", &cv_playersforexit, 101}, + {IT_STRING | IT_CVAR, NULL, "Starposts", &cv_coopstarposts, 106}, + {IT_STRING | IT_CVAR, NULL, "Life sharing", &cv_cooplives, 111}, + {IT_STRING | IT_CVAR, NULL, "Post-goal free roaming", &cv_exitmove, 116}, - {IT_HEADER, NULL, "Race, Competition", NULL, 120}, - {IT_STRING | IT_CVAR, NULL, "Level completion countdown", &cv_countdowntime, 126}, - {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_competitionboxes, 131}, + {IT_HEADER, NULL, "Race, Competition", NULL, 125}, + {IT_STRING | IT_CVAR, NULL, "Level completion countdown", &cv_countdowntime, 131}, + {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_competitionboxes, 136}, - {IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 140}, - {IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 146}, - {IT_STRING | IT_CVAR, NULL, "Score Limit", &cv_pointlimit, 151}, - {IT_STRING | IT_CVAR, NULL, "Overtime on Tie", &cv_overtime, 156}, - {IT_STRING | IT_CVAR, NULL, "Player respawn delay", &cv_respawntime, 161}, + {IT_HEADER, NULL, "Ringslinger (Match, CTF, Tag, H&S)", NULL, 145}, + {IT_STRING | IT_CVAR, NULL, "Time Limit", &cv_timelimit, 151}, + {IT_STRING | IT_CVAR, NULL, "Score Limit", &cv_pointlimit, 156}, + {IT_STRING | IT_CVAR, NULL, "Overtime on Tie", &cv_overtime, 161}, + {IT_STRING | IT_CVAR, NULL, "Player respawn delay", &cv_respawntime, 166}, - {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_matchboxes, 171}, - {IT_STRING | IT_CVAR, NULL, "Weapon Rings", &cv_specialrings, 176}, - {IT_STRING | IT_CVAR, NULL, "Power Stones", &cv_powerstones, 181}, + {IT_STRING | IT_CVAR, NULL, "Item Monitors", &cv_matchboxes, 176}, + {IT_STRING | IT_CVAR, NULL, "Weapon Rings", &cv_specialrings, 181}, + {IT_STRING | IT_CVAR, NULL, "Power Stones", &cv_powerstones, 186}, - {IT_STRING | IT_CVAR, NULL, "Flag respawn delay", &cv_flagtime, 191}, - {IT_STRING | IT_CVAR, NULL, "Hiding time", &cv_hidetime, 196}, + {IT_STRING | IT_CVAR, NULL, "Flag respawn delay", &cv_flagtime, 196}, + {IT_STRING | IT_CVAR, NULL, "Hiding time", &cv_hidetime, 201}, - {IT_HEADER, NULL, "Teams", NULL, 205}, - {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 211}, - {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 216}, + {IT_HEADER, NULL, "Teams", NULL, 210}, + {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216}, + {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221}, #ifndef NONET - {IT_HEADER, NULL, "Advanced", NULL, 225}, - {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 231}, + {IT_HEADER, NULL, "Advanced", NULL, 230}, + {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236}, - {IT_STRING | IT_CVAR, NULL, "Join delay", &cv_joindelay, 246}, - {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 251}, + {IT_STRING | IT_CVAR, NULL, "Join delay", &cv_joindelay, 251}, + {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256}, - {IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 256}, + {IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261}, #endif }; @@ -3212,7 +3215,7 @@ boolean M_Responder(event_t *ev) if (gamestate == GS_TITLESCREEN && finalecount < TICRATE) return false; - if (CON_Ready()) + if (CON_Ready() && gamestate != GS_WAITINGPLAYERS) return false; if (noFurtherInput) @@ -3226,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) @@ -3259,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; @@ -3304,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; @@ -3318,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; @@ -3336,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 @@ -3683,17 +3686,12 @@ void M_StartControlPanel(void) } else { - INT32 numlives = 2; + INT32 numlives = players[consoleplayer].lives; + if (players[consoleplayer].playerstate != PST_LIVE) + ++numlives; SPauseMenu[spause_pandora].status = (M_SecretUnlocked(SECRET_PANDORA) && !marathonmode) ? (IT_STRING | IT_CALL) : (IT_DISABLED); - if (&players[consoleplayer]) - { - numlives = players[consoleplayer].lives; - if (players[consoleplayer].playerstate != PST_LIVE) - ++numlives; - } - // The list of things that can disable retrying is (was?) a little too complex // for me to want to use the short if statement syntax if (numlives <= 1 || G_IsSpecialStage(gamemap)) @@ -3751,7 +3749,7 @@ void M_StartControlPanel(void) if (G_GametypeHasTeams()) MPauseMenu[mpause_switchteam].status = IT_STRING | IT_SUBMENU; else if (G_GametypeHasSpectators()) - MPauseMenu[((&players[consoleplayer] && players[consoleplayer].spectator) ? mpause_entergame : mpause_spectate)].status = IT_STRING | IT_CALL; + MPauseMenu[players[consoleplayer].spectator ? mpause_entergame : mpause_spectate].status = IT_STRING | IT_CALL; else // in this odd case, we still want something to be on the menu even if it's useless MPauseMenu[mpause_spectate].status = IT_GRAYEDOUT; } @@ -4033,7 +4031,7 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv) xx += p->width - p->leftoffset; for (i = 0; i < 16; i++) { - V_DrawScaledPatch(xx, y, V_WRAPX, W_CachePatchNum(centerlump[i & 1], PU_PATCH)); + V_DrawScaledPatch(xx, y, 0, W_CachePatchNum(centerlump[i & 1], PU_PATCH)); xx += 8; } V_DrawScaledPatch(xx, y, 0, W_CachePatchNum(rightlump, PU_PATCH)); @@ -4059,14 +4057,6 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) for (i = 1; i < SLIDER_RANGE; i++) V_DrawScaledPatch (x+i*8, y, 0,p); - if (ontop) - { - V_DrawCharacter(x - 6 - (skullAnimCounter/5), y, - '\x1C' | V_YELLOWMAP, false); - V_DrawCharacter(x+i*8 + 8 + (skullAnimCounter/5), y, - '\x1D' | V_YELLOWMAP, false); - } - p = W_CachePatchName("M_SLIDER", PU_PATCH); V_DrawScaledPatch(x+i*8, y, 0, p); @@ -4102,6 +4092,16 @@ static void M_DrawSlider(INT32 x, INT32 y, const consvar_t *cv, boolean ontop) range = 100; V_DrawMappedPatch(x + 2 + (SLIDER_RANGE*8*range)/100, y, 0, p, yellowmap); + + if (ontop) + { + V_DrawCharacter(x - 6 - (skullAnimCounter/5), y, + '\x1C' | V_YELLOWMAP, false); + V_DrawCharacter(x + 80 + (skullAnimCounter/5), y, + '\x1D' | V_YELLOWMAP, false); + V_DrawCenteredString(x + 40, y, V_30TRANS, + (cv->flags & CV_FLOAT) ? va("%.2f", FIXED_TO_FLOAT(cv->value)) : va("%d", cv->value)); + } } // @@ -4129,7 +4129,7 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) p = W_CachePatchNum(viewborderlump[BRDR_L], PU_PATCH); for (n = 0; n < boxlines; n++) { - V_DrawScaledPatch(cx, cy, V_WRAPY, p); + V_DrawScaledPatch(cx, cy, 0, p); cy += step; } V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BL], PU_PATCH)); @@ -4141,8 +4141,8 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) cy = y; while (width > 0) { - V_DrawScaledPatch(cx, cy, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH)); - V_DrawScaledPatch(cx, y + boff + boxlines*step, V_WRAPX, W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH)); + V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_T], PU_PATCH)); + V_DrawScaledPatch(cx, y + boff + boxlines*step, 0, W_CachePatchNum(viewborderlump[BRDR_B], PU_PATCH)); width--; cx += step; } @@ -4154,7 +4154,7 @@ void M_DrawTextBox(INT32 x, INT32 y, INT32 width, INT32 boxlines) p = W_CachePatchNum(viewborderlump[BRDR_R], PU_PATCH); for (n = 0; n < boxlines; n++) { - V_DrawScaledPatch(cx, cy, V_WRAPY, p); + V_DrawScaledPatch(cx, cy, 0, p); cy += step; } V_DrawScaledPatch(cx, cy, 0, W_CachePatchNum(viewborderlump[BRDR_BR], PU_PATCH)); @@ -4182,7 +4182,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<var)); + snprintf(targettext, 9, "%u", P_GetScoreForGradeOverall(gamemap, emblem->var)); snprintf(currenttext, 9, "%u", G_GetBestNightsScore(gamemap, 0)); targettext[8] = 0; @@ -5165,34 +5165,75 @@ static boolean M_GametypeHasLevels(INT32 gt) static INT32 M_CountRowsToShowOnPlatter(INT32 gt) { - INT32 mapnum = 0, prevmapnum = 0, col = 0, rows = 0; + INT32 col = 0, rows = 0; + INT32 mapIterate = 0; + INT32 headingIterate = 0; + boolean mapAddedAlready[NUMMAPS]; - while (mapnum < NUMMAPS) + memset(mapAddedAlready, 0, sizeof mapAddedAlready); + + for (mapIterate = 0; mapIterate < NUMMAPS; mapIterate++) { - if (M_CanShowLevelOnPlatter(mapnum, gt)) + boolean forceNewRow = true; + + if (mapAddedAlready[mapIterate] == true) { - if (rows == 0) + // Already added under another heading + continue; + } + + if (M_CanShowLevelOnPlatter(mapIterate, gt) == false) + { + // Don't show this one + continue; + } + + for (headingIterate = mapIterate; headingIterate < NUMMAPS; headingIterate++) + { + boolean wide = false; + + if (mapAddedAlready[headingIterate] == true) + { + // Already added under another heading + continue; + } + + if (M_CanShowLevelOnPlatter(headingIterate, gt) == false) + { + // Don't show this one + continue; + } + + if (!fastcmp(mapheaderinfo[mapIterate]->selectheading, mapheaderinfo[headingIterate]->selectheading)) + { + // Headers don't match + continue; + } + + wide = (mapheaderinfo[headingIterate]->menuflags & LF2_WIDEICON); + + // preparing next position to drop mapnum into + if (col == 2 // no more space on the row? + || wide || forceNewRow) + { + col = 0; rows++; + } else { - if (col == 2 - || (mapheaderinfo[prevmapnum]->menuflags & LF2_WIDEICON) - || (mapheaderinfo[mapnum]->menuflags & LF2_WIDEICON) - || !(fastcmp(mapheaderinfo[mapnum]->selectheading, mapheaderinfo[prevmapnum]->selectheading))) - { - col = 0; - rows++; - } - else - col++; + col++; } - prevmapnum = mapnum; + + // Done adding this one + mapAddedAlready[headingIterate] = true; + forceNewRow = wide; } - mapnum++; } if (levellistmode == LLM_CREATESERVER) + { rows++; + } return rows; } @@ -5222,7 +5263,10 @@ static void M_CacheLevelPlatter(void) static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) { INT32 numrows = M_CountRowsToShowOnPlatter(gt); - INT32 mapnum = 0, prevmapnum = 0, col = 0, row = 0, startrow = 0; + INT32 col = 0, row = 0, startrow = 0; + INT32 mapIterate = 0; // First level of map loop -- find starting points for select headings + INT32 headingIterate = 0; // Second level of map loop -- finding maps that match mapIterate's heading. + boolean mapAddedAlready[NUMMAPS]; if (!numrows) return false; @@ -5239,6 +5283,8 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) // done here so lsrow and lscol can be set if cv_nextmap is on the platter lsrow = lscol = lshli = lsoffs[0] = lsoffs[1] = 0; + memset(mapAddedAlready, 0, sizeof mapAddedAlready); + if (levellistmode == LLM_CREATESERVER) { sprintf(levelselect.rows[0].header, "Gametype"); @@ -5250,31 +5296,75 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) char_notes = NULL; } - while (mapnum < NUMMAPS) + for (mapIterate = 0; mapIterate < NUMMAPS; mapIterate++) { - if (M_CanShowLevelOnPlatter(mapnum, gt)) + INT32 headerRow = -1; + boolean anyAvailable = false; + boolean forceNewRow = true; + + if (mapAddedAlready[mapIterate] == true) { - const UINT8 actnum = mapheaderinfo[mapnum]->actnum; - const boolean headingisname = (fastcmp(mapheaderinfo[mapnum]->selectheading, mapheaderinfo[mapnum]->lvlttl)); - const boolean wide = (mapheaderinfo[mapnum]->menuflags & LF2_WIDEICON); + // Already added under another heading + continue; + } + + if (M_CanShowLevelOnPlatter(mapIterate, gt) == false) + { + // Don't show this one + continue; + } + + for (headingIterate = mapIterate; headingIterate < NUMMAPS; headingIterate++) + { + UINT8 actnum = 0; + boolean headingisname = false; + boolean wide = false; + + if (mapAddedAlready[headingIterate] == true) + { + // Already added under another heading + continue; + } + + if (M_CanShowLevelOnPlatter(headingIterate, gt) == false) + { + // Don't show this one + continue; + } + + if (!fastcmp(mapheaderinfo[mapIterate]->selectheading, mapheaderinfo[headingIterate]->selectheading)) + { + // Headers don't match + continue; + } + + actnum = mapheaderinfo[headingIterate]->actnum; + headingisname = (fastcmp(mapheaderinfo[headingIterate]->selectheading, mapheaderinfo[headingIterate]->lvlttl)); + wide = (mapheaderinfo[headingIterate]->menuflags & LF2_WIDEICON); // preparing next position to drop mapnum into if (levelselect.rows[startrow].maplist[0]) { if (col == 2 // no more space on the row? - || wide - || (mapheaderinfo[prevmapnum]->menuflags & LF2_WIDEICON) - || !(fastcmp(mapheaderinfo[mapnum]->selectheading, mapheaderinfo[prevmapnum]->selectheading))) // a new heading is starting? + || wide || forceNewRow) { col = 0; row++; } else + { col++; + } } - levelselect.rows[row].maplist[col] = mapnum+1; // putting the map on the platter - levelselect.rows[row].mapavailable[col] = M_LevelAvailableOnPlatter(mapnum); + if (headerRow == -1) + { + // Set where the header row is meant to be + headerRow = row; + } + + levelselect.rows[row].maplist[col] = headingIterate+1; // putting the map on the platter + levelselect.rows[row].mapavailable[col] = M_LevelAvailableOnPlatter(headingIterate); if ((lswide(row) = wide)) // intentionally assignment { @@ -5282,7 +5372,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) levelselect.rows[row].mapavailable[2] = levelselect.rows[row].mapavailable[1] = levelselect.rows[row].mapavailable[0]; } - if (nextmappick && cv_nextmap.value == mapnum+1) // A little quality of life improvement. + if (nextmappick && cv_nextmap.value == headingIterate+1) // A little quality of life improvement. { lsrow = row; lscol = col; @@ -5291,6 +5381,8 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) // individual map name if (levelselect.rows[row].mapavailable[col]) { + anyAvailable = true; + if (headingisname) { if (actnum) @@ -5301,7 +5393,7 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) else if (wide) { // Yes, with LF2_WIDEICON it'll continue on over into the next 17+1 char block. That's alright; col is always zero, the string is contiguous, and the maximum length is lvlttl[22] + ' ' + ZONE + ' ' + INT32, which is about 39 or so - barely crossing into the third column. - char* mapname = G_BuildMapTitle(mapnum+1); + char* mapname = G_BuildMapTitle(headingIterate+1); strcpy(levelselect.rows[row].mapnames[col], (const char *)mapname); Z_Free(mapname); } @@ -5310,38 +5402,49 @@ static boolean M_PrepareLevelPlatter(INT32 gt, boolean nextmappick) char mapname[22+1+11]; // lvlttl[22] + ' ' + INT32 if (actnum) - sprintf(mapname, "%s %d", mapheaderinfo[mapnum]->lvlttl, actnum); + sprintf(mapname, "%s %d", mapheaderinfo[headingIterate]->lvlttl, actnum); + else if (V_ThinStringWidth(mapheaderinfo[headingIterate]->lvlttl, 0) <= 80) + strlcpy(mapname, mapheaderinfo[headingIterate]->lvlttl, 22); else - strcpy(mapname, mapheaderinfo[mapnum]->lvlttl); - - if (strlen(mapname) >= 17) - strcpy(mapname+17-3, "..."); + { + strlcpy(mapname, mapheaderinfo[headingIterate]->lvlttl, 15); + strcat(mapname, "..."); + } strcpy(levelselect.rows[row].mapnames[col], (const char *)mapname); } } else - sprintf(levelselect.rows[row].mapnames[col], "???"); - - // creating header text - if (!col && ((row == startrow) || !(fastcmp(mapheaderinfo[mapnum]->selectheading, mapheaderinfo[levelselect.rows[row-1].maplist[0]-1]->selectheading)))) { - if (!levelselect.rows[row].mapavailable[col]) - sprintf(levelselect.rows[row].header, "???"); - else - { - sprintf(levelselect.rows[row].header, "%s", mapheaderinfo[mapnum]->selectheading); - if (!(mapheaderinfo[mapnum]->levelflags & LF_NOZONE) && headingisname) - { - sprintf(levelselect.rows[row].header + strlen(levelselect.rows[row].header), " ZONE"); - } - } + sprintf(levelselect.rows[row].mapnames[col], "???"); } - prevmapnum = mapnum; + // Done adding this one + mapAddedAlready[headingIterate] = true; + forceNewRow = wide; } - mapnum++; + if (headerRow == -1) + { + // Shouldn't happen + continue; + } + + // creating header text + if (anyAvailable == false) + { + sprintf(levelselect.rows[headerRow].header, "???"); + } + else + { + sprintf(levelselect.rows[headerRow].header, "%s", mapheaderinfo[mapIterate]->selectheading); + + if (!(mapheaderinfo[mapIterate]->levelflags & LF_NOZONE) + && fastcmp(mapheaderinfo[mapIterate]->selectheading, mapheaderinfo[mapIterate]->lvlttl)) + { + sprintf(levelselect.rows[headerRow].header + strlen(levelselect.rows[headerRow].header), " ZONE"); + } + } } #ifdef SYMMETRICAL_PLATTER @@ -5641,7 +5744,7 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea ? 159 : 63)); if (strlen(levelselect.rows[row].mapnames[col]) > 6) // "AERIAL GARDEN" vs "ACT 18" - "THE ACT" intentionally compressed - V_DrawThinString(x, y+50, (highlight ? V_YELLOWMAP : 0), levelselect.rows[row].mapnames[col]); + V_DrawThinString(x, y+50+1, (highlight ? V_YELLOWMAP : 0), levelselect.rows[row].mapnames[col]); else V_DrawString(x, y+50, (highlight ? V_YELLOWMAP : 0), levelselect.rows[row].mapnames[col]); } @@ -6233,8 +6336,8 @@ static void M_AddonsOptions(INT32 choice) M_SetupNextMenu(&OP_AddonsOptionsDef); } -#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/MODS\x80 to get & make add-ons!" -//#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/MODS\x80 to get & make add-ons!" +#define LOCATIONSTRING1 "Visit \x83SRB2.ORG/ADDONS\x80 to get & make addons!" +//#define LOCATIONSTRING2 "Visit \x88SRB2.ORG/ADDONS\x80 to get & make addons!" static void M_LoadAddonsPatches(void) { @@ -6306,6 +6409,7 @@ static void M_Addons(INT32 choice) M_SetupNextMenu(&MISC_AddonsDef); } +#ifdef ENFORCE_WAD_LIMIT #define width 4 #define vpadding 27 #define h (BASEVIDHEIGHT-(2*vpadding)) @@ -6353,6 +6457,7 @@ static void M_DrawTemperature(INT32 x, fixed_t t) #undef vpadding #undef h #undef NUMCOLOURS +#endif static char *M_AddonsHeaderPath(void) { @@ -6446,21 +6551,20 @@ static void M_DrawAddons(void) V_DrawCenteredString(BASEVIDWIDTH/2, 5, 0, LOCATIONSTRING1); // (recommendedflags == V_SKYMAP ? LOCATIONSTRING2 : LOCATIONSTRING1) +#ifdef ENFORCE_WAD_LIMIT if (numwadfiles <= mainwads+1) y = 0; else if (numwadfiles >= MAX_WADFILES) y = FRACUNIT; else { - x = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))< y) - y = x; + y = FixedDiv(((ssize_t)(numwadfiles) - (ssize_t)(mainwads+1))< FRACUNIT) // happens because of how we're shrinkin' it a little y = FRACUNIT; } M_DrawTemperature(BASEVIDWIDTH - 19 - 5, y); +#endif // DRAW MENU x = currentMenu->x; @@ -6905,7 +7009,7 @@ static void M_RetryResponse(INT32 ch) if (ch != 'y' && ch != KEY_ENTER) return; - if (!&players[consoleplayer] || netgame || multiplayer) // Should never happen! + if (netgame || multiplayer) // Should never happen! return; M_ClearMenus(true); @@ -6936,7 +7040,7 @@ static void M_SelectableClearMenus(INT32 choice) static void M_UltimateCheat(INT32 choice) { (void)choice; - LUAh_GameQuit(true); + LUA_HookBool(true, HOOK(GameQuit)); I_Quit(); } @@ -7083,13 +7187,20 @@ static void M_HandleChecklist(INT32 choice) static void M_DrawChecklist(void) { - INT32 i = check_on, j = 0, y = currentMenu->y; + INT32 i = check_on, j = 0, y = currentMenu->y, emblems = numemblems+numextraemblems; UINT32 condnum, previd, maxcond; condition_t *cond; // draw title (or big pic) M_DrawMenuTitle(); + // draw emblem counter + if (emblems > 0) + { + V_DrawString(42, 20, (emblems == M_CountEmblems()) ? V_GREENMAP : 0, va("%d/%d", M_CountEmblems(), emblems)); + V_DrawSmallScaledPatch(28, 20, 0, W_CachePatchName("EMBLICON", PU_PATCH)); + } + if (check_on) V_DrawString(10, y-(skullAnimCounter/5), V_YELLOWMAP, "\x1A"); @@ -8421,7 +8532,7 @@ static void M_DrawLoadGameData(void) sprdef = &charbotskin->sprites[SPR2_SIGN]; if (!sprdef->numframes) goto skipbot; - colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin-1, charbotskin->prefcolor, 0); + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].botskin-1, charbotskin->prefcolor, GTC_CACHE); sprframe = &sprdef->spriteframes[0]; patch = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); @@ -8431,8 +8542,6 @@ static void M_DrawLoadGameData(void) charbotskin->highresscale, 0, patch, colormap); - Z_Free(colormap); - tempx -= (20<sprites[SPR2_SIGN]; - colormap = R_GetTranslationColormap(savegameinfo[savetodraw].skinnum, charskin->prefcolor, 0); + colormap = R_GetTranslationColormap(savegameinfo[savetodraw].skinnum, charskin->prefcolor, GTC_CACHE); if (!sprdef->numframes) goto skipsign; sprframe = &sprdef->spriteframes[0]; @@ -8481,8 +8590,6 @@ skipsign: charskin->highresscale/2, 0, patch, colormap); skiplife: - if (colormap) - Z_Free(colormap); patch = W_CachePatchName("STLIVEX", PU_PATCH); @@ -8552,6 +8659,12 @@ static void M_DrawLoad(void) loadgameoffset = 0; M_DrawLoadGameData(); + + if (modifiedgame && !savemoddata) + { + V_DrawCenteredThinString(BASEVIDWIDTH/2, 184, 0, "\x85WARNING: \x80The game is modified."); + V_DrawCenteredThinString(BASEVIDWIDTH/2, 192, 0, "Progress will not be saved."); + } } // @@ -8583,7 +8696,7 @@ static void M_LoadSelect(INT32 choice) #define VERSIONSIZE 16 #define BADSAVE { savegameinfo[slot].lives = -666; Z_Free(savebuffer); return; } -#define CHECKPOS if (save_p >= end_p) BADSAVE +#define CHECKPOS if (sav_p >= end_p) BADSAVE // Reads the save file to list lives, level, player, etc. // Tails 05-29-2003 static void M_ReadSavegameInfo(UINT32 slot) @@ -8592,10 +8705,13 @@ static void M_ReadSavegameInfo(UINT32 slot) char savename[255]; UINT8 *savebuffer; UINT8 *end_p; // buffer end point, don't read past here - UINT8 *save_p; + UINT8 *sav_p; INT32 fake; // Dummy variable char temp[sizeof(timeattackfolder)]; char vcheck[VERSIONSIZE]; +#ifdef NEWSKINSAVES + INT16 backwardsCompat = 0; +#endif sprintf(savename, savegamename, slot); @@ -8611,83 +8727,113 @@ static void M_ReadSavegameInfo(UINT32 slot) end_p = savebuffer + length; // skip the description field - save_p = savebuffer; + sav_p = savebuffer; // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, "version %d", VERSION); - if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE - save_p += VERSIONSIZE; + if (strcmp((const char *)sav_p, (const char *)vcheck)) BADSAVE + sav_p += VERSIONSIZE; // dearchive all the modifications // P_UnArchiveMisc() CHECKPOS - fake = READINT16(save_p); + fake = READINT16(sav_p); if (((fake-1) & 8191) >= NUMMAPS) BADSAVE if(!mapheaderinfo[(fake-1) & 8191]) savegameinfo[slot].levelname[0] = '\0'; + else if (V_ThinStringWidth(mapheaderinfo[(fake-1) & 8191]->lvlttl, 0) <= 78) + strlcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl, 22); else { - strlcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl, 17+1); - - if (strlen(mapheaderinfo[(fake-1) & 8191]->lvlttl) >= 17) - strcpy(savegameinfo[slot].levelname+17-3, "..."); + strlcpy(savegameinfo[slot].levelname, mapheaderinfo[(fake-1) & 8191]->lvlttl, 15); + strcat(savegameinfo[slot].levelname, "..."); } savegameinfo[slot].gamemap = fake; CHECKPOS - savegameinfo[slot].numemeralds = READUINT16(save_p)-357; // emeralds + savegameinfo[slot].numemeralds = READUINT16(sav_p)-357; // emeralds CHECKPOS - READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to + READSTRINGN(sav_p, temp, sizeof(temp)); // mod it belongs to if (strcmp(temp, timeattackfolder)) BADSAVE // P_UnArchivePlayer() +#ifdef NEWSKINSAVES CHECKPOS - fake = READUINT16(save_p); - savegameinfo[slot].skinnum = fake & ((1<<5) - 1); - if (savegameinfo[slot].skinnum >= numskins - || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) - BADSAVE - savegameinfo[slot].botskin = fake >> 5; - if (savegameinfo[slot].botskin-1 >= numskins - || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) - BADSAVE + backwardsCompat = READUINT16(sav_p); + + if (backwardsCompat != NEWSKINSAVES) + { + // Backwards compat + savegameinfo[slot].skinnum = backwardsCompat & ((1<<5) - 1); + + if (savegameinfo[slot].skinnum >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) + BADSAVE + + savegameinfo[slot].botskin = backwardsCompat >> 5; + if (savegameinfo[slot].botskin-1 >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) + BADSAVE + } + else +#endif + { + char ourSkinName[SKINNAMESIZE+1]; + char botSkinName[SKINNAMESIZE+1]; + + CHECKPOS + READSTRINGN(sav_p, ourSkinName, SKINNAMESIZE); + savegameinfo[slot].skinnum = R_SkinAvailable(ourSkinName); + + if (savegameinfo[slot].skinnum >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].skinnum)) + BADSAVE + + CHECKPOS + READSTRINGN(sav_p, botSkinName, SKINNAMESIZE); + savegameinfo[slot].botskin = (R_SkinAvailable(botSkinName) + 1); + + if (savegameinfo[slot].botskin-1 >= numskins + || !R_SkinUsable(-1, savegameinfo[slot].botskin-1)) + BADSAVE + } CHECKPOS - savegameinfo[slot].numgameovers = READUINT8(save_p); // numgameovers + savegameinfo[slot].numgameovers = READUINT8(sav_p); // numgameovers CHECKPOS - savegameinfo[slot].lives = READSINT8(save_p); // lives + savegameinfo[slot].lives = READSINT8(sav_p); // lives CHECKPOS - savegameinfo[slot].continuescore = READINT32(save_p); // score + savegameinfo[slot].continuescore = READINT32(sav_p); // score CHECKPOS - fake = READINT32(save_p); // continues + fake = READINT32(sav_p); // continues if (useContinues) savegameinfo[slot].continuescore = fake; // File end marker check CHECKPOS - switch (READUINT8(save_p)) + switch (READUINT8(sav_p)) { case 0xb7: { UINT8 i, banksinuse; CHECKPOS - banksinuse = READUINT8(save_p); + banksinuse = READUINT8(sav_p); CHECKPOS if (banksinuse > NUM_LUABANKS) BADSAVE for (i = 0; i < banksinuse; i++) { - (void)READINT32(save_p); + (void)READINT32(sav_p); CHECKPOS } - if (READUINT8(save_p) != 0x1d) + if (READUINT8(sav_p) != 0x1d) BADSAVE } case 0x1d: @@ -8820,7 +8966,7 @@ static void M_HandleLoadSave(INT32 choice) break; case KEY_ENTER: - if (ultimate_selectable && saveSlotSelected == NOSAVESLOT) + if (ultimate_selectable && saveSlotSelected == NOSAVESLOT && !savemoddata && !modifiedgame) { loadgamescroll = 0; S_StartSound(NULL, sfx_skid); @@ -8913,7 +9059,7 @@ static void M_LoadGame(INT32 choice) if (tutorialmap && cv_tutorialprompt.value) { - M_StartMessage("Do you want to \x82play a brief Tutorial\x80?\n\nWe highly recommend this because \nthe controls are slightly different \nfrom other games.\n\nPress 'Y' or 'Enter' to go\nPress 'N' or any key to skip\n", + M_StartMessage("Do you want to \x82play a brief Tutorial\x80?\n\nWe highly recommend this because \nthe controls are slightly different \nfrom other games.\n\nPress the\x82 Y\x80 key or the\x83 A button\x80 to go\nPress the\x82 N\x80 key or the\x83 Y button\x80 to skip\n", M_FirstTimeResponse, MM_YESNO); return; } @@ -8966,7 +9112,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) static UINT8 M_SetupChoosePlayerDirect(INT32 choice) { - INT32 skinnum; + INT32 skinnum, botskinnum; UINT8 i; UINT8 firstvalid = 255, lastvalid = 255; boolean allowed = false; @@ -8998,6 +9144,13 @@ static UINT8 M_SetupChoosePlayerDirect(INT32 choice) skinnum = description[i].skinnum[0]; if ((skinnum != -1) && (R_SkinUsable(-1, skinnum))) { + botskinnum = description[i].skinnum[1]; + if ((botskinnum != -1) && (!R_SkinUsable(-1, botskinnum))) + { + // Bot skin isn't unlocked + continue; + } + // Handling order. if (firstvalid == 255) firstvalid = i; @@ -11422,9 +11575,9 @@ static void M_ServerOptions(INT32 choice) OP_ServerOptionsMenu[ 2].status = IT_GRAYEDOUT; // Max players OP_ServerOptionsMenu[ 3].status = IT_GRAYEDOUT; // Allow add-on downloading OP_ServerOptionsMenu[ 4].status = IT_GRAYEDOUT; // Allow players to join - OP_ServerOptionsMenu[35].status = IT_GRAYEDOUT; // Master server - OP_ServerOptionsMenu[36].status = IT_GRAYEDOUT; // Minimum delay between joins - OP_ServerOptionsMenu[37].status = IT_GRAYEDOUT; // Attempts to resynchronise + OP_ServerOptionsMenu[36].status = IT_GRAYEDOUT; // Master server + OP_ServerOptionsMenu[37].status = IT_GRAYEDOUT; // Minimum delay between joins + OP_ServerOptionsMenu[38].status = IT_GRAYEDOUT; // Attempts to resynchronise } else { @@ -11432,11 +11585,9 @@ static void M_ServerOptions(INT32 choice) OP_ServerOptionsMenu[ 2].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[ 3].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[ 4].status = IT_STRING | IT_CVAR; - OP_ServerOptionsMenu[35].status = (netgame - ? IT_GRAYEDOUT - : (IT_STRING | IT_CVAR | IT_CV_STRING)); - OP_ServerOptionsMenu[36].status = IT_STRING | IT_CVAR; + OP_ServerOptionsMenu[36].status = IT_STRING | IT_CVAR | IT_CV_STRING; OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR; + OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR; } #endif @@ -11753,7 +11904,7 @@ static void M_DrawSetupMultiPlayerMenu(void) goto faildraw; // ok, draw player sprite for sure now - colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, 0); + colormap = R_GetTranslationColormap(setupm_fakeskin, setupm_fakecolor->color, GTC_CACHE); if (multi_frame >= sprdef->numframes) multi_frame = 0; @@ -11771,7 +11922,6 @@ static void M_DrawSetupMultiPlayerMenu(void) FixedDiv(skins[setupm_fakeskin].highresscale, skins[setupm_fakeskin].shieldscale), flags, patch, colormap); - Z_Free(colormap); goto colordraw; faildraw: @@ -12687,13 +12837,13 @@ static void M_DrawControl(void) else { if (keys[0] != KEY_NULL) - strcat (tmp, G_KeynumToString (keys[0])); + strcat (tmp, G_KeyNumToName (keys[0])); if (keys[0] != KEY_NULL && keys[1] != KEY_NULL) strcat(tmp," or "); if (keys[1] != KEY_NULL) - strcat (tmp, G_KeynumToString (keys[1])); + strcat (tmp, G_KeyNumToName (keys[1])); } @@ -12720,7 +12870,7 @@ static void M_ChangecontrolResponse(event_t *ev) { INT32 control; INT32 found; - INT32 ch = ev->data1; + INT32 ch = ev->key; // ESCAPE cancels; dummy out PAUSE if (ch != KEY_ESCAPE && ch != KEY_PAUSE) @@ -12739,7 +12889,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: @@ -12790,7 +12940,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 @@ -12855,6 +13005,7 @@ static void M_DrawPlaystyleMenu(void) if (i == playstyle_currentchoice) { + V_DrawFill(20, 40, 280, 150, 159); V_DrawScaledPatch((i+1)*BASEVIDWIDTH/4 - 8, 10, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); V_DrawString(30, 50, V_ALLOWLOWERCASE, PlaystyleDesc[i]); } @@ -12927,7 +13078,7 @@ static void M_VideoModeMenu(INT32 choice) memset(modedescs, 0, sizeof(modedescs)); -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) +#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) VID_PrepareModeList(); // FIXME: hack #endif vidm_nummodes = 0; @@ -13370,7 +13521,7 @@ void M_QuitResponse(INT32 ch) if (ch != 'y' && ch != KEY_ENTER) return; - LUAh_GameQuit(true); + LUA_HookBool(true, HOOK(GameQuit)); if (!(netgame || cv_debug)) { S_ResetCaptions(); diff --git a/src/m_menu.h b/src/m_menu.h index 0465128ef..a7072b0c1 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2011-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -389,9 +389,9 @@ typedef struct // level select platter typedef struct { - char header[22+5]; // mapheader_t lvltttl max length + " ZONE" + char header[22+5]; // mapheader_t lvlttl max length + " ZONE" INT32 maplist[3]; - char mapnames[3][17+1]; + char mapnames[3][22]; // lvlttl max length boolean mapavailable[4]; // mapavailable[3] == wide or not } levelselectrow_t; diff --git a/src/m_misc.c b/src/m_misc.c index ad2d133ab..6c346e5a1 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -64,8 +64,6 @@ typedef off_t off64_t; #define PRIdS "u" #elif defined (_WIN32) #define PRIdS "Iu" -#elif defined (DJGPP) -#define PRIdS "u" #else #define PRIdS "zu" #endif @@ -165,7 +163,9 @@ consvar_t cv_zlib_window_bitsa = CVAR_INIT ("apng_window_size", "32k", CV_SAVE, consvar_t cv_apng_delay = CVAR_INIT ("apng_speed", "1x", CV_SAVE, apng_delay_t, NULL); consvar_t cv_apng_downscale = CVAR_INIT ("apng_downscale", "On", CV_SAVE, CV_OnOff, NULL); +#ifdef USE_APNG static boolean apng_downscale = false; // So nobody can do something dumb like changing cvars mid output +#endif boolean takescreenshot = false; // Take a screenshot this tic @@ -566,10 +566,13 @@ void M_FirstLoadConfig(void) gameconfig_loaded = true; // reset to default player stuff - COM_BufAddText (va("%s \"%s\"\n",cv_skin.name,cv_defaultskin.string)); - COM_BufAddText (va("%s \"%s\"\n",cv_playercolor.name,cv_defaultplayercolor.string)); - COM_BufAddText (va("%s \"%s\"\n",cv_skin2.name,cv_defaultskin2.string)); - COM_BufAddText (va("%s \"%s\"\n",cv_playercolor2.name,cv_defaultplayercolor2.string)); + if (!dedicated) + { + COM_BufAddText (va("%s \"%s\"\n",cv_skin.name,cv_defaultskin.string)); + COM_BufAddText (va("%s \"%s\"\n",cv_playercolor.name,cv_defaultplayercolor.string)); + COM_BufAddText (va("%s \"%s\"\n",cv_skin2.name,cv_defaultskin2.string)); + COM_BufAddText (va("%s \"%s\"\n",cv_playercolor2.name,cv_defaultplayercolor2.string)); + } } /** Saves the game configuration. @@ -833,7 +836,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png else snprintf(lvlttltext, 48, "Unknown"); - if (gamestate == GS_LEVEL && &players[displayplayer] && players[displayplayer].mo) + if (gamestate == GS_LEVEL && players[displayplayer].mo) snprintf(locationtxt, 40, "X:%d Y:%d Z:%d A:%d", players[displayplayer].mo->x>>FRACBITS, players[displayplayer].mo->y>>FRACBITS, @@ -1631,14 +1634,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; @@ -1970,18 +1973,168 @@ void M_UnGetToken(void) endPos = oldendPos; } -/** Returns the current token's position. - */ -UINT32 M_GetTokenPos(void) +#define NUMTOKENS 2 +static const char *tokenizerInput = NULL; +static UINT32 tokenCapacity[NUMTOKENS] = {0}; +static char *tokenizerToken[NUMTOKENS] = {NULL}; +static UINT32 tokenizerStartPos = 0; +static UINT32 tokenizerEndPos = 0; +static UINT32 tokenizerInputLength = 0; +static UINT8 tokenizerInComment = 0; // 0 = not in comment, 1 = // Single-line, 2 = /* Multi-line */ + +void M_TokenizerOpen(const char *inputString) { - return endPos; + size_t i; + + tokenizerInput = inputString; + for (i = 0; i < NUMTOKENS; i++) + { + tokenCapacity[i] = 1024; + tokenizerToken[i] = (char*)Z_Malloc(tokenCapacity[i] * sizeof(char), PU_STATIC, NULL); + } + tokenizerInputLength = strlen(tokenizerInput); } -/** Sets the current token's position. - */ -void M_SetTokenPos(UINT32 newPos) +void M_TokenizerClose(void) { - endPos = newPos; + size_t i; + + tokenizerInput = NULL; + for (i = 0; i < NUMTOKENS; i++) + Z_Free(tokenizerToken[i]); + tokenizerStartPos = 0; + tokenizerEndPos = 0; + tokenizerInComment = 0; +} + +static void M_DetectComment(UINT32 *pos) +{ + if (tokenizerInComment) + return; + + if (*pos >= tokenizerInputLength - 1) + return; + + if (tokenizerInput[*pos] != '/') + return; + + //Single-line comment start + if (tokenizerInput[*pos + 1] == '/') + tokenizerInComment = 1; + //Multi-line comment start + else if (tokenizerInput[*pos + 1] == '*') + tokenizerInComment = 2; +} + +static void M_ReadTokenString(UINT32 i) +{ + UINT32 tokenLength = tokenizerEndPos - tokenizerStartPos; + if (tokenLength + 1 > tokenCapacity[i]) + { + tokenCapacity[i] = tokenLength + 1; + // Assign the memory. Don't forget an extra byte for the end of the string! + tokenizerToken[i] = (char *)Z_Malloc(tokenCapacity[i] * sizeof(char), PU_STATIC, NULL); + } + // Copy the string. + M_Memcpy(tokenizerToken[i], tokenizerInput + tokenizerStartPos, (size_t)tokenLength); + // Make the final character NUL. + tokenizerToken[i][tokenLength] = '\0'; +} + +const char *M_TokenizerRead(UINT32 i) +{ + if (!tokenizerInput) + return NULL; + + tokenizerStartPos = tokenizerEndPos; + + // Try to detect comments now, in case we're pointing right at one + M_DetectComment(&tokenizerStartPos); + + // Find the first non-whitespace char, or else the end of the string trying + while ((tokenizerInput[tokenizerStartPos] == ' ' + || tokenizerInput[tokenizerStartPos] == '\t' + || tokenizerInput[tokenizerStartPos] == '\r' + || tokenizerInput[tokenizerStartPos] == '\n' + || tokenizerInput[tokenizerStartPos] == '\0' + || tokenizerInput[tokenizerStartPos] == '=' || tokenizerInput[tokenizerStartPos] == ';' // UDMF TEXTMAP. + || tokenizerInComment != 0) + && tokenizerStartPos < tokenizerInputLength) + { + // Try to detect comment endings now + if (tokenizerInComment == 1 && tokenizerInput[tokenizerStartPos] == '\n') + tokenizerInComment = 0; // End of line for a single-line comment + else if (tokenizerInComment == 2 + && tokenizerStartPos < tokenizerInputLength - 1 + && tokenizerInput[tokenizerStartPos] == '*' + && tokenizerInput[tokenizerStartPos+1] == '/') + { + // End of multi-line comment + tokenizerInComment = 0; + tokenizerStartPos++; // Make damn well sure we're out of the comment ending at the end of it all + } + + tokenizerStartPos++; + M_DetectComment(&tokenizerStartPos); + } + + // If the end of the string is reached, no token is to be read + if (tokenizerStartPos == tokenizerInputLength) { + tokenizerEndPos = tokenizerInputLength; + return NULL; + } + // Else, if it's one of these three symbols, capture only this one character + else if (tokenizerInput[tokenizerStartPos] == ',' + || tokenizerInput[tokenizerStartPos] == '{' + || tokenizerInput[tokenizerStartPos] == '}') + { + tokenizerEndPos = tokenizerStartPos + 1; + tokenizerToken[i][0] = tokenizerInput[tokenizerStartPos]; + tokenizerToken[i][1] = '\0'; + return tokenizerToken[i]; + } + // Return entire string within quotes, except without the quotes. + else if (tokenizerInput[tokenizerStartPos] == '"') + { + tokenizerEndPos = ++tokenizerStartPos; + while (tokenizerInput[tokenizerEndPos] != '"' && tokenizerEndPos < tokenizerInputLength) + tokenizerEndPos++; + + M_ReadTokenString(i); + tokenizerEndPos++; + return tokenizerToken[i]; + } + + // Now find the end of the token. This includes several additional characters that are okay to capture as one character, but not trailing at the end of another token. + tokenizerEndPos = tokenizerStartPos + 1; + while ((tokenizerInput[tokenizerEndPos] != ' ' + && tokenizerInput[tokenizerEndPos] != '\t' + && tokenizerInput[tokenizerEndPos] != '\r' + && tokenizerInput[tokenizerEndPos] != '\n' + && tokenizerInput[tokenizerEndPos] != ',' + && tokenizerInput[tokenizerEndPos] != '{' + && tokenizerInput[tokenizerEndPos] != '}' + && tokenizerInput[tokenizerEndPos] != '=' && tokenizerInput[tokenizerEndPos] != ';' // UDMF TEXTMAP. + && tokenizerInComment == 0) + && tokenizerEndPos < tokenizerInputLength) + { + tokenizerEndPos++; + // Try to detect comment starts now; if it's in a comment, we don't want it in this token + M_DetectComment(&tokenizerEndPos); + } + + M_ReadTokenString(i); + return tokenizerToken[i]; +} + +UINT32 M_TokenizerGetEndPos(void) +{ + return tokenizerEndPos; +} + +void M_TokenizerSetEndPos(UINT32 newPos) +{ + tokenizerEndPos = newPos; } /** Count bits in a number. @@ -2688,3 +2841,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 c5ef9f9f2..5b79c6c8c 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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/m_perfstats.c b/src/m_perfstats.c index 1596a87e5..9fc41000d 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2020-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -22,560 +22,805 @@ #include "hardware/hw_main.h" #endif -struct perfstatcol; struct perfstatrow; -typedef struct perfstatcol perfstatcol_t; typedef struct perfstatrow perfstatrow_t; -struct perfstatcol { - INT32 lores_x; - INT32 hires_x; - INT32 color; - perfstatrow_t * rows; -}; - struct perfstatrow { - const char * lores_label; - const char * hires_label; - void * value; + const char * lores_label; + const char * hires_label; + ps_metric_t * metric; + UINT8 flags; }; -static precise_t ps_frametime = 0; +// perfstatrow_t flags -precise_t ps_tictime = 0; +#define PS_TIME 1 // metric measures time (uses precise_t instead of INT32) +#define PS_LEVEL 2 // metric is valid only when a level is active +#define PS_SW 4 // metric is valid only in software mode +#define PS_HW 8 // metric is valid only in opengl mode +#define PS_BATCHING 16 // metric is valid only when opengl batching is active +#define PS_HIDE_ZERO 32 // hide metric if its value is zero -precise_t ps_playerthink_time = 0; -precise_t ps_thinkertime = 0; +static ps_metric_t ps_frametime = {0}; -precise_t ps_thlist_times[NUM_THINKERLISTS]; +ps_metric_t ps_tictime = {0}; -int ps_checkposition_calls = 0; +ps_metric_t ps_playerthink_time = {0}; +ps_metric_t ps_thinkertime = {0}; -precise_t ps_lua_thinkframe_time = 0; -int ps_lua_mobjhooks = 0; +ps_metric_t ps_thlist_times[NUM_THINKERLISTS]; + +static ps_metric_t ps_thinkercount = {0}; +static ps_metric_t ps_polythcount = {0}; +static ps_metric_t ps_mainthcount = {0}; +static ps_metric_t ps_mobjcount = {0}; +static ps_metric_t ps_regularcount = {0}; +static ps_metric_t ps_scenerycount = {0}; +static ps_metric_t ps_nothinkcount = {0}; +static ps_metric_t ps_dynslopethcount = {0}; +static ps_metric_t ps_precipcount = {0}; +static ps_metric_t ps_removecount = {0}; + +ps_metric_t ps_checkposition_calls = {0}; + +ps_metric_t ps_lua_thinkframe_time = {0}; +ps_metric_t ps_lua_mobjhooks = {0}; + +ps_metric_t ps_otherlogictime = {0}; + +// Columns for perfstats pages. + +// Position on screen is determined separately in the drawing functions. + +// New columns must also be added to the drawing and update functions. +// Drawing functions: PS_DrawRenderStats, PS_DrawGameLogicStats, etc. +// Update functions: +// - PS_UpdateFrameStats for frame-dependent values +// - PS_UpdateTickStats for tick-dependent values + +// Rendering stats columns + +perfstatrow_t rendertime_rows[] = { + {"frmtime", "Frame time: ", &ps_frametime, PS_TIME}, + {"drwtime", "3d rendering: ", &ps_rendercalltime, PS_TIME|PS_LEVEL}, + +#ifdef HWRENDER + {" skybox ", " Skybox render: ", &ps_hw_skyboxtime, PS_TIME|PS_LEVEL|PS_HW}, + {" bsptime", " RenderBSPNode: ", &ps_bsptime, PS_TIME|PS_LEVEL|PS_HW}, + {" batsort", " Batch sort: ", &ps_hw_batchsorttime, PS_TIME|PS_LEVEL|PS_HW|PS_BATCHING}, + {" batdraw", " Batch render: ", &ps_hw_batchdrawtime, PS_TIME|PS_LEVEL|PS_HW|PS_BATCHING}, + {" sprsort", " Sprite sort: ", &ps_hw_spritesorttime, PS_TIME|PS_LEVEL|PS_HW}, + {" sprdraw", " Sprite render: ", &ps_hw_spritedrawtime, PS_TIME|PS_LEVEL|PS_HW}, + {" nodesrt", " Drwnode sort: ", &ps_hw_nodesorttime, PS_TIME|PS_LEVEL|PS_HW}, + {" nodedrw", " Drwnode render:", &ps_hw_nodedrawtime, PS_TIME|PS_LEVEL|PS_HW}, + {" other ", " Other: ", &ps_otherrendertime, PS_TIME|PS_LEVEL|PS_HW}, +#endif + + {" bsptime", " RenderBSPNode: ", &ps_bsptime, PS_TIME|PS_LEVEL|PS_SW}, + {" sprclip", " R_ClipSprites: ", &ps_sw_spritecliptime, PS_TIME|PS_LEVEL|PS_SW}, + {" portals", " Portals+Skybox:", &ps_sw_portaltime, PS_TIME|PS_LEVEL|PS_SW}, + {" planes ", " R_DrawPlanes: ", &ps_sw_planetime, PS_TIME|PS_LEVEL|PS_SW}, + {" masked ", " R_DrawMasked: ", &ps_sw_maskedtime, PS_TIME|PS_LEVEL|PS_SW}, + {" other ", " Other: ", &ps_otherrendertime, PS_TIME|PS_LEVEL|PS_SW}, + + {"ui ", "UI render: ", &ps_uitime, PS_TIME}, + {"finupdt", "I_FinishUpdate:", &ps_swaptime, PS_TIME}, + {0} +}; + +perfstatrow_t gamelogicbrief_row[] = { + {"logic ", "Game logic: ", &ps_tictime, PS_TIME}, + {0} +}; + +perfstatrow_t commoncounter_rows[] = { + {"bspcall", "BSP calls: ", &ps_numbspcalls, 0}, + {"sprites", "Sprites: ", &ps_numsprites, 0}, + {"drwnode", "Drawnodes: ", &ps_numdrawnodes, 0}, + {"plyobjs", "Polyobjects: ", &ps_numpolyobjects, 0}, + {0} +}; + +#ifdef HWRENDER +perfstatrow_t batchcount_rows[] = { + {"polygon", "Polygons: ", &ps_hw_numpolys, 0}, + {"vertex ", "Vertices: ", &ps_hw_numverts, 0}, + {0} +}; + +perfstatrow_t batchcalls_rows[] = { + {"drwcall", "Draw calls:", &ps_hw_numcalls, 0}, + {"shaders", "Shaders: ", &ps_hw_numshaders, 0}, + {"texture", "Textures: ", &ps_hw_numtextures, 0}, + {"polyflg", "Polyflags: ", &ps_hw_numpolyflags, 0}, + {"colors ", "Colors: ", &ps_hw_numcolors, 0}, + {0} +}; +#endif + +// Game logic stats columns + +perfstatrow_t gamelogic_rows[] = { + {"logic ", "Game logic: ", &ps_tictime, PS_TIME}, + {" plrthnk", " P_PlayerThink: ", &ps_playerthink_time, PS_TIME|PS_LEVEL}, + {" thnkers", " P_RunThinkers: ", &ps_thinkertime, PS_TIME|PS_LEVEL}, + {" plyobjs", " Polyobjects: ", &ps_thlist_times[THINK_POLYOBJ], PS_TIME|PS_LEVEL}, + {" main ", " Main: ", &ps_thlist_times[THINK_MAIN], PS_TIME|PS_LEVEL}, + {" mobjs ", " Mobjs: ", &ps_thlist_times[THINK_MOBJ], PS_TIME|PS_LEVEL}, + {" dynslop", " Dynamic slopes: ", &ps_thlist_times[THINK_DYNSLOPE], PS_TIME|PS_LEVEL}, + {" precip ", " Precipitation: ", &ps_thlist_times[THINK_PRECIP], PS_TIME|PS_LEVEL}, + {" lthinkf", " LUAh_ThinkFrame:", &ps_lua_thinkframe_time, PS_TIME|PS_LEVEL}, + {" other ", " Other: ", &ps_otherlogictime, PS_TIME|PS_LEVEL}, + {0} +}; + +perfstatrow_t thinkercount_rows[] = { + {"thnkers", "Thinkers: ", &ps_thinkercount, PS_LEVEL}, + {" plyobjs", " Polyobjects: ", &ps_polythcount, PS_LEVEL}, + {" main ", " Main: ", &ps_mainthcount, PS_LEVEL}, + {" mobjs ", " Mobjs: ", &ps_mobjcount, PS_LEVEL}, + {" regular", " Regular: ", &ps_regularcount, PS_LEVEL}, + {" scenery", " Scenery: ", &ps_scenerycount, PS_LEVEL}, + {" nothink", " Nothink: ", &ps_nothinkcount, PS_HIDE_ZERO|PS_LEVEL}, + {" dynslop", " Dynamic slopes: ", &ps_dynslopethcount, PS_LEVEL}, + {" precip ", " Precipitation: ", &ps_precipcount, PS_LEVEL}, + {" remove ", " Pending removal:", &ps_removecount, PS_LEVEL}, + {0} +}; + +perfstatrow_t misc_calls_rows[] = { + {"lmhook", "Lua mobj hooks: ", &ps_lua_mobjhooks, PS_LEVEL}, + {"chkpos", "P_CheckPosition:", &ps_checkposition_calls, PS_LEVEL}, + {0} +}; + +// Sample collection status for averaging. +// Maximum of these two is shown to user if nonzero to tell that +// the reported averages are not correct yet. +int ps_frame_samples_left = 0; +int ps_tick_samples_left = 0; +// History writing positions for frame and tick based metrics +int ps_frame_index = 0; +int ps_tick_index = 0; // dynamically allocated resizeable array for thinkframe hook stats ps_hookinfo_t *thinkframe_hooks = NULL; int thinkframe_hooks_length = 0; int thinkframe_hooks_capacity = 16; -static INT32 draw_row; - -void PS_SetThinkFrameHookInfo(int index, UINT32 time_taken, char* short_src) +void PS_SetThinkFrameHookInfo(int index, precise_t time_taken, char* short_src) { if (!thinkframe_hooks) { // array needs to be initialized - thinkframe_hooks = Z_Malloc(sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity, PU_STATIC, NULL); + thinkframe_hooks = Z_Calloc(sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity, PU_STATIC, NULL); } if (index >= thinkframe_hooks_capacity) { // array needs more space, realloc with double size - thinkframe_hooks_capacity *= 2; + int new_capacity = thinkframe_hooks_capacity * 2; thinkframe_hooks = Z_Realloc(thinkframe_hooks, - sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity, PU_STATIC, NULL); + sizeof(ps_hookinfo_t) * new_capacity, PU_STATIC, NULL); + // initialize new memory with zeros so the pointers in the structs are null + memset(&thinkframe_hooks[thinkframe_hooks_capacity], 0, + sizeof(ps_hookinfo_t) * thinkframe_hooks_capacity); + thinkframe_hooks_capacity = new_capacity; } - thinkframe_hooks[index].time_taken = time_taken; + thinkframe_hooks[index].time_taken.value.p = time_taken; memcpy(thinkframe_hooks[index].short_src, short_src, LUA_IDSIZE * sizeof(char)); // since the values are set sequentially from begin to end, the last call should leave // the correct value to this variable thinkframe_hooks_length = index + 1; } -static void PS_SetFrameTime(void) -{ - precise_t currenttime = I_GetPreciseTime(); - ps_frametime = currenttime - ps_prevframetime; - ps_prevframetime = currenttime; -} - -static boolean M_HighResolution(void) +static boolean PS_HighResolution(void) { return (vid.width >= 640 && vid.height >= 400); } -enum { - PERF_TIME, - PERF_COUNT, -}; - -static void M_DrawPerfString(perfstatcol_t *col, int type) +static boolean PS_IsLevelActive(void) { - const boolean hires = M_HighResolution(); + return gamestate == GS_LEVEL || + (gamestate == GS_TITLESCREEN && titlemapinaction); +} - INT32 draw_flags = V_MONOSPACE | col->color; +// Is the row valid in the current context? +static boolean PS_IsRowValid(perfstatrow_t *row) +{ + return !((row->flags & PS_LEVEL && !PS_IsLevelActive()) + || (row->flags & PS_SW && rendermode != render_soft) + || (row->flags & PS_HW && rendermode != render_opengl) +#ifdef HWRENDER + || (row->flags & PS_BATCHING && !cv_glbatching.value) +#endif + ); +} +// Should the row be visible on the screen? +static boolean PS_IsRowVisible(perfstatrow_t *row) +{ + boolean value_is_zero; + + if (row->flags & PS_TIME) + value_is_zero = row->metric->value.p == 0; + else + value_is_zero = row->metric->value.i == 0; + + return !(!PS_IsRowValid(row) || + (row->flags & PS_HIDE_ZERO && value_is_zero)); +} + +static INT32 PS_GetMetricAverage(ps_metric_t *metric, boolean time_metric) +{ + char* history_read_pos = metric->history; // char* used for pointer arithmetic + INT64 sum = 0; + int i; + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + + for (i = 0; i < cv_ps_samplesize.value; i++) + { + if (time_metric) + sum += I_PreciseToMicros(*((precise_t*)history_read_pos)); + else + sum += *((INT32*)history_read_pos); + history_read_pos += value_size; + } + + return sum / cv_ps_samplesize.value; +} + +static INT32 PS_GetMetricMinOrMax(ps_metric_t *metric, boolean time_metric, boolean get_max) +{ + char* history_read_pos = metric->history; // char* used for pointer arithmetic + INT32 found_value = get_max ? INT32_MIN : INT32_MAX; + int i; + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + + for (i = 0; i < cv_ps_samplesize.value; i++) + { + INT32 value; + if (time_metric) + value = I_PreciseToMicros(*((precise_t*)history_read_pos)); + else + value = *((INT32*)history_read_pos); + + if ((get_max && value > found_value) || + (!get_max && value < found_value)) + { + found_value = value; + } + history_read_pos += value_size; + } + + return found_value; +} + +// Calculates the standard deviation for metric. +static INT32 PS_GetMetricSD(ps_metric_t *metric, boolean time_metric) +{ + char* history_read_pos = metric->history; // char* used for pointer arithmetic + INT64 sum = 0; + int i; + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + INT32 avg = PS_GetMetricAverage(metric, time_metric); + + for (i = 0; i < cv_ps_samplesize.value; i++) + { + INT64 value; + if (time_metric) + value = I_PreciseToMicros(*((precise_t*)history_read_pos)); + else + value = *((INT32*)history_read_pos); + + value -= avg; + sum += value * value; + + history_read_pos += value_size; + } + + return round(sqrt(sum / cv_ps_samplesize.value)); +} + +// Returns the value to show on screen for metric. +static INT32 PS_GetMetricScreenValue(ps_metric_t *metric, boolean time_metric) +{ + if (cv_ps_samplesize.value > 1 && metric->history) + { + if (cv_ps_descriptor.value == 1) + return PS_GetMetricAverage(metric, time_metric); + else if (cv_ps_descriptor.value == 2) + return PS_GetMetricSD(metric, time_metric); + else if (cv_ps_descriptor.value == 3) + return PS_GetMetricMinOrMax(metric, time_metric, false); + else + return PS_GetMetricMinOrMax(metric, time_metric, true); + } + else + { + if (time_metric) + return I_PreciseToMicros(metric->value.p); + else + return metric->value.i; + } +} + +static int PS_DrawPerfRows(int x, int y, int color, perfstatrow_t *rows) +{ + const boolean hires = PS_HighResolution(); + INT32 draw_flags = V_MONOSPACE | color; perfstatrow_t * row; - - int value; + int draw_y = y; if (hires) draw_flags |= V_ALLOWLOWERCASE; - for (row = col->rows; row->lores_label; ++row) + for (row = rows; row->lores_label; ++row) { - if (type == PERF_TIME) - value = I_PreciseToMicros(*(precise_t *)row->value); - else - value = *(int *)row->value; + const char *label; + INT32 value; + char *final_str; + + if (!PS_IsRowVisible(row)) + continue; + + label = hires ? row->hires_label : row->lores_label; + value = PS_GetMetricScreenValue(row->metric, !!(row->flags & PS_TIME)); + final_str = va("%s %d", label, value); if (hires) { - V_DrawSmallString(col->hires_x, draw_row, draw_flags, - va("%s %d", row->hires_label, value)); - - draw_row += 5; + V_DrawSmallString(x, draw_y, draw_flags, final_str); + draw_y += 5; } else { - V_DrawThinString(col->lores_x, draw_row, draw_flags, - va("%s %d", row->lores_label, value)); - - draw_row += 8; + V_DrawThinString(x, draw_y, draw_flags, final_str); + draw_y += 8; } } + + return draw_y; +} + +static void PS_UpdateMetricHistory(ps_metric_t *metric, boolean time_metric, boolean frame_metric, boolean set_user) +{ + int index = frame_metric ? ps_frame_index : ps_tick_index; + + if (!metric->history) + { + // allocate history table + int value_size = time_metric ? sizeof(precise_t) : sizeof(INT32); + void** memory_user = set_user ? &metric->history : NULL; + + metric->history = Z_Calloc(value_size * cv_ps_samplesize.value, PU_PERFSTATS, + memory_user); + + // reset "samples left" counter since this history table needs to be filled + if (frame_metric) + ps_frame_samples_left = cv_ps_samplesize.value; + else + ps_tick_samples_left = cv_ps_samplesize.value; + } + + if (time_metric) + { + precise_t *history = (precise_t*)metric->history; + history[index] = metric->value.p; + } + else + { + INT32 *history = (INT32*)metric->history; + history[index] = metric->value.i; + } } -static void M_DrawPerfTiming(perfstatcol_t *col) +static void PS_UpdateRowHistories(perfstatrow_t *rows, boolean frame_metric) { - M_DrawPerfString(col, PERF_TIME); -} - -static void M_DrawPerfCount(perfstatcol_t *col) -{ - M_DrawPerfString(col, PERF_COUNT); -} - -static void M_DrawRenderStats(void) -{ - const boolean hires = M_HighResolution(); - - const int half_row = hires ? 5 : 4; - - precise_t extrarendertime; - - perfstatrow_t frametime_row[] = { - {"frmtime", "Frame time: ", &ps_frametime}, - {0} - }; - - perfstatrow_t rendercalltime_row[] = { - {"drwtime", "3d rendering: ", &ps_rendercalltime}, - {0} - }; - - perfstatrow_t opengltime_row[] = { - {"skybox ", "Skybox render: ", &ps_hw_skyboxtime}, - {"bsptime", "RenderBSPNode: ", &ps_bsptime}, - {"nodesrt", "Drwnode sort: ", &ps_hw_nodesorttime}, - {"nodedrw", "Drwnode render:", &ps_hw_nodedrawtime}, - {"sprsort", "Sprite sort: ", &ps_hw_spritesorttime}, - {"sprdraw", "Sprite render: ", &ps_hw_spritedrawtime}, - {"other ", "Other: ", &extrarendertime}, - {0} - }; - - perfstatrow_t softwaretime_row[] = { - {"bsptime", "RenderBSPNode: ", &ps_bsptime}, - {"sprclip", "R_ClipSprites: ", &ps_sw_spritecliptime}, - {"portals", "Portals+Skybox:", &ps_sw_portaltime}, - {"planes ", "R_DrawPlanes: ", &ps_sw_planetime}, - {"masked ", "R_DrawMasked: ", &ps_sw_maskedtime}, - {"other ", "Other: ", &extrarendertime}, - {0} - }; - - perfstatrow_t uiswaptime_row[] = { - {"ui ", "UI render: ", &ps_uitime}, - {"finupdt", "I_FinishUpdate:", &ps_swaptime}, - {0} - }; - - perfstatrow_t tictime_row[] = { - {"logic ", "Game logic: ", &ps_tictime}, - {0} - }; - - perfstatrow_t rendercalls_row[] = { - {"bspcall", "BSP calls: ", &ps_numbspcalls}, - {"sprites", "Sprites: ", &ps_numsprites}, - {"drwnode", "Drawnodes: ", &ps_numdrawnodes}, - {"plyobjs", "Polyobjects: ", &ps_numpolyobjects}, - {0} - }; - - perfstatrow_t batchtime_row[] = { - {"batsort", "Batch sort: ", &ps_hw_batchsorttime}, - {"batdraw", "Batch render:", &ps_hw_batchdrawtime}, - {0} - }; - - perfstatrow_t batchcount_row[] = { - {"polygon", "Polygons: ", &ps_hw_numpolys}, - {"vertex ", "Vertices: ", &ps_hw_numverts}, - {0} - }; - - perfstatrow_t batchcalls_row[] = { - {"drwcall", "Draw calls:", &ps_hw_numcalls}, - {"shaders", "Shaders: ", &ps_hw_numshaders}, - {"texture", "Textures: ", &ps_hw_numtextures}, - {"polyflg", "Polyflags: ", &ps_hw_numpolyflags}, - {"colors ", "Colors: ", &ps_hw_numcolors}, - {0} - }; - - perfstatcol_t frametime_col = {20, 20, V_YELLOWMAP, frametime_row}; - perfstatcol_t rendercalltime_col = {20, 20, V_YELLOWMAP, rendercalltime_row}; - - perfstatcol_t opengltime_col = {24, 24, V_YELLOWMAP, opengltime_row}; - perfstatcol_t softwaretime_col = {24, 24, V_YELLOWMAP, softwaretime_row}; - - perfstatcol_t uiswaptime_col = {20, 20, V_YELLOWMAP, uiswaptime_row}; - perfstatcol_t tictime_col = {20, 20, V_GRAYMAP, tictime_row}; - - perfstatcol_t rendercalls_col = {90, 115, V_BLUEMAP, rendercalls_row}; - - perfstatcol_t batchtime_col = {90, 115, V_REDMAP, batchtime_row}; - - perfstatcol_t batchcount_col = {155, 200, V_PURPLEMAP, batchcount_row}; - perfstatcol_t batchcalls_col = {220, 200, V_PURPLEMAP, batchcalls_row}; - - - boolean rendering = ( - gamestate == GS_LEVEL || - (gamestate == GS_TITLESCREEN && titlemapinaction) - ); - - draw_row = 10; - M_DrawPerfTiming(&frametime_col); - - if (rendering) + perfstatrow_t *row; + for (row = rows; row->lores_label; row++) { - M_DrawPerfTiming(&rendercalltime_col); + if (PS_IsRowValid(row)) + PS_UpdateMetricHistory(row->metric, !!(row->flags & PS_TIME), frame_metric, true); + } +} +// Update all metrics that are calculated on every frame. +static void PS_UpdateFrameStats(void) +{ + // update frame time + precise_t currenttime = I_GetPreciseTime(); + ps_frametime.value.p = currenttime - ps_prevframetime; + ps_prevframetime = currenttime; + + // update 3d rendering stats + if (PS_IsLevelActive()) + { // Remember to update this calculation when adding more 3d rendering stats! - extrarendertime = ps_rendercalltime - ps_bsptime; + ps_otherrendertime.value.p = ps_rendercalltime.value.p - ps_bsptime.value.p; #ifdef HWRENDER if (rendermode == render_opengl) { - extrarendertime -= - ps_hw_skyboxtime + - ps_hw_nodesorttime + - ps_hw_nodedrawtime + - ps_hw_spritesorttime + - ps_hw_spritedrawtime; + ps_otherrendertime.value.p -= + ps_hw_skyboxtime.value.p + + ps_hw_nodesorttime.value.p + + ps_hw_nodedrawtime.value.p + + ps_hw_spritesorttime.value.p + + ps_hw_spritedrawtime.value.p; if (cv_glbatching.value) { - extrarendertime -= - ps_hw_batchsorttime + - ps_hw_batchdrawtime; + ps_otherrendertime.value.p -= + ps_hw_batchsorttime.value.p + + ps_hw_batchdrawtime.value.p; } - - M_DrawPerfTiming(&opengltime_col); } else #endif { - extrarendertime -= - ps_sw_spritecliptime + - ps_sw_portaltime + - ps_sw_planetime + - ps_sw_maskedtime; - - M_DrawPerfTiming(&softwaretime_col); + ps_otherrendertime.value.p -= + ps_sw_spritecliptime.value.p + + ps_sw_portaltime.value.p + + ps_sw_planetime.value.p + + ps_sw_maskedtime.value.p; } } - M_DrawPerfTiming(&uiswaptime_col); - - draw_row += half_row; - M_DrawPerfTiming(&tictime_col); - - if (rendering) + if (cv_ps_samplesize.value > 1) { - draw_row = 10; - M_DrawPerfCount(&rendercalls_col); + PS_UpdateRowHistories(rendertime_rows, true); + if (PS_IsLevelActive()) + PS_UpdateRowHistories(commoncounter_rows, true); #ifdef HWRENDER if (rendermode == render_opengl && cv_glbatching.value) { - draw_row += half_row; - M_DrawPerfTiming(&batchtime_col); - - draw_row = 10; - M_DrawPerfCount(&batchcount_col); - - if (hires) - draw_row += half_row; - else - draw_row = 10; - - M_DrawPerfCount(&batchcalls_col); + PS_UpdateRowHistories(batchcount_rows, true); + PS_UpdateRowHistories(batchcalls_rows, true); } #endif + + ps_frame_index++; + if (ps_frame_index >= cv_ps_samplesize.value) + ps_frame_index = 0; + if (ps_frame_samples_left) + ps_frame_samples_left--; } } -static void M_DrawTickStats(void) +// Update thinker counters by iterating the thinker lists. +static void PS_CountThinkers(void) { - int i = 0; + int i; thinker_t *thinker; - int thinkercount = 0; - int polythcount = 0; - int mainthcount = 0; - int mobjcount = 0; - int nothinkcount = 0; - int scenerycount = 0; - int regularcount = 0; - int dynslopethcount = 0; - int precipcount = 0; - int removecount = 0; - precise_t extratime = - ps_tictime - - ps_playerthink_time - - ps_thinkertime - - ps_lua_thinkframe_time; - - perfstatrow_t tictime_row[] = { - {"logic ", "Game logic: ", &ps_tictime}, - {0} - }; - - perfstatrow_t thinker_time_row[] = { - {"plrthnk", "P_PlayerThink: ", &ps_playerthink_time}, - {"thnkers", "P_RunThinkers: ", &ps_thinkertime}, - {0} - }; - - perfstatrow_t detailed_thinker_time_row[] = { - {"plyobjs", "Polyobjects: ", &ps_thlist_times[THINK_POLYOBJ]}, - {"main ", "Main: ", &ps_thlist_times[THINK_MAIN]}, - {"mobjs ", "Mobjs: ", &ps_thlist_times[THINK_MOBJ]}, - {"dynslop", "Dynamic slopes: ", &ps_thlist_times[THINK_DYNSLOPE]}, - {"precip ", "Precipitation: ", &ps_thlist_times[THINK_PRECIP]}, - {0} - }; - - perfstatrow_t extra_thinker_time_row[] = { - {"lthinkf", "LUAh_ThinkFrame:", &ps_lua_thinkframe_time}, - {"other ", "Other: ", &extratime}, - {0} - }; - - perfstatrow_t thinkercount_row[] = { - {"thnkers", "Thinkers: ", &thinkercount}, - {0} - }; - - perfstatrow_t detailed_thinkercount_row[] = { - {"plyobjs", "Polyobjects: ", &polythcount}, - {"main ", "Main: ", &mainthcount}, - {"mobjs ", "Mobjs: ", &mobjcount}, - {0} - }; - - perfstatrow_t mobjthinkercount_row[] = { - {"regular", "Regular: ", ®ularcount}, - {"scenery", "Scenery: ", &scenerycount}, - {0} - }; - - perfstatrow_t nothinkcount_row[] = { - {"nothink", "Nothink: ", ¬hinkcount}, - {0} - }; - - perfstatrow_t detailed_thinkercount_row2[] = { - {"dynslop", "Dynamic slopes: ", &dynslopethcount}, - {"precip ", "Precipitation: ", &precipcount}, - {"remove ", "Pending removal:", &removecount}, - {0} - }; - - perfstatrow_t misc_calls_row[] = { - {"lmhook", "Lua mobj hooks: ", &ps_lua_mobjhooks}, - {"chkpos", "P_CheckPosition:", &ps_checkposition_calls}, - {0} - }; - - perfstatcol_t tictime_col = {20, 20, V_YELLOWMAP, tictime_row}; - perfstatcol_t thinker_time_col = {24, 24, V_YELLOWMAP, thinker_time_row}; - perfstatcol_t detailed_thinker_time_col = {28, 28, V_YELLOWMAP, detailed_thinker_time_row}; - perfstatcol_t extra_thinker_time_col = {24, 24, V_YELLOWMAP, extra_thinker_time_row}; - - perfstatcol_t thinkercount_col = {90, 115, V_BLUEMAP, thinkercount_row}; - perfstatcol_t detailed_thinkercount_col = {94, 119, V_BLUEMAP, detailed_thinkercount_row}; - perfstatcol_t mobjthinkercount_col = {98, 123, V_BLUEMAP, mobjthinkercount_row}; - perfstatcol_t nothinkcount_col = {98, 123, V_BLUEMAP, nothinkcount_row}; - perfstatcol_t detailed_thinkercount_col2 = {94, 119, V_BLUEMAP, detailed_thinkercount_row2}; - perfstatcol_t misc_calls_col = {170, 216, V_PURPLEMAP, misc_calls_row}; + ps_thinkercount.value.i = 0; + ps_polythcount.value.i = 0; + ps_mainthcount.value.i = 0; + ps_mobjcount.value.i = 0; + ps_regularcount.value.i = 0; + ps_scenerycount.value.i = 0; + ps_nothinkcount.value.i = 0; + ps_dynslopethcount.value.i = 0; + ps_precipcount.value.i = 0; + ps_removecount.value.i = 0; for (i = 0; i < NUM_THINKERLISTS; i++) { for (thinker = thlist[i].next; thinker != &thlist[i]; thinker = thinker->next) { - thinkercount++; + ps_thinkercount.value.i++; if (thinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - removecount++; + ps_removecount.value.i++; else if (i == THINK_POLYOBJ) - polythcount++; + ps_polythcount.value.i++; else if (i == THINK_MAIN) - mainthcount++; + ps_mainthcount.value.i++; else if (i == THINK_MOBJ) { if (thinker->function.acp1 == (actionf_p1)P_MobjThinker) { mobj_t *mobj = (mobj_t*)thinker; - mobjcount++; + ps_mobjcount.value.i++; if (mobj->flags & MF_NOTHINK) - nothinkcount++; + ps_nothinkcount.value.i++; else if (mobj->flags & MF_SCENERY) - scenerycount++; + ps_scenerycount.value.i++; else - regularcount++; + ps_regularcount.value.i++; } } else if (i == THINK_DYNSLOPE) - dynslopethcount++; + ps_dynslopethcount.value.i++; else if (i == THINK_PRECIP) - precipcount++; + ps_precipcount.value.i++; } } +} - draw_row = 10; - M_DrawPerfTiming(&tictime_col); - M_DrawPerfTiming(&thinker_time_col); - M_DrawPerfTiming(&detailed_thinker_time_col); - M_DrawPerfTiming(&extra_thinker_time_col); - - draw_row = 10; - M_DrawPerfCount(&thinkercount_col); - M_DrawPerfCount(&detailed_thinkercount_col); - M_DrawPerfCount(&mobjthinkercount_col); - - if (nothinkcount) - M_DrawPerfCount(¬hinkcount_col); - - M_DrawPerfCount(&detailed_thinkercount_col2); - - if (M_HighResolution()) +// Update all metrics that are calculated on every tick. +void PS_UpdateTickStats(void) +{ + if (cv_perfstats.value == 1 && cv_ps_samplesize.value > 1) { + PS_UpdateRowHistories(gamelogicbrief_row, false); + } + if (cv_perfstats.value == 2) + { + if (PS_IsLevelActive()) + { + ps_otherlogictime.value.p = + ps_tictime.value.p - + ps_playerthink_time.value.p - + ps_thinkertime.value.p - + ps_lua_thinkframe_time.value.p; + + PS_CountThinkers(); + } + + if (cv_ps_samplesize.value > 1) + { + PS_UpdateRowHistories(gamelogic_rows, false); + PS_UpdateRowHistories(thinkercount_rows, false); + PS_UpdateRowHistories(misc_calls_rows, false); + } + } + if (cv_perfstats.value == 3 && cv_ps_samplesize.value > 1 && PS_IsLevelActive()) + { + int i; + for (i = 0; i < thinkframe_hooks_length; i++) + { + PS_UpdateMetricHistory(&thinkframe_hooks[i].time_taken, true, false, false); + } + } + if (cv_perfstats.value && cv_ps_samplesize.value > 1) + { + ps_tick_index++; + if (ps_tick_index >= cv_ps_samplesize.value) + ps_tick_index = 0; + if (ps_tick_samples_left) + ps_tick_samples_left--; + } +} + +static void PS_DrawDescriptorHeader(void) +{ + if (cv_ps_samplesize.value > 1) + { + const char* descriptor_names[] = { + "average", + "standard deviation", + "minimum", + "maximum" + }; + const boolean hires = PS_HighResolution(); + char* str; + INT32 flags = V_MONOSPACE | V_ALLOWLOWERCASE; + int samples_left = max(ps_frame_samples_left, ps_tick_samples_left); + int x, y; + + if (cv_perfstats.value == 3) + { + x = 2; + y = 0; + } + else + { + x = 20; + y = hires ? 5 : 2; + } + + if (samples_left) + { + str = va("Samples needed for correct results: %d", samples_left); + flags |= V_REDMAP; + } + else + { + str = va("Showing the %s of %d samples.", + descriptor_names[cv_ps_descriptor.value - 1], cv_ps_samplesize.value); + flags |= V_GREENMAP; + } + + if (hires) + V_DrawSmallString(x, y, flags, str); + else + V_DrawThinString(x, y, flags, str); + } +} + +static void PS_DrawRenderStats(void) +{ + const boolean hires = PS_HighResolution(); + const int half_row = hires ? 5 : 4; + int x, y; + + PS_DrawDescriptorHeader(); + + y = PS_DrawPerfRows(20, 10, V_YELLOWMAP, rendertime_rows); + + PS_DrawPerfRows(20, y + half_row, V_GRAYMAP, gamelogicbrief_row); + + if (PS_IsLevelActive()) + { + x = hires ? 115 : 90; + PS_DrawPerfRows(x, 10, V_BLUEMAP, commoncounter_rows); + +#ifdef HWRENDER + if (rendermode == render_opengl && cv_glbatching.value) + { + x = hires ? 200 : 155; + y = PS_DrawPerfRows(x, 10, V_PURPLEMAP, batchcount_rows); + + x = hires ? 200 : 220; + y = hires ? y + half_row : 10; + PS_DrawPerfRows(x, y, V_PURPLEMAP, batchcalls_rows); + } +#endif + } +} + +static void PS_DrawGameLogicStats(void) +{ + const boolean hires = PS_HighResolution(); + int x, y; + + PS_DrawDescriptorHeader(); + + PS_DrawPerfRows(20, 10, V_YELLOWMAP, gamelogic_rows); + + x = hires ? 115 : 90; + PS_DrawPerfRows(x, 10, V_BLUEMAP, thinkercount_rows); + + if (hires) V_DrawSmallString(212, 10, V_MONOSPACE | V_ALLOWLOWERCASE | V_PURPLEMAP, "Calls:"); - draw_row = 15; - } - else - { - draw_row = 10; - } + x = hires ? 216 : 170; + y = hires ? 15 : 10; + PS_DrawPerfRows(x, y, V_PURPLEMAP, misc_calls_rows); +} - M_DrawPerfCount(&misc_calls_col); +static void PS_DrawThinkFrameStats(void) +{ + char s[100]; + int i; + // text writing position + int x = 2; + int y = 4; + UINT32 text_color; + char tempbuffer[LUA_IDSIZE]; + char last_mod_name[LUA_IDSIZE]; + last_mod_name[0] = '\0'; + + PS_DrawDescriptorHeader(); + + for (i = 0; i < thinkframe_hooks_length; i++) + { + +#define NEXT_ROW() \ +y += 4; \ +if (y > 192) \ +{ \ + y = 4; \ + x += 106; \ + if (x > 214) \ + break; \ +} + + char* str = thinkframe_hooks[i].short_src; + char* tempstr = tempbuffer; + int len = (int)strlen(str); + char* str_ptr; + if (strcmp(".lua", str + len - 4) == 0) + { + str[len-4] = '\0'; // remove .lua at end + len -= 4; + } + // we locate the wad/pk3 name in the string and compare it to + // what we found on the previous iteration. + // if the name has changed, print it out on the screen + strcpy(tempstr, str); + str_ptr = strrchr(tempstr, '|'); + if (str_ptr) + { + *str_ptr = '\0'; + str = str_ptr + 1; // this is the name of the hook without the mod file name + str_ptr = strrchr(tempstr, PATHSEP[0]); + if (str_ptr) + tempstr = str_ptr + 1; + // tempstr should now point to the mod name, (wad/pk3) possibly truncated + if (strcmp(tempstr, last_mod_name) != 0) + { + strcpy(last_mod_name, tempstr); + len = (int)strlen(tempstr); + if (len > 25) + tempstr += len - 25; + snprintf(s, sizeof s - 1, "%s", tempstr); + V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | V_GRAYMAP, s); + NEXT_ROW() + } + text_color = V_YELLOWMAP; + } + else + { + // probably a standalone lua file + // cut off the folder if it's there + str_ptr = strrchr(tempstr, PATHSEP[0]); + if (str_ptr) + str = str_ptr + 1; + text_color = 0; // white + } + len = (int)strlen(str); + if (len > 20) + str += len - 20; + snprintf(s, sizeof s - 1, "%20s: %d", str, + PS_GetMetricScreenValue(&thinkframe_hooks[i].time_taken, true)); + V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | text_color, s); + NEXT_ROW() + +#undef NEXT_ROW + + } } void M_DrawPerfStats(void) { - char s[100]; - - PS_SetFrameTime(); - if (cv_perfstats.value == 1) // rendering { - M_DrawRenderStats(); + PS_UpdateFrameStats(); + PS_DrawRenderStats(); } else if (cv_perfstats.value == 2) // logic { - M_DrawTickStats(); + // PS_UpdateTickStats is called in TryRunTics, since otherwise it would miss + // tics when frame skips happen + PS_DrawGameLogicStats(); } else if (cv_perfstats.value == 3) // lua thinkframe { - if (!(gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + if (!PS_IsLevelActive()) return; - if (vid.width < 640 || vid.height < 400) // low resolution + if (!PS_HighResolution()) { - // it's not gonna fit very well.. - V_DrawThinString(30, 30, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "Not available for resolutions below 640x400"); + // Low resolutions can't really use V_DrawSmallString that is used by thinkframe stats. + // A low-res version using V_DrawThinString could be implemented, + // but it would have much less space for information. + V_DrawThinString(80, 92, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "Perfstats 3 is not available"); + V_DrawThinString(80, 100, V_MONOSPACE | V_ALLOWLOWERCASE | V_YELLOWMAP, "for resolutions below 640x400."); } - else // high resolution + else { - int i; - // text writing position - int x = 2; - int y = 4; - UINT32 text_color; - char tempbuffer[LUA_IDSIZE]; - char last_mod_name[LUA_IDSIZE]; - last_mod_name[0] = '\0'; - for (i = 0; i < thinkframe_hooks_length; i++) - { - char* str = thinkframe_hooks[i].short_src; - char* tempstr = tempbuffer; - int len = (int)strlen(str); - char* str_ptr; - if (strcmp(".lua", str + len - 4) == 0) - { - str[len-4] = '\0'; // remove .lua at end - len -= 4; - } - // we locate the wad/pk3 name in the string and compare it to - // what we found on the previous iteration. - // if the name has changed, print it out on the screen - strcpy(tempstr, str); - str_ptr = strrchr(tempstr, '|'); - if (str_ptr) - { - *str_ptr = '\0'; - str = str_ptr + 1; // this is the name of the hook without the mod file name - str_ptr = strrchr(tempstr, PATHSEP[0]); - if (str_ptr) - tempstr = str_ptr + 1; - // tempstr should now point to the mod name, (wad/pk3) possibly truncated - if (strcmp(tempstr, last_mod_name) != 0) - { - strcpy(last_mod_name, tempstr); - len = (int)strlen(tempstr); - if (len > 25) - tempstr += len - 25; - snprintf(s, sizeof s - 1, "%s", tempstr); - V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | V_GRAYMAP, s); - y += 4; // repeated code! - if (y > 192) - { - y = 4; - x += 106; - if (x > 214) - break; - } - } - text_color = V_YELLOWMAP; - } - else - { - // probably a standalone lua file - // cut off the folder if it's there - str_ptr = strrchr(tempstr, PATHSEP[0]); - if (str_ptr) - str = str_ptr + 1; - text_color = 0; // white - } - len = (int)strlen(str); - if (len > 20) - str += len - 20; - snprintf(s, sizeof s - 1, "%20s: %u", str, thinkframe_hooks[i].time_taken); - V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | text_color, s); - y += 4; // repeated code! - if (y > 192) - { - y = 4; - x += 106; - if (x > 214) - break; - } - } + PS_DrawThinkFrameStats(); } } } + +// remove and unallocate history from all metrics +static void PS_ClearHistory(void) +{ + int i; + + Z_FreeTag(PU_PERFSTATS); + // thinkframe hook metric history pointers need to be cleared manually + for (i = 0; i < thinkframe_hooks_length; i++) + { + thinkframe_hooks[i].time_taken.history = NULL; + } + + ps_frame_index = ps_tick_index = 0; + // PS_UpdateMetricHistory will set these correctly when it runs + ps_frame_samples_left = ps_tick_samples_left = 0; +} + +void PS_PerfStats_OnChange(void) +{ + if (cv_perfstats.value && cv_ps_samplesize.value > 1) + PS_ClearHistory(); +} + +void PS_SampleSize_OnChange(void) +{ + if (cv_ps_samplesize.value > 1) + PS_ClearHistory(); +} diff --git a/src/m_perfstats.h b/src/m_perfstats.h index 132bea38c..f6a7c1f74 100644 --- a/src/m_perfstats.h +++ b/src/m_perfstats.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by Sonic Team Junior. +// Copyright (C) 2020-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -16,26 +16,45 @@ #include "lua_script.h" #include "p_local.h" -extern precise_t ps_tictime; - -extern precise_t ps_playerthink_time; -extern precise_t ps_thinkertime; - -extern precise_t ps_thlist_times[]; - -extern int ps_checkposition_calls; - -extern precise_t ps_lua_thinkframe_time; -extern int ps_lua_mobjhooks; +typedef struct +{ + union { + precise_t p; + INT32 i; + } value; + void *history; +} ps_metric_t; typedef struct { - UINT32 time_taken; + ps_metric_t time_taken; char short_src[LUA_IDSIZE]; } ps_hookinfo_t; -void PS_SetThinkFrameHookInfo(int index, UINT32 time_taken, char* short_src); +#define PS_START_TIMING(metric) metric.value.p = I_GetPreciseTime() +#define PS_STOP_TIMING(metric) metric.value.p = I_GetPreciseTime() - metric.value.p + +extern ps_metric_t ps_tictime; + +extern ps_metric_t ps_playerthink_time; +extern ps_metric_t ps_thinkertime; + +extern ps_metric_t ps_thlist_times[]; + +extern ps_metric_t ps_checkposition_calls; + +extern ps_metric_t ps_lua_thinkframe_time; +extern ps_metric_t ps_lua_mobjhooks; + +extern ps_metric_t ps_otherlogictime; + +void PS_SetThinkFrameHookInfo(int index, precise_t time_taken, char* short_src); + +void PS_UpdateTickStats(void); void M_DrawPerfStats(void); +void PS_PerfStats_OnChange(void); +void PS_SampleSize_OnChange(void); + #endif diff --git a/src/m_queue.c b/src/m_queue.c index 8603ab202..2cc3f7cb8 100644 --- a/src/m_queue.c +++ b/src/m_queue.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2003 by James Haley -// Copyright (C) 2003-2020 by Sonic Team Junior. +// Copyright (C) 2003-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_queue.h b/src/m_queue.h index 3e9579e11..071f9d8fa 100644 --- a/src/m_queue.h +++ b/src/m_queue.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2003 by James Haley -// Copyright (C) 2003-2020 by Sonic Team Junior. +// Copyright (C) 2003-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_random.c b/src/m_random.c index 481fdb72b..112795500 100644 --- a/src/m_random.c +++ b/src/m_random.c @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -60,7 +60,7 @@ UINT8 M_RandomByte(void) */ INT32 M_RandomKey(INT32 a) { - return (INT32)((rand()/((unsigned)RAND_MAX+1.0f))*a); + return (INT32)((rand()/((float)RAND_MAX+1.0f))*a); } /** Provides a random integer in a given range. @@ -73,7 +73,7 @@ INT32 M_RandomKey(INT32 a) */ INT32 M_RandomRange(INT32 a, INT32 b) { - return (INT32)((rand()/((unsigned)RAND_MAX+1.0f))*(b-a+1))+a; + return (INT32)((rand()/((float)RAND_MAX+1.0f))*(b-a+1))+a; } diff --git a/src/m_random.h b/src/m_random.h index 01190e046..aa5ffb0bb 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -3,7 +3,7 @@ // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/m_swap.h b/src/m_swap.h index b44d6de8c..df5f3e907 100644 --- a/src/m_swap.h +++ b/src/m_swap.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/mserv.c b/src/mserv.c index dfb417415..bff562c95 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -1,8 +1,8 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. -// Copyright (C) 2020 by James R. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// Copyright (C) 2020-2022 by James R. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -98,6 +98,7 @@ void AddMServCommands(void) CV_RegisterVar(&cv_servername); #ifdef MASTERSERVER COM_AddCommand("listserv", Command_Listserv_f); + COM_AddCommand("masterserver_update", Update_parameters); // allows people to updates manually in case you were delisted by accident #endif #endif } diff --git a/src/mserv.h b/src/mserv.h index d0d5e49df..23b26fbc5 100644 --- a/src/mserv.h +++ b/src/mserv.h @@ -1,8 +1,8 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. -// Copyright (C) 2020 by James R. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// Copyright (C) 2020-2022 by James R. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_ceilng.c b/src/p_ceilng.c index f12499d5c..d88d9be86 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -34,7 +34,6 @@ INT32 ceilmovesound = sfx_None; void T_MoveCeiling(ceiling_t *ceiling) { result_e res; - boolean dontupdate = false; if (ceiling->delaytimer) { @@ -42,257 +41,81 @@ void T_MoveCeiling(ceiling_t *ceiling) return; } - switch (ceiling->direction) + res = T_MovePlane(ceiling->sector, ceiling->speed, (ceiling->direction == 1) ? ceiling->topheight : ceiling->bottomheight, false, true, ceiling->direction); + + if (ceiling->type == bounceCeiling) { - case 0: // IN STASIS - break; - case 1: // UP - res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->topheight, false, true, ceiling->direction); - - if (ceiling->type == bounceCeiling) - { - const fixed_t origspeed = FixedDiv(ceiling->origspeed,(ELEVATORSPEED/2)); - const fixed_t fs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].frontsector->ceilingheight); - const fixed_t bs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].backsector->ceilingheight); - if (fs < bs) - ceiling->speed = FixedDiv(fs,25*FRACUNIT) + FRACUNIT/4; - else - ceiling->speed = FixedDiv(bs,25*FRACUNIT) + FRACUNIT/4; - - ceiling->speed = FixedMul(ceiling->speed,origspeed); - } - - if (res == pastdest) - { - switch (ceiling->type) - { - case instantMoveCeilingByFrontSector: - ceiling->sector->ceilingpic = ceiling->texture; - ceiling->sector->ceilingdata = NULL; - ceiling->sector->ceilspeed = 0; - P_RemoveThinker(&ceiling->thinker); - dontupdate = true; - break; - case moveCeilingByFrontSector: - if (ceiling->texture < -1) // chained linedef executing - P_LinedefExecute((INT16)(ceiling->texture + INT16_MAX + 2), NULL, NULL); - if (ceiling->texture > -1) // flat changing - ceiling->sector->ceilingpic = ceiling->texture; - /* FALLTHRU */ - case raiseToHighest: -// case raiseCeilingByLine: - case moveCeilingByFrontTexture: - ceiling->sector->ceilingdata = NULL; - ceiling->sector->ceilspeed = 0; - P_RemoveThinker(&ceiling->thinker); - dontupdate = true; - break; - - case fastCrushAndRaise: - case crushAndRaise: - ceiling->direction = -1; - break; - - case bounceCeiling: - { - fixed_t dest = ceiling->topheight; - - if (dest == lines[ceiling->texture].frontsector->ceilingheight) - dest = lines[ceiling->texture].backsector->ceilingheight; - else - dest = lines[ceiling->texture].frontsector->ceilingheight; - - if (dest < ceiling->sector->ceilingheight) // must move down - { - ceiling->direction = -1; - ceiling->bottomheight = dest; - } - else // must move up - { - ceiling->direction = 1; - ceiling->topheight = dest; - } - - ceiling->delaytimer = ceiling->delay; - - // That's it. Do not set dontupdate, do not remove the thinker. - break; - } - - case bounceCeilingCrush: - { - fixed_t dest = ceiling->topheight; - - if (dest == lines[ceiling->texture].frontsector->ceilingheight) - { - dest = lines[ceiling->texture].backsector->ceilingheight; - ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dy),4*FRACUNIT); // return trip, use dy - } - else - { - dest = lines[ceiling->texture].frontsector->ceilingheight; - ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dx),4*FRACUNIT); // going frontways, use dx - } - - if (dest < ceiling->sector->ceilingheight) // must move down - { - ceiling->direction = -1; - ceiling->bottomheight = dest; - } - else // must move up - { - ceiling->direction = 1; - ceiling->topheight = dest; - } - - ceiling->delaytimer = ceiling->delay; - - // That's it. Do not set dontupdate, do not remove the thinker. - break; - } - - default: - break; - } - } - break; - - case -1: // DOWN - res = T_MovePlane(ceiling->sector, ceiling->speed, ceiling->bottomheight, ceiling->crush, true, ceiling->direction); - - if (ceiling->type == bounceCeiling) - { - const fixed_t origspeed = FixedDiv(ceiling->origspeed,(ELEVATORSPEED/2)); - const fixed_t fs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].frontsector->ceilingheight); - const fixed_t bs = abs(ceiling->sector->ceilingheight - lines[ceiling->texture].backsector->ceilingheight); - if (fs < bs) - ceiling->speed = FixedDiv(fs,25*FRACUNIT) + FRACUNIT/4; - else - ceiling->speed = FixedDiv(bs,25*FRACUNIT) + FRACUNIT/4; - ceiling->speed = FixedMul(ceiling->speed,origspeed); - } - - if (res == pastdest) - { - switch (ceiling->type) - { - // make platform stop at bottom of all crusher strokes - // except generalized ones, reset speed, start back up - case crushAndRaise: - ceiling->speed = CEILSPEED; - /* FALLTHRU */ - case fastCrushAndRaise: - ceiling->direction = 1; - break; - - case instantMoveCeilingByFrontSector: - ceiling->sector->ceilingpic = ceiling->texture; - ceiling->sector->ceilingdata = NULL; - ceiling->sector->ceilspeed = 0; - P_RemoveThinker(&ceiling->thinker); - dontupdate = true; - break; - - case moveCeilingByFrontSector: - if (ceiling->texture < -1) // chained linedef executing - P_LinedefExecute((INT16)(ceiling->texture + INT16_MAX + 2), NULL, NULL); - if (ceiling->texture > -1) // flat changing - ceiling->sector->ceilingpic = ceiling->texture; - // don't break - /* FALLTHRU */ - - // in all other cases, just remove the active ceiling - case lowerAndCrush: - case lowerToLowest: - case raiseToLowest: -// case lowerCeilingByLine: - case moveCeilingByFrontTexture: - ceiling->sector->ceilingdata = NULL; - ceiling->sector->ceilspeed = 0; - P_RemoveThinker(&ceiling->thinker); - dontupdate = true; - break; - case bounceCeiling: - { - fixed_t dest = ceiling->bottomheight; - - if (dest == lines[ceiling->texture].frontsector->ceilingheight) - dest = lines[ceiling->texture].backsector->ceilingheight; - else - dest = lines[ceiling->texture].frontsector->ceilingheight; - - if (dest < ceiling->sector->ceilingheight) // must move down - { - ceiling->direction = -1; - ceiling->bottomheight = dest; - } - else // must move up - { - ceiling->direction = 1; - ceiling->topheight = dest; - } - - ceiling->delaytimer = ceiling->delay; - - // That's it. Do not set dontupdate, do not remove the thinker. - break; - } - - case bounceCeilingCrush: - { - fixed_t dest = ceiling->bottomheight; - - if (dest == lines[ceiling->texture].frontsector->ceilingheight) - { - dest = lines[ceiling->texture].backsector->ceilingheight; - ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dy),4*FRACUNIT); // return trip, use dy - } - else - { - dest = lines[ceiling->texture].frontsector->ceilingheight; - ceiling->speed = ceiling->origspeed = FixedDiv(abs(lines[ceiling->texture].dx),4*FRACUNIT); // going frontways, use dx - } - - if (dest < ceiling->sector->ceilingheight) // must move down - { - ceiling->direction = -1; - ceiling->bottomheight = dest; - } - else // must move up - { - ceiling->direction = 1; - ceiling->topheight = dest; - } - - ceiling->delaytimer = ceiling->delay; - - // That's it. Do not set dontupdate, do not remove the thinker. - break; - } - - default: - break; - } - } - else if (res == crushed) - { - switch (ceiling->type) - { - case crushAndRaise: - case lowerAndCrush: - ceiling->speed = FixedDiv(CEILSPEED,8*FRACUNIT); - break; - - default: - break; - } - } - break; + const fixed_t origspeed = FixedDiv(ceiling->origspeed, (ELEVATORSPEED/2)); + const fixed_t fs = abs(ceiling->sector->ceilingheight - lines[ceiling->sourceline].frontsector->ceilingheight); + const fixed_t bs = abs(ceiling->sector->ceilingheight - lines[ceiling->sourceline].backsector->ceilingheight); + if (fs < bs) + ceiling->speed = FixedDiv(fs, 25*FRACUNIT) + FRACUNIT/4; + else + ceiling->speed = FixedDiv(bs, 25*FRACUNIT) + FRACUNIT/4; + ceiling->speed = FixedMul(ceiling->speed, origspeed); } - if (!dontupdate) - ceiling->sector->ceilspeed = ceiling->speed*ceiling->direction; - else - ceiling->sector->ceilspeed = 0; + + if (res == pastdest) + { + switch (ceiling->type) + { + case instantMoveCeilingByFrontSector: + if (ceiling->texture > -1) // flat changing + ceiling->sector->ceilingpic = ceiling->texture; + ceiling->sector->ceilingdata = NULL; + ceiling->sector->ceilspeed = 0; + P_RemoveThinker(&ceiling->thinker); + return; + case moveCeilingByFrontSector: + if (ceiling->tag) // chained linedef executing + P_LinedefExecute(ceiling->tag, NULL, NULL); + if (ceiling->texture > -1) // flat changing + ceiling->sector->ceilingpic = ceiling->texture; + /* FALLTHRU */ + case raiseToHighest: + case moveCeilingByDistance: + ceiling->sector->ceilingdata = NULL; + ceiling->sector->ceilspeed = 0; + P_RemoveThinker(&ceiling->thinker); + return; + case bounceCeiling: + case bounceCeilingCrush: + { + fixed_t dest = (ceiling->direction == 1) ? ceiling->topheight : ceiling->bottomheight; + + if (dest == lines[ceiling->sourceline].frontsector->ceilingheight) + { + dest = lines[ceiling->sourceline].backsector->ceilingheight; + ceiling->origspeed = lines[ceiling->sourceline].args[3] << (FRACBITS - 2); // return trip, use args[3] + } + else + { + dest = lines[ceiling->sourceline].frontsector->ceilingheight; + ceiling->origspeed = lines[ceiling->sourceline].args[2] << (FRACBITS - 2); // going frontways, use args[2] + } + + if (ceiling->type == bounceCeilingCrush) + ceiling->speed = ceiling->origspeed; + + if (dest < ceiling->sector->ceilingheight) // must move down + { + ceiling->direction = -1; + ceiling->bottomheight = dest; + } + else // must move up + { + ceiling->direction = 1; + ceiling->topheight = dest; + } + + ceiling->delaytimer = ceiling->delay; + break; + } + default: + break; + } + } + ceiling->sector->ceilspeed = ceiling->speed*ceiling->direction; } /** Moves a ceiling crusher. @@ -320,11 +143,7 @@ void T_CrushCeiling(ceiling_t *ceiling) if (res == pastdest) { ceiling->direction = -1; - - if (lines[ceiling->sourceline].flags & ML_EFFECT4) - ceiling->speed = ceiling->oldspeed; - else - ceiling->speed = ceiling->oldspeed*2; + ceiling->speed = lines[ceiling->sourceline].args[2] << (FRACBITS - 2); if (ceiling->type == crushCeilOnce || ceiling->type == crushBothOnce) @@ -365,12 +184,8 @@ void T_CrushCeiling(ceiling_t *ceiling) ceiling->sector->soundorg.z = ceiling->sector->floorheight; S_StartSound(mp,sfx_pstop); - if (lines[ceiling->sourceline].flags & ML_EFFECT4) - ceiling->speed = ceiling->oldspeed; - else - ceiling->speed = ceiling->oldspeed/2; - ceiling->direction = 1; + ceiling->speed = lines[ceiling->sourceline].args[3] << (FRACBITS - 2); } break; } @@ -383,21 +198,20 @@ void T_CrushCeiling(ceiling_t *ceiling) /** Starts a ceiling mover. * + * \param tag Tag. * \param line The source line. * \param type The type of ceiling movement. * \return 1 if at least one ceiling mover was started, 0 otherwise. * \sa EV_DoCrush, EV_DoFloor, EV_DoElevator, T_MoveCeiling */ -INT32 EV_DoCeiling(line_t *line, ceiling_e type) +INT32 EV_DoCeiling(mtag_t tag, line_t *line, ceiling_e type) { INT32 rtn = 0, firstone = 1; INT32 secnum = -1; sector_t *sec; ceiling_t *ceiling; - mtag_t tag = Tag_FGet(&line->tags); - TAG_ITER_DECLARECOUNTER(0); - TAG_ITER_SECTORS(0, tag, secnum) + TAG_ITER_SECTORS(tag, secnum) { sec = §ors[secnum]; @@ -416,44 +230,12 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) switch (type) { - case fastCrushAndRaise: - ceiling->crush = true; - ceiling->topheight = sec->ceilingheight; - ceiling->bottomheight = sec->floorheight + (8*FRACUNIT); - ceiling->direction = -1; - ceiling->speed = CEILSPEED * 2; - break; - - case crushAndRaise: - ceiling->crush = true; - ceiling->topheight = sec->ceilingheight; - /* FALLTHRU */ - case lowerAndCrush: - ceiling->bottomheight = sec->floorheight; - ceiling->bottomheight += 4*FRACUNIT; - ceiling->direction = -1; - ceiling->speed = line->dx; - break; - case raiseToHighest: ceiling->topheight = P_FindHighestCeilingSurrounding(sec); ceiling->direction = 1; ceiling->speed = CEILSPEED; break; - //SoM: 3/6/2000: Added Boom types - case lowerToLowest: - ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec); - ceiling->direction = -1; - ceiling->speed = CEILSPEED; - break; - - case raiseToLowest: // Graue 09-07-2004 - ceiling->topheight = P_FindLowestCeilingSurrounding(sec) - 4*FRACUNIT; - ceiling->direction = 1; - ceiling->speed = line->dx; // hack - break; - case lowerToLowestFast: ceiling->bottomheight = P_FindLowestCeilingSurrounding(sec); ceiling->direction = -1; @@ -468,8 +250,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) // Linedef executor excellence case moveCeilingByFrontSector: - ceiling->speed = P_AproxDistance(line->dx, line->dy); - ceiling->speed = FixedDiv(ceiling->speed,8*FRACUNIT); + ceiling->speed = line->args[2] << (FRACBITS - 3); if (line->frontsector->ceilingheight >= sec->ceilingheight) // Move up { ceiling->direction = 1; @@ -482,21 +263,13 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) } // chained linedef executing ability - if (line->flags & ML_BLOCKMONSTERS) - { - // only set it on ONE of the moving sectors (the smallest numbered) - // and front side x offset must be positive - if (firstone && sides[line->sidenum[0]].textureoffset > 0) - ceiling->texture = (sides[line->sidenum[0]].textureoffset>>FRACBITS) - 32769; - else - ceiling->texture = -1; - } + // only set it on ONE of the moving sectors (the smallest numbered) + // only set it if there isn't also a floor mover + if (line->args[3] && line->args[1] == 1) + ceiling->tag = firstone ? (INT16)line->args[3] : 0; // flat changing ability - else if (line->flags & ML_NOCLIMB) - ceiling->texture = line->frontsector->ceilingpic; - else - ceiling->texture = -1; + ceiling->texture = line->args[4] ? line->frontsector->ceilingpic : -1; break; // More linedef executor junk @@ -513,64 +286,30 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) ceiling->direction = -1; ceiling->bottomheight = line->frontsector->ceilingheight; } - ceiling->texture = line->frontsector->ceilingpic; + + // If flag is set, change ceiling texture after moving + ceiling->texture = line->args[2] ? line->frontsector->ceilingpic : -1; break; - case moveCeilingByFrontTexture: - if (line->flags & ML_NOCLIMB) + case moveCeilingByDistance: + if (line->args[4]) ceiling->speed = INT32_MAX/2; // as above, "instant" is one tic else - ceiling->speed = FixedDiv(sides[line->sidenum[0]].textureoffset,8*FRACUNIT); // texture x offset - if (sides[line->sidenum[0]].rowoffset > 0) + ceiling->speed = line->args[3] << (FRACBITS - 3); + if (line->args[2] > 0) { ceiling->direction = 1; // up - ceiling->topheight = sec->ceilingheight + sides[line->sidenum[0]].rowoffset; // texture y offset + ceiling->topheight = sec->ceilingheight + (line->args[2] << FRACBITS); } else { ceiling->direction = -1; // down - ceiling->bottomheight = sec->ceilingheight + sides[line->sidenum[0]].rowoffset; // texture y offset + ceiling->bottomheight = sec->ceilingheight + (line->args[2] << FRACBITS); } break; -/* - case lowerCeilingByLine: - ceiling->speed = FixedDiv(abs(line->dx),8*FRACUNIT); - ceiling->direction = -1; // Move down - ceiling->bottomheight = sec->ceilingheight - abs(line->dy); - break; - - case raiseCeilingByLine: - ceiling->speed = FixedDiv(abs(line->dx),8*FRACUNIT); - ceiling->direction = 1; // Move up - ceiling->topheight = sec->ceilingheight + abs(line->dy); - break; -*/ - case bounceCeiling: - ceiling->speed = P_AproxDistance(line->dx, line->dy); // same speed as elevateContinuous - ceiling->speed = FixedDiv(ceiling->speed,4*FRACUNIT); - ceiling->origspeed = ceiling->speed; - if (line->frontsector->ceilingheight >= sec->ceilingheight) // Move up - { - ceiling->direction = 1; - ceiling->topheight = line->frontsector->ceilingheight; - } - else // Move down - { - ceiling->direction = -1; - ceiling->bottomheight = line->frontsector->ceilingheight; - } - - // Any delay? - ceiling->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS; - ceiling->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Initial delay - - ceiling->texture = (fixed_t)(line - lines); // hack: use texture to store sourceline number - break; - case bounceCeilingCrush: - ceiling->speed = abs(line->dx); // same speed as elevateContinuous - ceiling->speed = FixedDiv(ceiling->speed,4*FRACUNIT); + ceiling->speed = line->args[2] << (FRACBITS - 2); // same speed as elevateContinuous ceiling->origspeed = ceiling->speed; if (line->frontsector->ceilingheight >= sec->ceilingheight) // Move up { @@ -584,10 +323,8 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) } // Any delay? - ceiling->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS; - ceiling->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Initial delay - - ceiling->texture = (fixed_t)(line - lines); // hack: use texture to store sourceline number + ceiling->delay = line->args[5]; + ceiling->delaytimer = line->args[4]; // Initial delay break; default: @@ -595,7 +332,6 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) } - ceiling->tag = tag; ceiling->type = type; firstone = 0; } @@ -604,22 +340,21 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) /** Starts a ceiling crusher. * + * \param tag Tag. * \param line The source line. * \param type The type of ceiling, either ::crushAndRaise or * ::fastCrushAndRaise. * \return 1 if at least one crusher was started, 0 otherwise. * \sa EV_DoCeiling, EV_DoFloor, EV_DoElevator, T_CrushCeiling */ -INT32 EV_DoCrush(line_t *line, ceiling_e type) +INT32 EV_DoCrush(mtag_t tag, line_t *line, ceiling_e type) { INT32 rtn = 0; INT32 secnum = -1; sector_t *sec; ceiling_t *ceiling; - mtag_t tag = Tag_FGet(&line->tags); - TAG_ITER_DECLARECOUNTER(0); - TAG_ITER_SECTORS(0, tag, secnum) + TAG_ITER_SECTORS(tag, secnum) { sec = §ors[secnum]; @@ -635,46 +370,33 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type) ceiling->sector = sec; ceiling->crush = true; ceiling->sourceline = (INT32)(line-lines); - - if (line->flags & ML_EFFECT4) - ceiling->oldspeed = FixedDiv(abs(line->dx),4*FRACUNIT); - else - ceiling->oldspeed = (R_PointToDist2(line->v2->x, line->v2->y, line->v1->x, line->v1->y)/16); + ceiling->speed = ceiling->origspeed = line->args[2] << (FRACBITS - 2); switch(type) { - case fastCrushAndRaise: // Up and then down + case raiseAndCrush: // Up and then down ceiling->topheight = P_FindHighestCeilingSurrounding(sec); ceiling->direction = 1; - ceiling->speed = ceiling->oldspeed; + // Retain stupid behavior for backwards compatibility + if (!udmf && !(line->flags & ML_MIDSOLID)) + ceiling->speed /= 2; + else + ceiling->speed = line->args[3] << (FRACBITS - 2); ceiling->bottomheight = sec->floorheight + FRACUNIT; break; case crushBothOnce: ceiling->topheight = sec->ceilingheight; ceiling->bottomheight = sec->floorheight + (sec->ceilingheight-sec->floorheight)/2; ceiling->direction = -1; - - if (line->flags & ML_EFFECT4) - ceiling->speed = ceiling->oldspeed; - else - ceiling->speed = ceiling->oldspeed*2; - break; case crushCeilOnce: default: // Down and then up. ceiling->topheight = sec->ceilingheight; ceiling->direction = -1; - - if (line->flags & ML_EFFECT4) - ceiling->speed = ceiling->oldspeed; - else - ceiling->speed = ceiling->oldspeed*2; - ceiling->bottomheight = sec->floorheight + FRACUNIT; break; } - ceiling->tag = tag; ceiling->type = type; } return rtn; diff --git a/src/p_enemy.c b/src/p_enemy.c index 203e04af1..75590faaa 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -12,6 +12,7 @@ /// \brief Enemy thinking, AI /// Action Pointer Functions that are associated with states/frames +#include "dehacked.h" #include "doomdef.h" #include "g_game.h" #include "p_local.h" @@ -25,6 +26,7 @@ #include "i_video.h" #include "z_zone.h" #include "lua_hook.h" +#include "m_cond.h" // SECRET_SKIN #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -106,6 +108,8 @@ void A_GoldMonitorRestore(mobj_t *actor); void A_GoldMonitorSparkle(mobj_t *actor); void A_Explode(mobj_t *actor); void A_BossDeath(mobj_t *actor); +void A_SetShadowScale(mobj_t *actor); +void A_ShadowScream(mobj_t *actor); void A_CustomPower(mobj_t *actor); void A_GiveWeapon(mobj_t *actor); void A_RingBox(mobj_t *actor); @@ -171,6 +175,7 @@ void A_Boss3TakeDamage(mobj_t *actor); void A_Boss3Path(mobj_t *actor); void A_Boss3ShockThink(mobj_t *actor); void A_LinedefExecute(mobj_t *actor); +void A_LinedefExecuteFromArg(mobj_t *actor); void A_PlaySeeSound(mobj_t *actor); void A_PlayAttackSound(mobj_t *actor); void A_PlayActiveSound(mobj_t *actor); @@ -199,6 +204,8 @@ void A_SetObjectFlags(mobj_t *actor); void A_SetObjectFlags2(mobj_t *actor); void A_RandomState(mobj_t *actor); void A_RandomStateRange(mobj_t *actor); +void A_StateRangeByAngle(mobj_t *actor); +void A_StateRangeByParameter(mobj_t *actor); void A_DualAction(mobj_t *actor); void A_RemoteAction(mobj_t *actor); void A_ToggleFlameJet(mobj_t *actor); @@ -743,8 +750,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 @@ -1708,7 +1715,7 @@ void A_HoodThink(mobj_t *actor) dx = (actor->target->x - actor->x), dy = (actor->target->y - actor->y), dz = (actor->target->z - actor->z); dm = P_AproxDistance(dx, dy); // Target dangerously close to robohood, retreat then. - if ((dm < 256<flags2 & MF2_AMBUSH)) { S_StartSound(actor, actor->info->attacksound); P_SetMobjState(actor, actor->info->raisestate); @@ -1834,7 +1841,7 @@ void A_SnailerThink(mobj_t *actor) fixed_t dist; fixed_t dx, dy; - dist = R_PointToDist2(0, 0, actor->x - actor->target->x, actor->y - actor->target->y); + dist = P_AproxDistance(actor->x - actor->target->x, actor->y - actor->target->y); if (an > ANGLE_45 && an <= ANGLE_90) // fire at 45 degrees to the left { @@ -2654,7 +2661,7 @@ void A_LobShot(mobj_t *actor) { INT32 locvar1 = var1; INT32 locvar2 = var2 >> 16; - mobj_t *shot, *hitspot; + mobj_t *shot; angle_t an; fixed_t z; fixed_t dist; @@ -2693,11 +2700,6 @@ void A_LobShot(mobj_t *actor) P_SetScale(shot, actor->scale); } - // Keep track of where it's going to land - hitspot = P_SpawnMobj(actor->target->x&(64*FRACUNIT-1), actor->target->y&(64*FRACUNIT-1), actor->target->subsector->sector->floorheight, MT_NULL); - hitspot->tics = airtime; - P_SetTarget(&shot->tracer, hitspot); - P_SetTarget(&shot->target, actor); // where it came from shot->angle = an = actor->angle; @@ -3333,20 +3335,18 @@ void A_SkullAttack(mobj_t *actor) actor->angle += (P_RandomChance(FRACUNIT/2)) ? ANGLE_90 : -ANGLE_90; else if (locvar1 == 3) { - statenum_t oldspawnstate = mobjinfo[MT_NULL].spawnstate; - UINT32 oldflags = mobjinfo[MT_NULL].flags; - fixed_t oldradius = mobjinfo[MT_NULL].radius; - fixed_t oldheight = mobjinfo[MT_NULL].height; - mobj_t *check; + statenum_t oldspawnstate = mobjinfo[MT_RAY].spawnstate; + UINT32 oldflags = mobjinfo[MT_RAY].flags; + fixed_t oldradius = mobjinfo[MT_RAY].radius; + fixed_t oldheight = mobjinfo[MT_RAY].height; INT32 i, j; static INT32 k;/* static for (at least) GCC 9.1 weirdness */ - boolean allow; angle_t testang = 0; - mobjinfo[MT_NULL].spawnstate = S_INVISIBLE; - mobjinfo[MT_NULL].flags = MF_NOGRAVITY|MF_NOTHINK|MF_NOCLIPTHING|MF_NOBLOCKMAP; - mobjinfo[MT_NULL].radius = mobjinfo[actor->type].radius; - mobjinfo[MT_NULL].height = mobjinfo[actor->type].height; + mobjinfo[MT_RAY].spawnstate = S_INVISIBLE; + mobjinfo[MT_RAY].flags = MF_NOGRAVITY|MF_NOTHINK|MF_NOCLIPTHING|MF_NOBLOCKMAP; + mobjinfo[MT_RAY].radius = mobjinfo[actor->type].radius; + mobjinfo[MT_RAY].height = mobjinfo[actor->type].height; if (P_RandomChance(FRACUNIT/2)) // port priority 1? { @@ -3359,15 +3359,12 @@ void A_SkullAttack(mobj_t *actor) j = 9; } -#define dostuff(q) check = P_SpawnMobjFromMobj(actor, 0, 0, 0, MT_NULL);\ +#define dostuff(q) \ testang = actor->angle + ((i+(q))*ANG10);\ - allow = (P_TryMove(check,\ - P_ReturnThrustX(check, testang, dist + 2*actor->radius),\ - P_ReturnThrustY(check, testang, dist + 2*actor->radius),\ - true));\ - P_RemoveMobj(check);\ - if (allow)\ - break; + if (P_CheckMove(actor,\ + P_ReturnThrustX(actor, testang, dist + 2*actor->radius),\ + P_ReturnThrustY(actor, testang, dist + 2*actor->radius),\ + true)) break; if (P_RandomChance(FRACUNIT/2)) // port priority 2? { @@ -3393,10 +3390,10 @@ void A_SkullAttack(mobj_t *actor) #undef dostuff - mobjinfo[MT_NULL].spawnstate = oldspawnstate; - mobjinfo[MT_NULL].flags = oldflags; - mobjinfo[MT_NULL].radius = oldradius; - mobjinfo[MT_NULL].height = oldheight; + mobjinfo[MT_RAY].spawnstate = oldspawnstate; + mobjinfo[MT_RAY].flags = oldflags; + mobjinfo[MT_RAY].radius = oldradius; + mobjinfo[MT_RAY].height = oldheight; } an = actor->angle >> ANGLETOFINESHIFT; @@ -3517,9 +3514,7 @@ void A_Scream(mobj_t *actor) if (LUA_CallAction(A_SCREAM, actor)) return; - if (actor->tracer && (actor->tracer->type == MT_SHELL || actor->tracer->type == MT_FIREBALL)) - S_StartScreamSound(actor, sfx_mario2); - else if (actor->info->deathsound) + if (actor->info->deathsound && !S_SoundPlaying(actor, sfx_mario2)) S_StartScreamSound(actor, actor->info->deathsound); } @@ -3590,7 +3585,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) @@ -3716,8 +3711,8 @@ void A_MonitorPop(mobj_t *actor) // Run a linedef executor immediately upon popping // You may want to delay your effects by 18 tics to sync with the reward giving - if (actor->spawnpoint && actor->lastlook) - P_LinedefExecute(actor->lastlook, actor->target, NULL); + if (actor->spawnpoint && actor->spawnpoint->args[0]) + P_LinedefExecute(actor->spawnpoint->args[0], actor->target, NULL); } // Function: A_GoldMonitorPop @@ -3802,8 +3797,8 @@ void A_GoldMonitorPop(mobj_t *actor) // Run a linedef executor immediately upon popping // You may want to delay your effects by 18 tics to sync with the reward giving - if (actor->spawnpoint && actor->lastlook) - P_LinedefExecute(actor->lastlook, actor->target, NULL); + if (actor->spawnpoint && actor->spawnpoint->args[0]) + P_LinedefExecute(actor->spawnpoint->args[0], actor->target, NULL); } // Function: A_GoldMonitorRestore @@ -3861,58 +3856,61 @@ void A_Explode(mobj_t *actor) P_RadiusAttack(actor, actor->target, actor->info->damage, locvar1, true); } -// Function: A_BossDeath -// -// Description: Possibly trigger special effects when boss dies. -// -// var1 = unused -// var2 = unused -// -void A_BossDeath(mobj_t *mo) +static mobj_t *P_FindBossFlyPoint(mobj_t *mo, INT32 tag) +{ + INT32 i; + mobj_t *closest = NULL; + + TAG_ITER_THINGS(tag, i) + { + mobj_t *mo2 = mapthings[i].mobj; + + if (!mo2) + continue; + + if (mo2->type != MT_BOSSFLYPOINT) + continue; + + // If this one's further than the last one, don't go for it. + if (closest && + P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) > + P_AproxDistance(P_AproxDistance(mo->x - closest->x, mo->y - closest->y), mo->z - closest->z)) + continue; + + closest = mo2; + } + + return closest; +} + +static void P_DoBossVictory(mobj_t *mo) { thinker_t *th; mobj_t *mo2; - line_t junk; INT32 i; - if (LUA_CallAction(A_BOSSDEATH, mo)) - return; - - if (mo->spawnpoint && mo->spawnpoint->extrainfo) - P_LinedefExecute(LE_BOSSDEAD+(mo->spawnpoint->extrainfo*LE_PARAMWIDTH), mo, NULL); - else - P_LinedefExecute(LE_BOSSDEAD, mo, NULL); - mo->health = 0; - - // Boss is dead (but not necessarily fleeing...) - // Lua may use this to ignore bosses after they start fleeing - mo->flags2 |= MF2_BOSSDEAD; - - // make sure there is a player alive for victory - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && ((players[i].mo && players[i].mo->health) - || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) - break; - - if (i == MAXPLAYERS) - return; // no one left alive, so do not end game - - // scan the remaining thinkers to see - // if all bosses are dead + // scan the remaining thinkers to see if all bosses are dead for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; mo2 = (mobj_t *)th; - if (mo2 != mo && (mo2->flags & MF_BOSS) && mo2->health > 0) - goto bossjustdie; // other boss not dead - just go straight to dying! + + if (mo2 == mo) + continue; + + if ((mo2->flags & MF_BOSS) && mo2->health > 0) + return; } // victory! - P_LinedefExecute(LE_ALLBOSSESDEAD, mo, NULL); + if (mo->spawnpoint) + P_LinedefExecute(mo->spawnpoint->args[3], mo, NULL); + if (stoppedclock && modeattacking) // if you're just time attacking, skip making the capsule appear since you don't need to step on it anyways. - goto bossjustdie; + return; + if (mo->flags2 & MF2_BOSSNOTRAP) { for (i = 0; i < MAXPLAYERS; i++) @@ -3924,18 +3922,14 @@ void A_BossDeath(mobj_t *mo) } else { - // Initialize my junk - junk.tags.tags = NULL; - junk.tags.count = 0; - - // Bring the egg trap up to the surface - // Incredibly shitty code ahead - Tag_FSet(&junk.tags, LE_CAPSULE0); - EV_DoElevator(&junk, elevateHighest, false); - Tag_FSet(&junk.tags, LE_CAPSULE1); - EV_DoElevator(&junk, elevateUp, false); - Tag_FSet(&junk.tags, LE_CAPSULE2); - EV_DoElevator(&junk, elevateHighest, false); + if (!udmf) + { + // Bring the egg trap up to the surface + // Incredibly shitty code ahead + EV_DoElevator(LE_CAPSULE0, NULL, elevateHighest); + EV_DoElevator(LE_CAPSULE1, NULL, elevateUp); + EV_DoElevator(LE_CAPSULE2, NULL, elevateHighest); + } if (mapheaderinfo[gamemap-1]->muspostbossname[0] && S_MusicExists(mapheaderinfo[gamemap-1]->muspostbossname, !midi_disabled, !digital_disabled)) @@ -3959,9 +3953,197 @@ void A_BossDeath(mobj_t *mo) mapheaderinfo[gamemap-1]->muspostbossfadein); } } +} -bossjustdie: - if (LUAh_BossDeath(mo)) +static void P_SpawnBoss1Junk(mobj_t *mo) +{ + mobj_t *mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSEGLZ1); + + mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSEGLZ2); +} + +static void P_SpawnBoss2Junk(mobj_t *mo) +{ + mobj_t *mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSTANK1); + + mo2 = P_SpawnMobjFromMobj(mo, + P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; + P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + P_SetMobjState(mo2, S_BOSSTANK2); + + mo2 = P_SpawnMobjFromMobj(mo, 0, 0, + mobjinfo[MT_EGGMOBILE2].height + (32<angle = mo->angle; + P_SetObjectMomZ(mo2, 4*FRACUNIT, false); + mo2->momz += mo->momz; + P_SetMobjState(mo2, S_BOSSSPIGOT); +} + +static void P_SpawnBoss3Junk(mobj_t *mo) +{ + mobj_t *mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK); + mo2->angle = mo->angle; + P_SetMobjState(mo2, S_BOSSSEBH1); +} + +static void P_DoCybrakdemonDeath(mobj_t *mo) +{ + mo->flags |= MF_NOCLIP; + mo->flags &= ~(MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT); + + S_StartSound(NULL, sfx_bedie2); + P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_CYBRAKDEMON_VILE_EXPLOSION); + mo->z += P_MobjFlip(mo); + P_SetObjectMomZ(mo, 12*FRACUNIT, false); + S_StartSound(mo, sfx_bgxpld); + if (mo->spawnpoint && !(mo->spawnpoint->args[6] & TMB_NODEATHFLING)) + P_InstaThrust(mo, R_PointToAngle2(0, 0, mo->x, mo->y), 14*FRACUNIT); +} + +static void P_DoBoss5Death(mobj_t *mo) +{ + if (mo->flags2 & MF2_SLIDEPUSH) + { + P_RemoveMobj(mo); + return; + } + if (mo->tracer) + { + var1 = var2 = 0; + A_Boss5Jump(mo); + mo->momx = ((16 - 1)*mo->momx)/16; + mo->momy = ((16 - 1)*mo->momy)/16; + { + const fixed_t time = FixedHypot(mo->tracer->x - mo->x, mo->tracer->y - mo->y)/FixedHypot(mo->momx, mo->momy); + const fixed_t speed = 64*FRACUNIT; + mobj_t *pole = P_SpawnMobj( + mo->tracer->x - P_ReturnThrustX(mo->tracer, mo->tracer->angle, speed*time), + mo->tracer->y - P_ReturnThrustY(mo->tracer, mo->tracer->angle, speed*time), + mo->tracer->floorz + (256+1)*FRACUNIT, + MT_FSGNB); + P_SetTarget(&pole->tracer, P_SpawnMobj( + pole->x, pole->y, + pole->z - 256*FRACUNIT, + MT_FSGNB)); + P_SetTarget(&pole->tracer->tracer, P_SpawnMobj( + pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT), + pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT), + pole->z + 256*FRACUNIT, + MT_FSGNA)); + pole->tracer->flags |= MF_NOCLIPTHING; + P_SetScale(pole, (pole->destscale = 2*FRACUNIT)); + P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT)); + pole->angle = pole->tracer->angle = mo->tracer->angle; + pole->tracer->tracer->angle = pole->angle - ANGLE_90; + pole->momx = P_ReturnThrustX(pole, pole->angle, speed); + pole->momy = P_ReturnThrustY(pole, pole->angle, speed); + pole->tracer->momx = pole->momx; + pole->tracer->momy = pole->momy; + pole->tracer->tracer->momx = pole->momx; + pole->tracer->tracer->momy = pole->momy; + } + } + else + { + P_SetObjectMomZ(mo, 10*FRACUNIT, false); + mo->flags |= MF_NOGRAVITY; + } + mo->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; +} + +static void P_DoBossDefaultDeath(mobj_t *mo) +{ + INT32 bossid = (mo->spawnpoint ? mo->spawnpoint->args[0] : 0); + + // Stop exploding and prepare to run. + P_SetMobjState(mo, mo->info->xdeathstate); + if (P_MobjWasRemoved(mo)) + return; + + P_SetTarget(&mo->target, P_FindBossFlyPoint(mo, bossid)); + + mo->flags |= MF_NOGRAVITY|MF_NOCLIP; + mo->flags |= MF_NOCLIPHEIGHT; + + mo->movedir = 0; + mo->extravalue1 = 35; + mo->flags2 |= MF2_BOSSFLEE; + mo->momz = P_MobjFlip(mo)*2*mo->scale; + + if (mo->target) + { + angle_t diff = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y) - mo->angle; + if (diff) + { + if (diff > ANGLE_180) + diff = InvAngle(InvAngle(diff)/mo->extravalue1); + else + diff /= mo->extravalue1; + mo->movedir = diff; + } + } +} + +// Function: A_BossDeath +// +// Description: Possibly trigger special effects when boss dies. +// +// var1 = unused +// var2 = unused +// +void A_BossDeath(mobj_t *mo) +{ + INT32 i; + + if (LUA_CallAction(A_BOSSDEATH, mo)) + return; + + if (mo->spawnpoint) + P_LinedefExecute(mo->spawnpoint->args[2], mo, NULL); + mo->health = 0; + + // Boss is dead (but not necessarily fleeing...) + // Lua may use this to ignore bosses after they start fleeing + mo->flags2 |= MF2_BOSSDEAD; + + // make sure there is a player alive for victory + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && ((players[i].mo && players[i].mo->health) + || ((netgame || multiplayer) && (players[i].lives || players[i].continues)))) + break; + + if (i == MAXPLAYERS) + return; // no one left alive, so do not end game + + P_DoBossVictory(mo); + + if (LUA_HookMobj(mo, MOBJ_HOOK(BossDeath))) return; else if (P_MobjWasRemoved(mo)) return; @@ -3972,61 +4154,13 @@ bossjustdie: default: break; case MT_EGGMOBILE: // twin laser pods - { - mo2 = P_SpawnMobjFromMobj(mo, - P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSEGLZ1); - - mo2 = P_SpawnMobjFromMobj(mo, - P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSEGLZ2); - } + P_SpawnBoss1Junk(mo); break; case MT_EGGMOBILE2: // twin tanks + spigot - { - mo2 = P_SpawnMobjFromMobj(mo, - P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSTANK1); - - mo2 = P_SpawnMobjFromMobj(mo, - P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; - P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - P_SetMobjState(mo2, S_BOSSTANK2); - - mo2 = P_SpawnMobjFromMobj(mo, 0, 0, - mobjinfo[MT_EGGMOBILE2].height + (32<angle = mo->angle; - P_SetObjectMomZ(mo2, 4*FRACUNIT, false); - mo2->momz += mo->momz; - P_SetMobjState(mo2, S_BOSSSPIGOT); - } + P_SpawnBoss2Junk(mo); break; case MT_EGGMOBILE3: - { - mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK); - mo2->angle = mo->angle; - P_SetMobjState(mo2, S_BOSSSEBH1); - } + P_SpawnBoss3Junk(mo); break; } @@ -4034,150 +4168,58 @@ bossjustdie: switch (mo->type) { case MT_BLACKEGGMAN: - { mo->flags |= MF_NOCLIP; mo->flags &= ~MF_SPECIAL; S_StartSound(NULL, sfx_befall); break; - } case MT_CYBRAKDEMON: - { - mo->flags |= MF_NOCLIP; - mo->flags &= ~(MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT); - - S_StartSound(NULL, sfx_bedie2); - P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_CYBRAKDEMON_VILE_EXPLOSION); - mo->z += P_MobjFlip(mo); - P_SetObjectMomZ(mo, 12*FRACUNIT, false); - S_StartSound(mo, sfx_bgxpld); - if (mo->spawnpoint && !(mo->spawnpoint->options & MTF_EXTRA)) - P_InstaThrust(mo, R_PointToAngle2(0, 0, mo->x, mo->y), 14*FRACUNIT); + P_DoCybrakdemonDeath(mo); break; - } - case MT_KOOPA: - { - // Initialize my junk - junk.tags.tags = NULL; - junk.tags.count = 0; - - Tag_FSet(&junk.tags, LE_KOOPA); - EV_DoCeiling(&junk, raiseToHighest); - return; - } case MT_FANG: - { - if (mo->flags2 & MF2_SLIDEPUSH) - { - P_RemoveMobj(mo); - return; - } - if (mo->tracer) - { - var1 = var2 = 0; - A_Boss5Jump(mo); - mo->momx = ((16 - 1)*mo->momx)/16; - mo->momy = ((16 - 1)*mo->momy)/16; - { - const fixed_t time = FixedHypot(mo->tracer->x - mo->x, mo->tracer->y - mo->y)/FixedHypot(mo->momx, mo->momy); - const fixed_t speed = 64*FRACUNIT; - mobj_t *pole = P_SpawnMobj( - mo->tracer->x - P_ReturnThrustX(mo->tracer, mo->tracer->angle, speed*time), - mo->tracer->y - P_ReturnThrustY(mo->tracer, mo->tracer->angle, speed*time), - mo->tracer->floorz + (256+1)*FRACUNIT, - MT_FSGNB); - P_SetTarget(&pole->tracer, P_SpawnMobj( - pole->x, pole->y, - pole->z - 256*FRACUNIT, - MT_FSGNB)); - P_SetTarget(&pole->tracer->tracer, P_SpawnMobj( - pole->x + P_ReturnThrustX(pole, mo->tracer->angle, FRACUNIT), - pole->y + P_ReturnThrustY(pole, mo->tracer->angle, FRACUNIT), - pole->z + 256*FRACUNIT, - MT_FSGNA)); - pole->tracer->flags |= MF_NOCLIPTHING; - P_SetScale(pole, (pole->destscale = 2*FRACUNIT)); - P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT)); - pole->angle = pole->tracer->angle = mo->tracer->angle; - pole->tracer->tracer->angle = pole->angle - ANGLE_90; - pole->momx = P_ReturnThrustX(pole, pole->angle, speed); - pole->momy = P_ReturnThrustY(pole, pole->angle, speed); - pole->tracer->momx = pole->momx; - pole->tracer->momy = pole->momy; - pole->tracer->tracer->momx = pole->momx; - pole->tracer->tracer->momy = pole->momy; - } - } - else - { - P_SetObjectMomZ(mo, 10*FRACUNIT, false); - mo->flags |= MF_NOGRAVITY; - } - mo->flags |= MF_NOCLIP|MF_NOCLIPHEIGHT; - return; - } - default: //eggmobiles - { - UINT8 extrainfo = (mo->spawnpoint ? mo->spawnpoint->extrainfo : 0); - - // Stop exploding and prepare to run. - P_SetMobjState(mo, mo->info->xdeathstate); - if (P_MobjWasRemoved(mo)) - return; - - P_SetTarget(&mo->target, NULL); - - // Flee! Flee! Find a point to escape to! If none, just shoot upward! - // scan the thinkers to find the runaway point - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t *)th; - - if (mo2->type != MT_BOSSFLYPOINT) - continue; - - if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo) - continue; - - // If this one's further then the last one, don't go for it. - if (mo->target && - P_AproxDistance(P_AproxDistance(mo->x - mo2->x, mo->y - mo2->y), mo->z - mo2->z) > - P_AproxDistance(P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y), mo->z - mo->target->z)) - continue; - - // Otherwise... Do! - P_SetTarget(&mo->target, mo2); - } - - mo->flags |= MF_NOGRAVITY|MF_NOCLIP; - mo->flags |= MF_NOCLIPHEIGHT; - - mo->movedir = 0; - mo->extravalue1 = 35; - mo->flags2 |= MF2_BOSSFLEE; - mo->momz = P_MobjFlip(mo)*2*mo->scale; - - if (mo->target) - { - angle_t diff = R_PointToAngle2(mo->x, mo->y, mo->target->x, mo->target->y) - mo->angle; - if (diff) - { - if (diff > ANGLE_180) - diff = InvAngle(InvAngle(diff)/mo->extravalue1); - else - diff /= mo->extravalue1; - mo->movedir = diff; - } - } - + P_DoBoss5Death(mo); + break; + default: //eggmobiles + P_DoBossDefaultDeath(mo); break; - } } } +// Function: A_SetShadowScale +// +// Description: Sets the target's shadowscale. +// +// var1 = new fixed_t shadowscale (default = FRACUNIT) +// var2 = unused +// +void A_SetShadowScale(mobj_t *actor) +{ + INT32 locvar1 = var1; + + if (LUA_CallAction(A_SETSHADOWSCALE, actor)) + return; + + actor->shadowscale = locvar1; +} + + +// Function: A_ShadowScream +// +// Description: Sets the target's shadowscale and starts the death sound of the object. +// +// var1 = new fixed_t shadowscale (default = FRACUNIT) +// var2 = unused +// +void A_ShadowScream(mobj_t *actor) +{ + if (LUA_CallAction(A_SHADOWSCREAM, actor)) + return; + + A_SetShadowScale(actor); + A_Scream(actor); +} + + // Function: A_CustomPower // // Description: Provides a custom powerup. Target (must be a player) is awarded the powerup. Reactiontime of the object is used as an index to the powers array. @@ -4190,7 +4232,6 @@ void A_CustomPower(mobj_t *actor) player_t *player; INT32 locvar1 = var1; INT32 locvar2 = var2; - boolean spawnshield = false; if (LUA_CallAction(A_CUSTOMPOWER, actor)) return; @@ -4201,7 +4242,7 @@ void A_CustomPower(mobj_t *actor) return; } - if (locvar1 >= NUMPOWERS) + if (locvar1 >= NUMPOWERS || locvar1 < 0) { CONS_Debug(DBG_GAMELOGIC, "Power #%d out of range!\n", locvar1); return; @@ -4209,15 +4250,10 @@ void A_CustomPower(mobj_t *actor) player = actor->target->player; - if (locvar1 == pw_shield && player->powers[pw_shield] != locvar2) - spawnshield = true; + P_SetPower(player, locvar1, locvar2); - player->powers[locvar1] = (UINT16)locvar2; if (actor->info->seesound) S_StartSound(player->mo, actor->info->seesound); - - if (spawnshield) //workaround for a bug - P_SpawnShieldOrb(player); } // Function: A_GiveWeapon @@ -4814,12 +4850,16 @@ void A_FishJump(mobj_t *actor) fixed_t jumpval; if (locvar1) - jumpval = var1; + jumpval = locvar1; else - jumpval = FixedMul(AngleFixed(actor->angle)/4, actor->scale); + { + if (actor->spawnpoint && actor->spawnpoint->args[0]) + jumpval = actor->spawnpoint->args[0]; + else + jumpval = 44; + } - if (!jumpval) jumpval = FixedMul(44*(FRACUNIT/4), actor->scale); - actor->momz = jumpval; + actor->momz = FixedMul(jumpval << (FRACBITS - 2), actor->scale); P_SetMobjStateNF(actor, actor->info->seestate); } @@ -4912,7 +4952,7 @@ void A_ThrownRing(mobj_t *actor) } if (actor->tracer && (actor->tracer->health) - && (actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow. + && (actor->tracer->player && actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC))// Already found someone to follow. { const INT32 temp = actor->threshold; actor->threshold = 32000; @@ -5101,6 +5141,33 @@ void A_SignSpin(mobj_t *actor) } } +static boolean SignSkinCheck(player_t *player, INT32 num) +{ + INT32 i; + + if (player != NULL) + { + // Use player's availabilities + return R_SkinUsable(player - players, num); + } + + // Player invalid, only show characters that are unlocked from the start. + for (i = 0; i < MAXUNLOCKABLES; i++) + { + if (unlockables[i].type == SECRET_SKIN) + { + INT32 lockedSkin = M_UnlockableSkinNum(&unlockables[i]); + + if (lockedSkin == num) + { + return false; + } + } + } + + return true; +} + // Function: A_SignPlayer // // Description: Changes the state of a level end sign to reflect the player that hit it. @@ -5161,23 +5228,21 @@ void A_SignPlayer(mobj_t *actor) // I turned this function into a fucking mess. I'm so sorry. -Lach if (locvar1 == -2) // random skin { -#define skincheck(num) (player ? !R_SkinUsable(player-players, num) : skins[num].availability > 0) player_t *player = actor->target ? actor->target->player : NULL; UINT8 skinnum; UINT8 skincount = 0; for (skinnum = 0; skinnum < numskins; skinnum++) - if (!skincheck(skinnum)) + if (SignSkinCheck(player, skinnum)) skincount++; skinnum = P_RandomKey(skincount); for (skincount = 0; skincount < numskins; skincount++) { if (skincount > skinnum) break; - if (skincheck(skincount)) + if (!SignSkinCheck(player, skincount)) skinnum++; } skin = &skins[skinnum]; -#undef skincheck } else // specific skin skin = &skins[locvar1]; @@ -5271,7 +5336,7 @@ void A_OverlayThink(mobj_t *actor) actor->z = actor->target->z + actor->target->height - mobjinfo[actor->type].height - ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; else actor->z = actor->target->z + ((var2>>16) ? -1 : 1)*(var2&0xFFFF)*FRACUNIT; - actor->angle = actor->target->angle + actor->movedir; + actor->angle = (actor->target->player ? actor->target->player->drawangle : actor->target->angle) + actor->movedir; actor->eflags = actor->target->eflags; actor->momx = actor->target->momx; @@ -5920,13 +5985,18 @@ void A_DetonChase(mobj_t *actor) if (actor->reactiontime == -42) { - fixed_t xyspeed; + fixed_t xyspeed, speed; + + if (actor->target->player) + speed = actor->target->player->normalspeed; + else + speed = actor->target->info->speed; actor->reactiontime = -42; exact = actor->movedir>>ANGLETOFINESHIFT; - xyspeed = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINECOSINE(exact)); - actor->momz = FixedMul(FixedMul(actor->tracer->player->normalspeed,3*FRACUNIT/4), FINESINE(exact)); + xyspeed = FixedMul(FixedMul(speed,3*FRACUNIT/4), FINECOSINE(exact)); + actor->momz = FixedMul(FixedMul(speed,3*FRACUNIT/4), FINESINE(exact)); exact = actor->angle>>ANGLETOFINESHIFT; actor->momx = FixedMul(xyspeed, FINECOSINE(exact)); @@ -6166,48 +6236,34 @@ void A_RockSpawn(mobj_t *actor) { mobj_t *mo; mobjtype_t type; - INT32 i = Tag_FindLineSpecial(12, (INT16)actor->threshold); - line_t *line; fixed_t dist; - fixed_t randomoomph; if (LUA_CallAction(A_ROCKSPAWN, actor)) return; - if (i == -1) + if (!actor->spawnpoint) + return; + + type = actor->spawnpoint->stringargs[0] ? get_number(actor->spawnpoint->stringargs[0]) : MT_ROCKCRUMBLE1; + + if (type < MT_NULL || type >= NUMMOBJTYPES) { - CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: Unable to find parameter line 12 (tag %d)!\n", actor->threshold); + CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: Invalid mobj type %s!\n", actor->spawnpoint->stringargs[0]); return; } - line = &lines[i]; - - if (!(sides[line->sidenum[0]].textureoffset >> FRACBITS)) - { - CONS_Debug(DBG_GAMELOGIC, "A_RockSpawn: No X-offset detected! (tag %d)!\n", actor->threshold); - return; - } - - dist = P_AproxDistance(line->dx, line->dy)/16; - - if (dist < 1) - dist = 1; - - type = MT_ROCKCRUMBLE1 + (sides[line->sidenum[0]].rowoffset >> FRACBITS); - - if (line->flags & ML_NOCLIMB) - randomoomph = P_RandomByte() * (FRACUNIT/32); - else - randomoomph = 0; + dist = max(actor->spawnpoint->args[0] << (FRACBITS - 4), 1); + if (actor->spawnpoint->args[2]) + dist += actor->spawnpoint->args[2] ? P_RandomByte() * (FRACUNIT/32) : 0; // random oomph mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK); P_SetMobjState(mo, mobjinfo[type].spawnstate); - mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); + mo->angle = FixedAngle(actor->spawnpoint->angle << FRACBITS); - P_InstaThrust(mo, mo->angle, dist + randomoomph); - mo->momz = dist + randomoomph; + P_InstaThrust(mo, mo->angle, dist); + mo->momz = dist; - var1 = sides[line->sidenum[0]].textureoffset >> FRACBITS; + var1 = actor->spawnpoint->args[1]; A_SetTics(actor); } @@ -6513,7 +6569,7 @@ void A_OldRingExplode(mobj_t *actor) { { const angle_t fa = (i*FINEANGLES/16) & FINEMASK; - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); P_SetTarget(&mo->target, actor->target); // Transfer target so player gets the points mo->momx = FixedMul(FINECOSINE(fa),ns); @@ -6539,7 +6595,7 @@ void A_OldRingExplode(mobj_t *actor) { } } - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); P_SetTarget(&mo->target, actor->target); mo->momz = ns; @@ -6554,7 +6610,7 @@ void A_OldRingExplode(mobj_t *actor) { mo->color = skincolor_bluering; } - mo = P_SpawnMobj(actor->x, actor->y, actor->z, locvar1); + mo = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1); P_SetTarget(&mo->target, actor->target); mo->momz = -ns; @@ -7041,10 +7097,8 @@ void A_Boss1Chase(mobj_t *actor) } else { - if (actor->spawnpoint && actor->spawnpoint->extrainfo) - P_LinedefExecute(LE_PINCHPHASE+(actor->spawnpoint->extrainfo*LE_PARAMWIDTH), actor, NULL); - else - P_LinedefExecute(LE_PINCHPHASE, actor, NULL); + if (actor->spawnpoint) + P_LinedefExecute(actor->spawnpoint->args[4], actor, NULL); P_SetMobjState(actor, actor->info->raisestate); } @@ -7168,7 +7222,7 @@ void A_Boss2Chase(mobj_t *actor) } else { - // Only speed up if you have the 'Deaf' flag. + // Only speed up if you have the ambush flag. if (actor->flags2 & MF2_AMBUSH) speedvar = actor->health; else @@ -7521,7 +7575,7 @@ void A_Boss2PogoTarget(mobj_t *actor) } // Target hit, retreat! - if (actor->target->player->powers[pw_flashing] > TICRATE || actor->flags2 & MF2_FRET) + if ((actor->target->player && actor->target->player->powers[pw_flashing] > TICRATE) || actor->flags2 & MF2_FRET) { UINT8 prandom = P_RandomByte(); actor->z++; // unstick from the floor @@ -7532,7 +7586,7 @@ void A_Boss2PogoTarget(mobj_t *actor) // Try to land on top of the player. else if (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) < FixedMul(512*FRACUNIT, actor->scale)) { - fixed_t airtime, gravityadd, zoffs; + fixed_t airtime, gravityadd, zoffs, height; // check gravity in the sector (for later math) P_CheckGravity(actor, true); @@ -7554,7 +7608,13 @@ void A_Boss2PogoTarget(mobj_t *actor) // Remember, kids! // Reduced down Calculus lets you avoid bad 'logic math' loops! //airtime = FixedDiv(-actor->momz<<1, gravityadd)<<1; // going from 0 to 0 is much simpler - zoffs = (P_GetPlayerHeight(actor->target->player)>>1) + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height, + + if (actor->target->player) + height = P_GetPlayerHeight(actor->target->player) >> 1; + else + height = actor->target->height >> 1; + + zoffs = height + (actor->target->floorz - actor->floorz); // offset by the difference in floor height plus half the player height, airtime = FixedDiv((-actor->momz - FixedSqrt(FixedMul(actor->momz,actor->momz)+zoffs)), gravityadd)<<1; // to try and land on their head rather than on their feet actor->angle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); @@ -7875,12 +7935,21 @@ void A_GuardChase(mobj_t *actor) false) && speed > 0) // can't be the same check as previous so that P_TryMove gets to happen. { - if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_OBJECTSPECIAL)) - actor->angle += ANGLE_90; - else if (actor->spawnpoint && ((actor->spawnpoint->options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_EXTRA)) - actor->angle -= ANGLE_90; - else - actor->angle += ANGLE_180; + INT32 direction = actor->spawnpoint ? actor->spawnpoint->args[0] : TMGD_BACK; + + switch (direction) + { + case TMGD_BACK: + default: + actor->angle += ANGLE_180; + break; + case TMGD_RIGHT: + actor->angle -= ANGLE_90; + break; + case TMGD_LEFT: + actor->angle += ANGLE_90; + break; + } } if (actor->extravalue1 < actor->info->speed) @@ -8080,10 +8149,6 @@ void A_Boss3TakeDamage(mobj_t *actor) actor->movecount = var1; actor->movefactor = -512*FRACUNIT; - - /*if (actor->target && actor->target->spawnpoint) - actor->threshold = actor->target->spawnpoint->extrainfo;*/ - } // Function: A_Boss3Path @@ -8123,27 +8188,21 @@ void A_Boss3Path(mobj_t *actor) if (!(actor->flags2 & MF2_STRONGBOX)) { - thinker_t *th; mobj_t *mo2; + INT32 i; P_SetTarget(&actor->target, NULL); - // scan the thinkers - // to find a point that matches - // the number - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + // Find waypoint + TAG_ITER_THINGS(actor->cusval, i) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + mo2 = mapthings[i].mobj; - mo2 = (mobj_t *)th; + if (!mo2) + continue; if (mo2->type != MT_BOSS3WAYPOINT) continue; - if (!mo2->spawnpoint) - continue; - if (mo2->spawnpoint->angle != actor->threshold) - continue; - if (mo2->spawnpoint->extrainfo != actor->cusval) + if (mapthings[i].args[0] != actor->threshold) continue; P_SetTarget(&actor->target, mo2); @@ -8235,7 +8294,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; @@ -8246,9 +8305,11 @@ void A_Boss3ShockThink(mobj_t *actor) y0 = actor->y; x1 = snext->x; y1 = snext->y; - if (FixedHypot(x1 - x0, y1 - y0) > 2*actor->radius) + if (R_PointToDist2(0, 0, x1 - x0, y1 - y0) > 2*actor->radius) { - snew = P_SpawnMobj((x0 + x1) >> 1, (y0 + y1) >> 1, (actor->z + snext->z) >> 1, actor->type); + snew = P_SpawnMobj((x0 >> 1) + (x1 >> 1), + (y0 >> 1) + (y1 >> 1), + (actor->z >> 1) + (snext->z >> 1), actor->type); snew->momx = (actor->momx + snext->momx) >> 1; snew->momy = (actor->momy + snext->momy) >> 1; snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? @@ -8256,6 +8317,10 @@ void A_Boss3ShockThink(mobj_t *actor) P_SetTarget(&snew->target, actor->target); snew->fuse = actor->fuse; + P_SetScale(snew, actor->scale); + snew->destscale = actor->destscale; + snew->scalespeed = actor->scalespeed; + P_SetTarget(&actor->hnext, snew); P_SetTarget(&snew->hnext, snext); } @@ -8283,8 +8348,6 @@ void A_LinedefExecute(mobj_t *actor) if (locvar2) tagnum += locvar2*(AngleFixed(actor->angle)>>FRACBITS); - else if (actor->spawnpoint && actor->spawnpoint->extrainfo) - tagnum += (actor->spawnpoint->extrainfo*LE_PARAMWIDTH); CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecute: Running mobjtype %d's sector with tag %d\n", actor->type, tagnum); @@ -8292,6 +8355,38 @@ void A_LinedefExecute(mobj_t *actor) P_LinedefExecute((INT16)tagnum, actor, actor->subsector->sector); } +// Function: A_LinedefExecuteFromArg +// +// Description: Object's location is used to set the calling sector. The tag used is the spawnpoint mapthing's args[var1]. +// +// var1 = mapthing arg to take tag from +// var2 = unused +// +void A_LinedefExecuteFromArg(mobj_t *actor) +{ + INT32 tagnum; + INT32 locvar1 = var1; + + if (LUA_CallAction(A_LINEDEFEXECUTEFROMARG, actor)) + return; + + if (!actor->spawnpoint) + return; + + if (locvar1 < 0 || locvar1 > NUMMAPTHINGARGS) + { + CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecuteFromArg: Invalid mapthing arg %d\n", locvar1); + return; + } + + tagnum = actor->spawnpoint->args[locvar1]; + + CONS_Debug(DBG_GAMELOGIC, "A_LinedefExecuteFromArg: Running mobjtype %d's sector with tag %d\n", actor->type, tagnum); + + // tag 32768 displayed in map editors is actually tag -32768, tag 32769 is -32767, 65535 is -1 etc. + P_LinedefExecute((INT16)tagnum, actor, actor->subsector->sector); +} + // Function: A_PlaySeeSound // // Description: Plays the object's seesound. @@ -9249,6 +9344,49 @@ void A_RandomStateRange(mobj_t *actor) P_SetMobjState(actor, P_RandomRange(locvar1, locvar2)); } +// Function: A_StateRangeByAngle +// +// Description: Chooses a state within the range supplied, depending on the actor's angle. +// +// var1 = Minimum state number to use. +// var2 = Maximum state number to use. The difference will act as a modulo operator. +// +void A_StateRangeByAngle(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + if (LUA_CallAction(A_STATERANGEBYANGLE, actor)) + return; + + if (locvar2 - locvar1 < 0) + return; // invalid range + + P_SetMobjState(actor, locvar1 + (AngleFixed(actor->angle)>>FRACBITS % (1 + locvar2 - locvar1))); +} + +// Function: A_StateRangeByParameter +// +// Description: Chooses a state within the range supplied, depending on the actor's parameter/extrainfo value. +// +// var1 = Minimum state number to use. +// var2 = Maximum state number to use. The difference will act as a modulo operator. +// +void A_StateRangeByParameter(mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + UINT8 parameter = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0); + + if (LUA_CallAction(A_STATERANGEBYPARAMETER, actor)) + return; + + if (locvar2 - locvar1 < 0) + return; // invalid range + + P_SetMobjState(actor, locvar1 + (parameter % (1 + locvar2 - locvar1))); +} + // Function: A_DualAction // // Description: Calls two actions. Be careful, if you reference the same state this action is called from, you can create an infinite loop. @@ -9862,28 +10000,29 @@ void A_Custom3DRotate(mobj_t *actor) const fixed_t radius = FixedMul(loc1lw*FRACUNIT, actor->scale); const fixed_t hOff = FixedMul(loc1up*FRACUNIT, actor->scale); - const fixed_t hspeed = FixedMul(loc2up*FRACUNIT/10, actor->scale); - const fixed_t vspeed = FixedMul(loc2lw*FRACUNIT/10, actor->scale); + const fixed_t hspeed = loc2up*FRACUNIT/10; // Monster's note (29/05/21): DO NOT SCALE, this is an angular speed! + const fixed_t vspeed = loc2lw*FRACUNIT/10; // ditto if (LUA_CallAction(A_CUSTOM3DROTATE, actor)) return; + if (!actor->target) // Ensure we actually have a target first. + { + CONS_Printf("Error: A_Custom3DRotate: Object has no target.\n"); + P_RemoveMobj(actor); + return; + } + if (actor->target->health == 0) { P_RemoveMobj(actor); return; } - if (!actor->target) // This should NEVER happen. - { - if (cv_debug) - CONS_Printf("Error: Object has no target\n"); - P_RemoveMobj(actor); - return; - } if (hspeed==0 && vspeed==0) { - CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n"); + if (cv_debug) + CONS_Printf("Error: A_Custom3DRotate: Object has no speed.\n"); return; } @@ -11388,10 +11527,7 @@ void A_BrakLobShot(mobj_t *actor) return; // Don't even bother if we've got nothing to aim at. // Look up actor's current gravity situation - if (actor->subsector->sector->gravity) - g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); - else - g = gravity; + g = FixedMul(gravity, P_GetSectorGravityFactor(actor->subsector->sector)); // Look up distance between actor and its target x = P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y); @@ -11503,10 +11639,7 @@ void A_NapalmScatter(mobj_t *actor) airtime = 16<subsector->sector->gravity) - g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); - else - g = gravity; + g = FixedMul(gravity, P_GetSectorGravityFactor(actor->subsector->sector)); // vy = (g*(airtime-1))/2 vy = FixedMul(g,(airtime-(1<>1; @@ -11629,7 +11762,7 @@ void A_FlickySpawn(mobj_t *actor) } // Internal Flicky color setting -void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo) +void P_InternalFlickySetColor(mobj_t *actor, UINT8 color) { UINT8 flickycolors[] = { SKINCOLOR_RED, @@ -11649,11 +11782,11 @@ void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo) SKINCOLOR_YELLOW, }; - if (extrainfo == 0) + if (color == 0) // until we can customize flicky colors by level header, just stick to SRB2's defaults actor->color = flickycolors[P_RandomKey(2)]; //flickycolors[P_RandomKey(sizeof(flickycolors))]; else - actor->color = flickycolors[min(extrainfo-1, 14)]; // sizeof(flickycolors)-1 + actor->color = flickycolors[min(color-1, 14)]; // sizeof(flickycolors)-1 } // Function: A_FlickyCenter @@ -11663,17 +11796,17 @@ void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo) // var1: // Lower 16 bits = if 0, spawns random flicky based on level header. Else, spawns the designated thing type. // Bits 17-20 = Flicky color, up to 15. Applies to fish. -// Bit 21 = Flag MF_SLIDEME (see below) -// Bit 22 = Flag MF_GRENADEBOUNCE (see below) -// Bit 23 = Flag MF_NOCLIPTHING (see below) +// Bit 21 = Flag TMFF_AIMLESS (see below) +// Bit 22 = Flag TMFF_STATIONARY (see below) +// Bit 23 = Flag TMFF_HOP (see below) // // If actor is placed from a spawnpoint (map Thing), the Thing's properties take precedence. // -// var2 = maximum default distance away from spawn the flickies are allowed to travel. If angle != 0, then that's the radius. +// var2 = maximum default distance away from spawn the flickies are allowed to travel. If args[0] != 0, then that's the radius. // -// If MTF_EXTRA (MF_SLIDEME): is flagged, Flickies move aimlessly. Else, orbit around the target. -// If MTF_OBJECTSPECIAL (MF_GRENADEBOUNCE): Flickies stand in-place without gravity (unless they hop, then gravity is applied.) -// If MTF_AMBUSH (MF_NOCLIPTHING): is flagged, Flickies hop. +// If TMFF_AIMLESS (MF_SLIDEME): is flagged, Flickies move aimlessly. Else, orbit around the target. +// If TMFF_STATIONARY (MF_GRENADEBOUNCE): Flickies stand in-place without gravity (unless they hop, then gravity is applied.) +// If TMFF_HOP (MF_NOCLIPTHING): is flagged, Flickies hop. // void A_FlickyCenter(mobj_t *actor) { @@ -11695,14 +11828,15 @@ void A_FlickyCenter(mobj_t *actor) if (actor->spawnpoint) { actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING); - actor->flags |= ( - ((actor->spawnpoint->options & MTF_EXTRA) ? MF_SLIDEME : 0) - | ((actor->spawnpoint->options & MTF_OBJECTSPECIAL) ? MF_GRENADEBOUNCE : 0) - | ((actor->spawnpoint->options & MTF_AMBUSH) ? MF_NOCLIPTHING : 0) - ); - actor->extravalue1 = actor->spawnpoint->angle ? abs(actor->spawnpoint->angle) * FRACUNIT - : locvar2 ? abs(locvar2) : 384 * FRACUNIT; - actor->extravalue2 = actor->spawnpoint->extrainfo; + if (actor->spawnpoint->args[1] & TMFF_AIMLESS) + actor->flags |= MF_SLIDEME; + if (actor->spawnpoint->args[1] & TMFF_STATIONARY) + actor->flags |= MF_GRENADEBOUNCE; + if (actor->spawnpoint->args[1] & TMFF_HOP) + actor->flags |= MF_NOCLIPTHING; + actor->extravalue1 = actor->spawnpoint->args[0] ? abs(actor->spawnpoint->args[0])*FRACUNIT + : locvar2 ? abs(locvar2) : 384*FRACUNIT; + actor->extravalue2 = actor->spawnpoint->args[2]; actor->friction = actor->spawnpoint->x*FRACUNIT; actor->movefactor = actor->spawnpoint->y*FRACUNIT; actor->watertop = actor->spawnpoint->z*FRACUNIT; @@ -11710,11 +11844,12 @@ void A_FlickyCenter(mobj_t *actor) else { actor->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE|MF_NOCLIPTHING); - actor->flags |= ( - ((flickyflags & 1) ? MF_SLIDEME : 0) - | ((flickyflags & 2) ? MF_GRENADEBOUNCE : 0) - | ((flickyflags & 4) ? MF_NOCLIPTHING : 0) - ); + if (flickyflags & TMFF_AIMLESS) + actor->flags |= MF_SLIDEME; + if (flickyflags & TMFF_STATIONARY) + actor->flags |= MF_GRENADEBOUNCE; + if (flickyflags & TMFF_HOP) + actor->flags |= MF_NOCLIPTHING; actor->extravalue1 = abs(locvar2); actor->extravalue2 = flickycolor; actor->friction = actor->x; @@ -12214,10 +12349,7 @@ void A_Boss5Jump(mobj_t *actor) return; // Don't even bother if we've got nothing to aim at. // Look up actor's current gravity situation - if (actor->subsector->sector->gravity) - g = FixedMul(gravity,(FixedDiv(*actor->subsector->sector->gravity>>FRACBITS, 1000))); - else - g = gravity; + g = FixedMul(gravity, P_GetSectorGravityFactor(actor->subsector->sector)); // Look up distance between actor and its tracer x = P_AproxDistance(actor->tracer->x - actor->x, actor->tracer->y - actor->y); @@ -12554,7 +12686,7 @@ void A_WhoCaresIfYourSonIsABee(mobj_t *actor) // Function: A_ParentTriesToSleep // -// Description: If extravalue1 is less than or equal to var1, go to var2. +// Description: If extravalue1 is greater than 0 go to var1 // // var1 = state to go to when extravalue1 // var2 = unused @@ -12639,67 +12771,43 @@ void A_Boss5FindWaypoint(mobj_t *actor) { INT32 locvar1 = var1; boolean avoidcenter; - UINT32 i; - UINT8 extrainfo = (actor->spawnpoint ? actor->spawnpoint->extrainfo : 0); + INT32 i; + INT32 bossid = (actor->spawnpoint ? actor->spawnpoint->args[0] : 0); if (LUA_CallAction(A_BOSS5FINDWAYPOINT, actor)) return; avoidcenter = !actor->tracer || (actor->health == actor->info->damage+1); - if (locvar1 == 2) // look for the boss waypoint + if (locvar1 == 2) // look for the boss flypoint { - thinker_t *th; - mobj_t *mo2; - P_SetTarget(&actor->tracer, NULL); - // Flee! Flee! Find a point to escape to! If none, just shoot upward! - // scan the thinkers to find the runaway point - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + P_SetTarget(&actor->tracer, P_FindBossFlyPoint(actor, bossid)); - mo2 = (mobj_t *)th; - - if (mo2->type != MT_BOSSFLYPOINT) - continue; - - if (mo2->spawnpoint && mo2->spawnpoint->extrainfo != extrainfo) - continue; - - // If this one's further then the last one, don't go for it. - if (actor->tracer && - P_AproxDistance(P_AproxDistance(actor->x - mo2->x, actor->y - mo2->y), actor->z - mo2->z) > - P_AproxDistance(P_AproxDistance(actor->x - actor->tracer->x, actor->y - actor->tracer->y), actor->z - actor->tracer->z)) - continue; - - // Otherwise... Do! - P_SetTarget(&actor->tracer, mo2); - } if (!actor->tracer) return; // no boss flypoints found } else if (locvar1 == 1) // always go to ambush-marked waypoint { + boolean found = false; + if (avoidcenter) goto nowaypoints; // if we can't go the center, why on earth are we doing this? - for (i = 0; i < nummapthings; i++) + TAG_ITER_THINGS(bossid, i) { if (!mapthings[i].mobj) continue; if (mapthings[i].mobj->type != MT_FANGWAYPOINT) continue; - if (mapthings[i].extrainfo != extrainfo) - continue; - if (!(mapthings[i].options & MTF_AMBUSH)) + if (!(mapthings[i].args[0])) continue; P_SetTarget(&actor->tracer, mapthings[i].mobj); + found = true; break; } - if (i == nummapthings) + if (!found) goto nowaypoints; } else // locvar1 == 0 @@ -12712,7 +12820,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) actor->z += hackoffset; // first, count how many waypoints we have - for (i = 0; i < nummapthings; i++) + TAG_ITER_THINGS(bossid, i) { if (!mapthings[i].mobj) continue; @@ -12720,9 +12828,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (actor->tracer == mapthings[i].mobj) // this was your tracer last time continue; - if (mapthings[i].extrainfo != extrainfo) - continue; - if (mapthings[i].options & MTF_AMBUSH) + if (mapthings[i].args[0]) { if (avoidcenter) continue; @@ -12769,7 +12875,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) numfangwaypoints = 0; // now find them again and add them to the table! - for (i = 0; i < nummapthings; i++) + TAG_ITER_THINGS(bossid, i) { if (!mapthings[i].mobj) continue; @@ -12777,9 +12883,7 @@ void A_Boss5FindWaypoint(mobj_t *actor) continue; if (actor->tracer == mapthings[i].mobj) // this was your tracer last time continue; - if (mapthings[i].extrainfo != extrainfo) - continue; - if (mapthings[i].options & MTF_AMBUSH) + if (mapthings[i].args[0]) { if (avoidcenter) continue; @@ -14216,7 +14320,7 @@ void A_SpawnPterabytes(mobj_t *actor) return; if (actor->spawnpoint) - amount = actor->spawnpoint->extrainfo + 1; + amount = min(1, actor->spawnpoint->args[0]); interval = FixedAngle(FRACUNIT*360/amount); @@ -14308,6 +14412,14 @@ void A_RolloutRock(mobj_t *actor) if (LUA_CallAction(A_ROLLOUTROCK, actor)) return; + if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health) + actor->flags |= MF_PUSHABLE; + else + { + actor->flags2 = (actor->flags2 & ~MF2_OBJECTFLIP) | (actor->tracer->flags2 & MF2_OBJECTFLIP); + actor->eflags = (actor->eflags & ~MFE_VERTICALFLIP) | (actor->tracer->eflags & MFE_VERTICALFLIP); + } + actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves if (actor->eflags & MFE_JUSTHITFLOOR) @@ -14346,7 +14458,8 @@ void A_RolloutRock(mobj_t *actor) speed = P_AproxDistance(actor->momx, actor->momy); // recalculate speed for visual rolling - if (speed < actor->scale >> 1) // stop moving if speed is insignificant + if (((actor->flags & MF_PUSHABLE) || !(actor->flags2 & MF2_STRONGBOX)) + && speed < actor->scale) // stop moving if speed is insignificant { actor->momx = 0; actor->momy = 0; @@ -14366,9 +14479,6 @@ void A_RolloutRock(mobj_t *actor) actor->frame = actor->reactiontime % maxframes; // set frame - if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health) - actor->flags |= MF_PUSHABLE; - if (!(actor->flags & MF_PUSHABLE) || (actor->movecount != 1)) // if being ridden or haven't moved, don't disappear actor->fuse = actor->info->painchance; else if (actor->fuse < 2*TICRATE) diff --git a/src/p_floor.c b/src/p_floor.c index 7c26065b5..b65435c21 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,6 +11,7 @@ /// \file p_floor.c /// \brief Floor animation, elevators +#include "dehacked.h" #include "doomdef.h" #include "doomstat.h" #include "m_random.h" @@ -162,7 +163,7 @@ result_e T_MovePlane(sector_t *sector, fixed_t speed, fixed_t dest, boolean crus void T_MoveFloor(floormove_t *movefloor) { result_e res = 0; - boolean dontupdate = false; + boolean remove = false; if (movefloor->delaytimer) { @@ -178,8 +179,8 @@ void T_MoveFloor(floormove_t *movefloor) if (movefloor->type == bounceFloor) { const fixed_t origspeed = FixedDiv(movefloor->origspeed,(ELEVATORSPEED/2)); - const fixed_t fs = abs(movefloor->sector->floorheight - lines[movefloor->texture].frontsector->floorheight); - const fixed_t bs = abs(movefloor->sector->floorheight - lines[movefloor->texture].backsector->floorheight); + const fixed_t fs = abs(movefloor->sector->floorheight - lines[movefloor->sourceline].frontsector->floorheight); + const fixed_t bs = abs(movefloor->sector->floorheight - lines[movefloor->sourceline].backsector->floorheight); if (fs < bs) movefloor->speed = FixedDiv(fs,25*FRACUNIT) + FRACUNIT/4; else @@ -190,113 +191,62 @@ void T_MoveFloor(floormove_t *movefloor) if (res == pastdest) { - if (movefloor->direction == 1) + switch (movefloor->type) { - switch (movefloor->type) - { - case moveFloorByFrontSector: - if (movefloor->texture < -1) // chained linedef executing - P_LinedefExecute((INT16)(movefloor->texture + INT16_MAX + 2), NULL, NULL); - /* FALLTHRU */ - case instantMoveFloorByFrontSector: - if (movefloor->texture > -1) // flat changing - movefloor->sector->floorpic = movefloor->texture; - break; - case bounceFloor: // Graue 03-12-2004 - if (movefloor->floordestheight == lines[movefloor->texture].frontsector->floorheight) - movefloor->floordestheight = lines[movefloor->texture].backsector->floorheight; - else - movefloor->floordestheight = lines[movefloor->texture].frontsector->floorheight; - movefloor->direction = (movefloor->floordestheight < movefloor->sector->floorheight) ? -1 : 1; - movefloor->sector->floorspeed = movefloor->speed * movefloor->direction; - movefloor->delaytimer = movefloor->delay; - P_RecalcPrecipInSector(movefloor->sector); - return; // not break, why did this work? Graue 04-03-2004 - case bounceFloorCrush: // Graue 03-27-2004 - if (movefloor->floordestheight == lines[movefloor->texture].frontsector->floorheight) - { - movefloor->floordestheight = lines[movefloor->texture].backsector->floorheight; - movefloor->speed = movefloor->origspeed = FixedDiv(abs(lines[movefloor->texture].dy),4*FRACUNIT); // return trip, use dy - } - else - { - movefloor->floordestheight = lines[movefloor->texture].frontsector->floorheight; - movefloor->speed = movefloor->origspeed = FixedDiv(abs(lines[movefloor->texture].dx),4*FRACUNIT); // forward again, use dx - } - movefloor->direction = (movefloor->floordestheight < movefloor->sector->floorheight) ? -1 : 1; - movefloor->sector->floorspeed = movefloor->speed * movefloor->direction; - movefloor->delaytimer = movefloor->delay; - P_RecalcPrecipInSector(movefloor->sector); - return; // not break, why did this work? Graue 04-03-2004 - case crushFloorOnce: - movefloor->floordestheight = lines[movefloor->texture].frontsector->floorheight; + case moveFloorByFrontSector: + if (movefloor->tag) // chained linedef executing + P_LinedefExecute(movefloor->tag, NULL, NULL); + /* FALLTHRU */ + case instantMoveFloorByFrontSector: + if (movefloor->texture > -1) // flat changing + movefloor->sector->floorpic = movefloor->texture; + remove = true; + break; + case bounceFloor: // Graue 03-12-2004 + case bounceFloorCrush: // Graue 03-27-2004 + if (movefloor->floordestheight == lines[movefloor->sourceline].frontsector->floorheight) + { + movefloor->floordestheight = lines[movefloor->sourceline].backsector->floorheight; + movefloor->origspeed = lines[movefloor->sourceline].args[3] << (FRACBITS - 2); // return trip, use args[3] + } + else + { + movefloor->floordestheight = lines[movefloor->sourceline].frontsector->floorheight; + movefloor->origspeed = lines[movefloor->sourceline].args[2] << (FRACBITS - 2); // forward again, use args[2] + } + if (movefloor->type == bounceFloorCrush) + movefloor->speed = movefloor->origspeed; + movefloor->direction = (movefloor->floordestheight < movefloor->sector->floorheight) ? -1 : 1; + movefloor->delaytimer = movefloor->delay; + remove = false; + break; + case crushFloorOnce: + if (movefloor->direction == 1) + { + movefloor->floordestheight = lines[movefloor->sourceline].frontsector->floorheight; movefloor->direction = -1; + movefloor->speed = lines[movefloor->sourceline].args[3] << (FRACBITS - 2); movefloor->sector->soundorg.z = movefloor->sector->floorheight; - S_StartSound(&movefloor->sector->soundorg,sfx_pstop); - P_RecalcPrecipInSector(movefloor->sector); - return; - default: - break; - } - } - else if (movefloor->direction == -1) - { - switch (movefloor->type) - { - case moveFloorByFrontSector: - if (movefloor->texture < -1) // chained linedef executing - P_LinedefExecute((INT16)(movefloor->texture + INT16_MAX + 2), NULL, NULL); - /* FALLTHRU */ - case instantMoveFloorByFrontSector: - if (movefloor->texture > -1) // flat changing - movefloor->sector->floorpic = movefloor->texture; - break; - case bounceFloor: // Graue 03-12-2004 - if (movefloor->floordestheight == lines[movefloor->texture].frontsector->floorheight) - movefloor->floordestheight = lines[movefloor->texture].backsector->floorheight; - else - movefloor->floordestheight = lines[movefloor->texture].frontsector->floorheight; - movefloor->direction = (movefloor->floordestheight < movefloor->sector->floorheight) ? -1 : 1; - movefloor->sector->floorspeed = movefloor->speed * movefloor->direction; - movefloor->delaytimer = movefloor->delay; - P_RecalcPrecipInSector(movefloor->sector); - return; // not break, why did this work? Graue 04-03-2004 - case bounceFloorCrush: // Graue 03-27-2004 - if (movefloor->floordestheight == lines[movefloor->texture].frontsector->floorheight) - { - movefloor->floordestheight = lines[movefloor->texture].backsector->floorheight; - movefloor->speed = movefloor->origspeed = FixedDiv(abs(lines[movefloor->texture].dy),4*FRACUNIT); // return trip, use dy - } - else - { - movefloor->floordestheight = lines[movefloor->texture].frontsector->floorheight; - movefloor->speed = movefloor->origspeed = FixedDiv(abs(lines[movefloor->texture].dx),4*FRACUNIT); // forward again, use dx - } - movefloor->direction = (movefloor->floordestheight < movefloor->sector->floorheight) ? -1 : 1; - movefloor->sector->floorspeed = movefloor->speed * movefloor->direction; - movefloor->delaytimer = movefloor->delay; - P_RecalcPrecipInSector(movefloor->sector); - return; // not break, why did this work? Graue 04-03-2004 - case crushFloorOnce: - movefloor->sector->floordata = NULL; // Clear up the thinker so others can use it - P_RemoveThinker(&movefloor->thinker); - movefloor->sector->floorspeed = 0; - P_RecalcPrecipInSector(movefloor->sector); - return; - default: - break; - } + S_StartSound(&movefloor->sector->soundorg, sfx_pstop); + remove = false; + } + else + remove = true; + break; + default: + remove = true; + break; } + } + if (remove) + { movefloor->sector->floordata = NULL; // Clear up the thinker so others can use it movefloor->sector->floorspeed = 0; P_RemoveThinker(&movefloor->thinker); - dontupdate = true; } - if (!dontupdate) - movefloor->sector->floorspeed = movefloor->speed*movefloor->direction; else - movefloor->sector->floorspeed = 0; + movefloor->sector->floorspeed = movefloor->speed*movefloor->direction; P_RecalcPrecipInSector(movefloor->sector); } @@ -634,8 +584,6 @@ void T_BounceCheese(bouncecheese_t *bouncer) sector_t *actionsector; boolean remove; INT32 i; - mtag_t tag = Tag_FGet(&bouncer->sourceline->tags); - TAG_ITER_DECLARECOUNTER(0); if (bouncer->sector->crumblestate == CRUMBLE_RESTORE || bouncer->sector->crumblestate == CRUMBLE_WAIT || bouncer->sector->crumblestate == CRUMBLE_ACTIVATED) // Oops! Crumbler says to remove yourself! @@ -650,7 +598,7 @@ void T_BounceCheese(bouncecheese_t *bouncer) } // You can use multiple target sectors, but at your own risk!!! - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(bouncer->sourceline->args[0], i) { actionsector = §ors[i]; actionsector->moved = true; @@ -774,8 +722,7 @@ void T_StartCrumble(crumble_t *crumble) ffloor_t *rover; sector_t *sector; INT32 i; - mtag_t tag = Tag_FGet(&crumble->sourceline->tags); - TAG_ITER_DECLARECOUNTER(0); + mtag_t tag = crumble->sourceline->args[0]; // Once done, the no-return thinker just sits there, // constantly 'returning'... kind of an oxymoron, isn't it? @@ -804,7 +751,7 @@ void T_StartCrumble(crumble_t *crumble) } else if (++crumble->timer == 0) // Reposition back to original spot { - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) { sector = §ors[i]; @@ -840,7 +787,7 @@ void T_StartCrumble(crumble_t *crumble) // Flash to indicate that the platform is about to return. if (crumble->timer > -224 && (leveltime % ((abs(crumble->timer)/8) + 1) == 0)) { - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) { sector = §ors[i]; @@ -932,7 +879,7 @@ void T_StartCrumble(crumble_t *crumble) P_RemoveThinker(&crumble->thinker); } - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) { sector = §ors[i]; sector->moved = true; @@ -948,7 +895,6 @@ void T_StartCrumble(crumble_t *crumble) void T_MarioBlock(mariothink_t *block) { INT32 i; - TAG_ITER_DECLARECOUNTER(0); T_MovePlane ( @@ -983,7 +929,7 @@ void T_MarioBlock(mariothink_t *block) block->sector->ceilspeed = 0; block->direction = 0; } - TAG_ITER_SECTORS(0, (INT16)block->tag, i) + TAG_ITER_SECTORS((INT16)block->tag, i) P_RecalcPrecipInSector(§ors[i]); } @@ -1045,6 +991,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node) case MT_THUNDERCOIN_ORB: case MT_IVSP: case MT_SUPERSPARK: + case MT_BOXSPARKLE: case MT_RAIN: case MT_SNOWFLAKE: case MT_SPLISH: @@ -1099,23 +1046,6 @@ void T_MarioBlockChecker(mariocheck_t *block) } } -static boolean P_IsPlayerValid(size_t playernum) -{ - if (!playeringame[playernum]) - return false; - - if (!players[playernum].mo) - return false; - - if (players[playernum].mo->health <= 0) - return false; - - if (players[playernum].spectator) - return false; - - return true; -} - // This is the Thwomp's 'brain'. It looks around for players nearby, and if // it finds any, **SMASH**!!! Muahahhaa.... void T_ThwompSector(thwomp_t *thwomp) @@ -1292,10 +1222,9 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) sector_t *sec = NULL; INT32 secnum = -1; boolean FOFsector = false; - mtag_t tag = Tag_FGet(&nobaddies->sourceline->tags); - TAG_ITER_DECLARECOUNTER(0); + mtag_t tag = nobaddies->sourceline->args[0]; - TAG_ITER_SECTORS(0, tag, secnum) + TAG_ITER_SECTORS(tag, secnum) { sec = §ors[secnum]; @@ -1305,15 +1234,13 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) for (i = 0; i < sec->linecount; i++) { INT32 targetsecnum = -1; - mtag_t tag2 = Tag_FGet(&sec->lines[i]->tags); - TAG_ITER_DECLARECOUNTER(1); if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300) continue; FOFsector = true; - TAG_ITER_SECTORS(1, tag2, targetsecnum) + TAG_ITER_SECTORS(sec->lines[i]->args[0], targetsecnum) { if (T_SectorHasEnemies(§ors[targetsecnum])) return; @@ -1331,219 +1258,68 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) P_RemoveThinker(&nobaddies->thinker); } -// -// P_IsObjectOnRealGround -// -// Helper function for T_EachTimeThinker -// Like P_IsObjectOnGroundIn, except ONLY THE REAL GROUND IS CONSIDERED, NOT FOFS -// I'll consider whether to make this a more globally accessible function or whatever in future -// -- Monster Iestyn -// -static boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec) +static boolean P_CheckAllTrigger(eachtime_t *eachtime) { - // Is the object in reverse gravity? - if (mo->eflags & MFE_VERTICALFLIP) + size_t i; + + for (i = 0; i < MAXPLAYERS; i++) { - // Detect if the player is on the ceiling. - if (mo->z+mo->height >= P_GetSpecialTopZ(mo, sec, sec)) - return true; + if (P_CanPlayerTrigger(i) && !eachtime->playersInArea[i]) + return false; } - // Nope! - else - { - // Detect if the player is on the floor. - if (mo->z <= P_GetSpecialBottomZ(mo, sec, sec)) - return true; - } - return false; + + return true; } -static boolean P_IsMobjTouchingSector(mobj_t *mo, sector_t *sec) -{ - msecnode_t *node; - - if (mo->subsector->sector == sec) - return true; - - if (!(sec->flags & SF_TRIGGERSPECIAL_TOUCH)) - return false; - - for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (node->m_sector == sec) - return true; - } - - return false; -} - -// -// T_EachTimeThinker -// -// Runs a linedef exec whenever a player enters an area. -// Keeps track of players currently in the area and notices any changes. -// -// \sa P_AddEachTimeThinker -// void T_EachTimeThinker(eachtime_t *eachtime) { - size_t i, j; - sector_t *sec = NULL; - sector_t *targetsec = NULL; - INT32 secnum = -1; + size_t i; boolean oldPlayersInArea[MAXPLAYERS]; - boolean oldPlayersOnArea[MAXPLAYERS]; - boolean *oldPlayersArea; - boolean *playersArea; - boolean FOFsector = false; - boolean floortouch = false; - fixed_t bottomheight, topheight; - ffloor_t *rover; - mtag_t tag = Tag_FGet(&eachtime->sourceline->tags); - TAG_ITER_DECLARECOUNTER(0); + sector_t *caller[MAXPLAYERS]; + boolean allPlayersChecked = false; + boolean allPlayersTrigger = false; for (i = 0; i < MAXPLAYERS; i++) { oldPlayersInArea[i] = eachtime->playersInArea[i]; - oldPlayersOnArea[i] = eachtime->playersOnArea[i]; - eachtime->playersInArea[i] = false; - eachtime->playersOnArea[i] = false; - } - - TAG_ITER_SECTORS(0, tag, secnum) - { - sec = §ors[secnum]; - - FOFsector = false; - - if (GETSECSPECIAL(sec->special, 2) == 3 || GETSECSPECIAL(sec->special, 2) == 5) - floortouch = true; - else if (GETSECSPECIAL(sec->special, 2) >= 1 && GETSECSPECIAL(sec->special, 2) <= 8) - floortouch = false; - else - continue; - - // Check the lines of this sector, to see if it is a FOF control sector. - for (i = 0; i < sec->linecount; i++) - { - INT32 targetsecnum = -1; - mtag_t tag2 = Tag_FGet(&sec->lines[i]->tags); - TAG_ITER_DECLARECOUNTER(1); - - if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300) - continue; - - FOFsector = true; - - TAG_ITER_SECTORS(1, tag2, targetsecnum) - { - targetsec = §ors[targetsecnum]; - - // Find the FOF corresponding to the control linedef - for (rover = targetsec->ffloors; rover; rover = rover->next) - { - if (rover->master == sec->lines[i]) - break; - } - - if (!rover) // This should be impossible, but don't complain if it is the case somehow - continue; - - if (!(rover->flags & FF_EXISTS)) // If the FOF does not "exist", we pretend that nobody's there - continue; - - for (j = 0; j < MAXPLAYERS; j++) - { - if (!P_IsPlayerValid(j)) - continue; - - if (!P_IsMobjTouchingSector(players[j].mo, targetsec)) - continue; - - topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec); - bottomheight = P_GetSpecialBottomZ(players[j].mo, sec, targetsec); - - if (players[j].mo->z > topheight) - continue; - - if (players[j].mo->z + players[j].mo->height < bottomheight) - continue; - - if (floortouch && P_IsObjectOnGroundIn(players[j].mo, targetsec)) - eachtime->playersOnArea[j] = true; - else - eachtime->playersInArea[j] = true; - } - } - } - - if (!FOFsector) - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!P_IsPlayerValid(i)) - continue; - - if (!P_IsMobjTouchingSector(players[i].mo, sec)) - continue; - - if (!(players[i].mo->subsector->sector == sec - || P_PlayerTouchingSectorSpecial(&players[i], 2, (GETSECSPECIAL(sec->special, 2))) == sec)) - continue; - - if (floortouch && P_IsObjectOnRealGround(players[i].mo, sec)) - eachtime->playersOnArea[i] = true; - else - eachtime->playersInArea[i] = true; - } - } - } - - // Check if a new player entered. - // If not, check if a player hit the floor. - // If either condition is true, execute. - if (floortouch) - { - playersArea = eachtime->playersOnArea; - oldPlayersArea = oldPlayersOnArea; - } - else - { - playersArea = eachtime->playersInArea; - oldPlayersArea = oldPlayersInArea; + caller[i] = P_CanPlayerTrigger(i) ? P_FindPlayerTrigger(&players[i], eachtime->sourceline) : NULL; + eachtime->playersInArea[i] = caller[i] != NULL; } // Easy check... nothing has changed - if (!memcmp(playersArea, oldPlayersArea, sizeof(boolean)*MAXPLAYERS)) + if (!memcmp(eachtime->playersInArea, oldPlayersInArea, sizeof(boolean)*MAXPLAYERS)) return; - // If sector has an "all players" trigger type, all players need to be in area - if (GETSECSPECIAL(sec->special, 2) == 2 || GETSECSPECIAL(sec->special, 2) == 3) - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (P_IsPlayerValid(i) && playersArea[i]) - continue; - } - } - // Trigger for every player who has entered (and exited, if triggerOnExit) for (i = 0; i < MAXPLAYERS; i++) { - if (playersArea[i] == oldPlayersArea[i]) + if (eachtime->playersInArea[i] == oldPlayersInArea[i]) continue; // If player has just left, check if still valid - if (!playersArea[i] && (!eachtime->triggerOnExit || !P_IsPlayerValid(i))) + if (!eachtime->playersInArea[i] && (!eachtime->triggerOnExit || !P_CanPlayerTrigger(i))) continue; - CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", tag); + // If sector has an "all players" trigger type, all players need to be in area + if (caller[i] && caller[i]->triggerer == TO_ALLPLAYERS) + { + if (!allPlayersChecked) + { + allPlayersChecked = true; + allPlayersTrigger = P_CheckAllTrigger(eachtime); + } + + if (!allPlayersTrigger) + continue; + } + + CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", Tag_FGet(&eachtime->sourceline->tags)); // 03/08/14 -Monster Iestyn // No more stupid hacks involving changing eachtime->sourceline's tag or special or whatever! // This should now run ONLY the stuff for eachtime->sourceline itself, instead of all trigger linedefs sharing the same tag. // Makes much more sense doing it this way, honestly. - P_RunTriggerLinedef(eachtime->sourceline, players[i].mo, sec); + P_RunTriggerLinedef(eachtime->sourceline, players[i].mo, caller[i]); if (!eachtime->sourceline->special) // this happens only for "Trigger on X calls" linedefs P_RemoveThinker(&eachtime->thinker); @@ -1570,12 +1346,11 @@ void T_RaiseSector(raise_t *raise) INT32 direction; result_e res = 0; mtag_t tag = raise->tag; - TAG_ITER_DECLARECOUNTER(0); if (raise->sector->crumblestate >= CRUMBLE_FALL || raise->sector->ceilingdata) return; - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) { sector = §ors[i]; @@ -1702,7 +1477,7 @@ void T_RaiseSector(raise_t *raise) raise->sector->ceilspeed = 42; raise->sector->floorspeed = speed*direction; - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) P_RecalcPrecipInSector(§ors[i]); } @@ -1813,16 +1588,14 @@ void T_PlaneDisplace(planedisplace_t *pd) // (egg capsule button), P_PlayerInSpecialSector (buttons), // and P_SpawnSpecials (continuous floor movers and instant lower). // -void EV_DoFloor(line_t *line, floor_e floortype) +void EV_DoFloor(mtag_t tag, line_t *line, floor_e floortype) { INT32 firstone = 1; INT32 secnum = -1; sector_t *sec; floormove_t *dofloor; - mtag_t tag = Tag_FGet(&line->tags); - TAG_ITER_DECLARECOUNTER(0); - TAG_ITER_SECTORS(0, tag, secnum) + TAG_ITER_SECTORS(tag, secnum) { sec = §ors[secnum]; @@ -1841,34 +1614,25 @@ void EV_DoFloor(line_t *line, floor_e floortype) dofloor->type = floortype; dofloor->crush = false; // default: types that crush will change this dofloor->sector = sec; + dofloor->sourceline = (INT32)(line - lines); switch (floortype) { - // Lowers a floor to the lowest surrounding floor. - case lowerFloorToLowest: - dofloor->direction = -1; // down - dofloor->speed = FLOORSPEED*2; // 2 fracunits per tic - dofloor->floordestheight = P_FindLowestFloorSurrounding(sec); - break; - - // Used for part of the Egg Capsule, when an FOF with type 666 is - // contacted by the player. + // Used to open the top of an Egg Capsule. case raiseFloorToNearestFast: dofloor->direction = -1; // down dofloor->speed = FLOORSPEED*4; // 4 fracunits per tic dofloor->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight); break; - // Used for sectors tagged to 50 linedefs (effectively - // changing the base height for placing things in that sector). + // Instantly lower floor to surrounding sectors. + // Used as a hack in the binary map format to allow thing heights above 4096. case instantLower: dofloor->direction = -1; // down dofloor->speed = INT32_MAX/2; // "instant" means "takes one tic" dofloor->floordestheight = P_FindLowestFloorSurrounding(sec); break; - // Linedef executor command, linetype 101. - // Front sector floor = destination height. case instantMoveFloorByFrontSector: dofloor->speed = INT32_MAX/2; // as above, "instant" is one tic dofloor->floordestheight = line->frontsector->floorheight; @@ -1878,22 +1642,12 @@ void EV_DoFloor(line_t *line, floor_e floortype) else dofloor->direction = -1; // down - // New for 1.09: now you can use the no climb flag to - // DISABLE the flat changing. This makes it work - // totally opposite the way linetype 106 does. Yet - // another reason I'll be glad to break backwards - // compatibility for the final. - if (line->flags & ML_NOCLIMB) - dofloor->texture = -1; // don't mess with the floorpic - else - dofloor->texture = line->frontsector->floorpic; + // If flag is set, change floor texture after moving + dofloor->texture = line->args[2] ? line->frontsector->floorpic : -1; break; - // Linedef executor command, linetype 106. - // Line length = speed, front sector floor = destination height. case moveFloorByFrontSector: - dofloor->speed = P_AproxDistance(line->dx, line->dy); - dofloor->speed = FixedDiv(dofloor->speed,8*FRACUNIT); + dofloor->speed = line->args[2] << (FRACBITS - 3); dofloor->floordestheight = line->frontsector->floorheight; if (dofloor->floordestheight >= sec->floorheight) @@ -1902,85 +1656,31 @@ void EV_DoFloor(line_t *line, floor_e floortype) dofloor->direction = -1; // down // chained linedef executing ability - if (line->flags & ML_BLOCKMONSTERS) - { - // Only set it on one of the moving sectors (the - // smallest numbered) and only if the front side - // x offset is positive, indicating a valid tag. - if (firstone && sides[line->sidenum[0]].textureoffset > 0) - dofloor->texture = (sides[line->sidenum[0]].textureoffset>>FRACBITS) - 32769; - else - dofloor->texture = -1; - } + // Only set it on one of the moving sectors (the smallest numbered) + if (line->args[3]) + dofloor->tag = firstone ? (INT16)line->args[3] : -1; // flat changing ability - else if (line->flags & ML_NOCLIMB) - dofloor->texture = line->frontsector->floorpic; - else - dofloor->texture = -1; // nothing special to do after movement completes - + dofloor->texture = line->args[4] ? line->frontsector->floorpic : -1; break; - case moveFloorByFrontTexture: - if (line->flags & ML_NOCLIMB) + case moveFloorByDistance: + if (line->args[4]) dofloor->speed = INT32_MAX/2; // as above, "instant" is one tic else - dofloor->speed = FixedDiv(sides[line->sidenum[0]].textureoffset,8*FRACUNIT); // texture x offset - dofloor->floordestheight = sec->floorheight + sides[line->sidenum[0]].rowoffset; // texture y offset + dofloor->speed = line->args[3] << (FRACBITS - 3); + dofloor->floordestheight = sec->floorheight + (line->args[2] << FRACBITS); if (dofloor->floordestheight > sec->floorheight) dofloor->direction = 1; // up else dofloor->direction = -1; // down break; -/* - // Linedef executor command, linetype 108. - // dx = speed, dy = amount to lower. - case lowerFloorByLine: - dofloor->direction = -1; // down - dofloor->speed = FixedDiv(abs(line->dx),8*FRACUNIT); - dofloor->floordestheight = sec->floorheight - abs(line->dy); - if (dofloor->floordestheight > sec->floorheight) // wrapped around - I_Error("Can't lower sector %d\n", secnum); - break; - - // Linedef executor command, linetype 109. - // dx = speed, dy = amount to raise. - case raiseFloorByLine: - dofloor->direction = 1; // up - dofloor->speed = FixedDiv(abs(line->dx),8*FRACUNIT); - dofloor->floordestheight = sec->floorheight + abs(line->dy); - if (dofloor->floordestheight < sec->floorheight) // wrapped around - I_Error("Can't raise sector %d\n", secnum); - break; -*/ - - // Linetypes 2/3. - // Move floor up and down indefinitely like the old elevators. + // Move floor up and down indefinitely. + // bounceFloor has slowdown at the top and bottom of movement. case bounceFloor: - dofloor->speed = P_AproxDistance(line->dx, line->dy); // same speed as elevateContinuous - dofloor->speed = FixedDiv(dofloor->speed,4*FRACUNIT); - dofloor->origspeed = dofloor->speed; // it gets slowed down at the top and bottom - dofloor->floordestheight = line->frontsector->floorheight; - - if (dofloor->floordestheight >= sec->floorheight) - dofloor->direction = 1; // up - else - dofloor->direction = -1; // down - - // Any delay? - dofloor->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS; - dofloor->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Initial delay - - dofloor->texture = (fixed_t)(line - lines); // hack: store source line number - break; - - // Linetypes 6/7. - // Like 2/3, but no slowdown at the top and bottom of movement, - // and the speed is line->dx the first way, line->dy for the - // return trip. Good for crushers. case bounceFloorCrush: - dofloor->speed = FixedDiv(abs(line->dx),4*FRACUNIT); + dofloor->speed = line->args[2] << (FRACBITS - 2); // same speed as elevateContinuous dofloor->origspeed = dofloor->speed; dofloor->floordestheight = line->frontsector->floorheight; @@ -1990,27 +1690,18 @@ void EV_DoFloor(line_t *line, floor_e floortype) dofloor->direction = -1; // down // Any delay? - dofloor->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS; - dofloor->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Initial delay - - dofloor->texture = (fixed_t)(line - lines); // hack: store source line number + dofloor->delay = line->args[5]; + dofloor->delaytimer = line->args[4]; // Initial delay break; case crushFloorOnce: - dofloor->speed = FixedDiv(abs(line->dx),4*FRACUNIT); - dofloor->origspeed = dofloor->speed; + dofloor->speed = dofloor->origspeed = line->args[2] << (FRACBITS - 2); dofloor->floordestheight = line->frontsector->ceilingheight; if (dofloor->floordestheight >= sec->floorheight) dofloor->direction = 1; // up else dofloor->direction = -1; // down - - // Any delay? - dofloor->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS; - dofloor->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; - - dofloor->texture = (fixed_t)(line - lines); // hack: store source line number break; default: @@ -2031,16 +1722,14 @@ void EV_DoFloor(line_t *line, floor_e floortype) // // jff 2/22/98 new type to move floor and ceiling in parallel // -void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) +void EV_DoElevator(mtag_t tag, line_t *line, elevator_e elevtype) { INT32 secnum = -1; sector_t *sec; elevator_t *elevator; - mtag_t tag = Tag_FGet(&line->tags); - TAG_ITER_DECLARECOUNTER(0); - // act on all sectors with the same tag as the triggering linedef - TAG_ITER_SECTORS(0, tag, secnum) + // act on all sectors with the given tag + TAG_ITER_SECTORS(tag, secnum) { sec = §ors[secnum]; @@ -2057,6 +1746,7 @@ void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) elevator->type = elevtype; elevator->sourceline = line; elevator->distance = 1; // Always crush unless otherwise + elevator->sector = sec; // set up the fields according to the type of elevator action switch (elevtype) @@ -2064,91 +1754,57 @@ void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) // elevator down to next floor case elevateDown: elevator->direction = -1; - elevator->sector = sec; elevator->speed = ELEVATORSPEED/2; // half speed elevator->floordestheight = P_FindNextLowestFloor(sec, sec->floorheight); - elevator->ceilingdestheight = elevator->floordestheight - + sec->ceilingheight - sec->floorheight; break; // elevator up to next floor case elevateUp: elevator->direction = 1; - elevator->sector = sec; elevator->speed = ELEVATORSPEED/4; // quarter speed elevator->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight); - elevator->ceilingdestheight = elevator->floordestheight - + sec->ceilingheight - sec->floorheight; break; // elevator up to highest floor case elevateHighest: elevator->direction = 1; - elevator->sector = sec; elevator->speed = ELEVATORSPEED/4; // quarter speed elevator->floordestheight = P_FindHighestFloorSurrounding(sec); - elevator->ceilingdestheight = elevator->floordestheight - + sec->ceilingheight - sec->floorheight; - break; - - // elevator to floor height of activating switch's front sector - case elevateCurrent: - elevator->sector = sec; - elevator->speed = ELEVATORSPEED; - elevator->floordestheight = line->frontsector->floorheight; - elevator->ceilingdestheight = elevator->floordestheight - + sec->ceilingheight - sec->floorheight; - elevator->direction = elevator->floordestheight > sec->floorheight? 1 : -1; break; case elevateContinuous: - if (customspeed) - { - elevator->origspeed = P_AproxDistance(line->dx, line->dy); - elevator->origspeed = FixedDiv(elevator->origspeed,4*FRACUNIT); - elevator->speed = elevator->origspeed; - } - else - { - elevator->speed = ELEVATORSPEED/2; - elevator->origspeed = elevator->speed; - } + elevator->origspeed = line->args[1] << (FRACBITS - 2); + elevator->speed = elevator->origspeed; - elevator->sector = sec; - elevator->low = !(line->flags & ML_NOCLIMB); // go down first unless noclimb is on + elevator->low = !line->args[4]; // go down first unless args[4] is set if (elevator->low) { elevator->direction = 1; elevator->floordestheight = P_FindNextHighestFloor(sec, sec->floorheight); - elevator->ceilingdestheight = elevator->floordestheight - + sec->ceilingheight - sec->floorheight; } else { elevator->direction = -1; elevator->floordestheight = P_FindNextLowestFloor(sec,sec->floorheight); - elevator->ceilingdestheight = elevator->floordestheight - + sec->ceilingheight - sec->floorheight; } elevator->floorwasheight = elevator->sector->floorheight; elevator->ceilingwasheight = elevator->sector->ceilingheight; - elevator->delay = sides[line->sidenum[0]].textureoffset >> FRACBITS; - elevator->delaytimer = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Initial delay + elevator->delay = line->args[3]; + elevator->delaytimer = line->args[2]; // Initial delay break; case bridgeFall: elevator->direction = -1; - elevator->sector = sec; elevator->speed = ELEVATORSPEED*4; // quadruple speed elevator->floordestheight = P_FindNextLowestFloor(sec, sec->floorheight); - elevator->ceilingdestheight = elevator->floordestheight - + sec->ceilingheight - sec->floorheight; break; default: break; } + + elevator->ceilingdestheight = elevator->floordestheight + sec->ceilingheight - sec->floorheight; } } @@ -2158,7 +1814,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) fixed_t leftx, rightx, topy, bottomy, topz, bottomz, widthfactor, heightfactor, a, b, c, spacing; mobjtype_t type; tic_t lifetime; - INT16 flags; + boolean fromcenter; sector_t *controlsec = rover->master->frontsector; mtag_t tag = Tag_FGet(&controlsec->tags); @@ -2188,25 +1844,20 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) spacing = (32<>FRACBITS != -1) - lifetime = (sides[lines[tagline].sidenum[0]].rowoffset>>FRACBITS); - else - lifetime = 0; - } - flags = lines[tagline].flags; + if (lines[tagline].stringargs[0]) + type = get_number(lines[tagline].stringargs[0]); + if (lines[tagline].args[0]) + spacing = lines[tagline].args[0] << FRACBITS; + if (lines[tagline].args[1]) + lifetime = (lines[tagline].args[1] != -1) ? lines[tagline].args[1] : 0; + fromcenter = !!lines[tagline].args[2]; } } @@ -2241,7 +1892,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) topz = *rover->topheight-(spacing>>1); bottomz = *rover->bottomheight; - if (flags & ML_EFFECT1) + if (fromcenter) { widthfactor = (rightx + topy - leftx - bottomy)>>3; heightfactor = (topz - *rover->bottomheight)>>2; @@ -2264,7 +1915,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) spawned = P_SpawnMobj(a, b, c, type); spawned->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones - if (flags & ML_EFFECT1) + if (fromcenter) { P_InstaThrust(spawned, R_PointToAngle2(sec->soundorg.x, sec->soundorg.y, a, b), FixedDiv(P_AproxDistance(a - sec->soundorg.x, b - sec->soundorg.y), widthfactor)); P_SetObjectMomZ(spawned, FixedDiv((c - bottomz), heightfactor), false); @@ -2336,8 +1987,7 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, crumble_t *crumble; sector_t *foundsec; INT32 i; - mtag_t tag = Tag_FGet(&rover->master->tags); - TAG_ITER_DECLARECOUNTER(0); + mtag_t tag = rover->master->args[0]; // If floor is already activated, skip it if (sec->floordata) @@ -2380,7 +2030,7 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, crumble->sector->crumblestate = CRUMBLE_ACTIVATED; - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) { foundsec = §ors[i]; @@ -2429,7 +2079,7 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) block->direction = 1; block->floorstartheight = block->sector->floorheight; block->ceilingstartheight = block->sector->ceilingheight; - block->tag = (INT16)Tag_FGet(§or->tags); + block->tag = (INT16)rover->master->args[0]; if (itsamonitor) { diff --git a/src/p_inter.c b/src/p_inter.c index e9a16a3dd..c230ce178 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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... @@ -365,7 +365,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (special->flags & (MF_ENEMY|MF_BOSS) && special->flags2 & MF2_FRET) return; - if (LUAh_TouchSpecial(special, toucher) || P_MobjWasRemoved(special)) + if (LUA_HookTouchSpecial(special, toucher) || P_MobjWasRemoved(special)) return; // 0 = none, 1 = elemental pierce, 2 = bubble bounce @@ -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,12 +738,11 @@ 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) || special->health <= 0 || special->health > MAXEMBLEMS) return; emblemlocations[special->health-1].collected = true; M_UpdateUnlockablesAndExtraEmblems(); - G_SaveGameData(); break; } @@ -751,7 +750,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; @@ -763,6 +762,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // return; { UINT8 flagteam = (special->type == MT_REDFLAG) ? 1 : 2; + sectorspecialflags_t specialflag = (special->type == MT_REDFLAG) ? SSF_REDTEAMBASE : SSF_BLUETEAMBASE; const char *flagtext; char flagcolor; char plname[MAXPLAYERNAME+4]; @@ -792,7 +792,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->fuse = 1; special->flags2 |= MF2_JUSTATTACKED; - if (!P_PlayerTouchingSectorSpecial(player, 4, 2 + flagteam)) + if (!P_PlayerTouchingSectorSpecialFlag(player, specialflag)) { CONS_Printf(M_GetText("%s returned the %c%s%c to base.\n"), plname, flagcolor, flagtext, 0x80); @@ -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; @@ -1381,19 +1381,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; case MT_AXE: { - line_t junk; thinker_t *th; mobj_t *mo2; - if (player->bot) + if (player->bot && player->bot != BOT_MPAI) return; - // Initialize my junk - junk.tags.tags = NULL; - junk.tags.count = 0; - - Tag_FSet(&junk.tags, LE_AXE); - EV_DoElevator(&junk, bridgeFall, false); + if (special->spawnpoint) + EV_DoElevator(special->spawnpoint->args[0], NULL, bridgeFall); // scan the remaining thinkers to find koopa for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -1423,7 +1418,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); @@ -1442,7 +1437,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Misc touchables // // *************** // case MT_STARPOST: - P_TouchStarPost(special, player, special->spawnpoint && (special->spawnpoint->options & MTF_OBJECTSPECIAL)); + P_TouchStarPost(special, player, special->spawnpoint && special->spawnpoint->args[1]); return; case MT_FAKEMOBILE: @@ -1685,7 +1680,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; // Only go in the mouth // Eaten by player! - if ((!player->bot) && (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)) + if ((!player->bot || player->bot == BOT_MPAI) && (player->powers[pw_underwater] && player->powers[pw_underwater] <= 12*TICRATE + 1)) { player->powers[pw_underwater] = underwatertics + 1; P_RestoreMusic(player); @@ -1696,7 +1691,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!player->climbing) { - if (player->bot && toucher->state-states != S_PLAY_GASP) + if (player->bot && player->bot != BOT_MPAI && toucher->state-states != S_PLAY_GASP) S_StartSound(toucher, special->info->deathsound); // Force it to play a sound for bots P_SetPlayerMobjState(toucher, S_PLAY_GASP); P_ResetPlayer(player); @@ -1704,7 +1699,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) toucher->momx = toucher->momy = toucher->momz = 0; - if (player->bot) + if (player->bot && player->bot != BOT_MPAI) return; else break; @@ -1736,7 +1731,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) return; case MT_MINECARTSPAWNER: - if (!player->bot && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART && !(player->powers[pw_ignorelatch] & (1<<15))) + if (!player->bot && player->bot != BOT_MPAI && special->fuse <= TICRATE && player->powers[pw_carry] != CR_MINECART && !(player->powers[pw_ignorelatch] & (1<<15))) { mobj_t *mcart = P_SpawnMobj(special->x, special->y, special->z, MT_MINECART); P_SetTarget(&mcart->target, toucher); @@ -1789,7 +1784,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) } return; default: // SOC or script pickup - if (player->bot) + if (player->bot && player->bot != BOT_MPAI) return; P_SetTarget(&special->target, toucher); break; @@ -1813,7 +1808,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 @@ -1939,7 +1934,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour if (!netgame) return; // Presumably it's obvious what's happening in splitscreen. - if (LUAh_HurtMsg(player, inflictor, source, damagetype)) + if (LUA_HookHurtMsg(player, inflictor, source, damagetype)) return; deadtarget = (player->mo->health <= 0); @@ -2391,7 +2386,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget mobj_t *mo; if (inflictor && (inflictor->type == MT_SHELL || inflictor->type == MT_FIREBALL)) - P_SetTarget(&target->tracer, inflictor); + S_StartScreamSound(target, sfx_mario2); if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && target->player && target->player->nightstime > 6) target->player->nightstime = 6; // Just let P_Ticker take care of the rest. @@ -2413,7 +2408,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->flags2 &= ~(MF2_SKULLFLY|MF2_NIGHTSPULL); target->health = 0; // This makes it easy to check if something's dead elsewhere. - if (LUAh_MobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target)) + if (LUA_HookMobjDeath(target, inflictor, source, damagetype) || P_MobjWasRemoved(target)) return; // Let EVERYONE know what happened to a player! 01-29-2002 Tails @@ -2555,7 +2550,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)) @@ -2776,7 +2771,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget case MT_BLASTEXECUTOR: if (target->spawnpoint) - P_LinedefExecute(target->spawnpoint->angle, (source ? source : inflictor), target->subsector->sector); + P_LinedefExecute(target->spawnpoint->args[0], (source ? source : inflictor), target->subsector->sector); break; case MT_SPINBOBERT: @@ -3475,7 +3470,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. @@ -3548,7 +3543,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da // Everything above here can't be forced. if (!metalrecording) { - UINT8 shouldForce = LUAh_ShouldDamage(target, inflictor, source, damage, damagetype); + UINT8 shouldForce = LUA_HookShouldDamage(target, inflictor, source, damage, damagetype); if (P_MobjWasRemoved(target)) return (shouldForce == 1); // mobj was removed if (shouldForce == 1) @@ -3566,7 +3561,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; } @@ -3589,7 +3584,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (!force && target->flags2 & MF2_FRET) // Currently flashing from being hit return false; - if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) + if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target)) return true; if (target->health > 1) @@ -3639,7 +3634,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da || (G_GametypeHasTeams() && player->ctfteam == source->player->ctfteam))) return false; // Don't run eachother over in special stages and team games and such } - if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) + if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype)) return true; P_NiGHTSDamage(target, source); // -5s :( return true; @@ -3651,7 +3646,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da return true; } - if (!force && inflictor && inflictor->flags & MF_FIRE) + if (!force && inflictor && inflictor->flags & MF_FIRE && !(damagetype && damagetype != DMG_FIRE)) { if (player->powers[pw_shield] & SH_PROTECTFIRE) return false; // Invincible to fire objects @@ -3693,15 +3688,15 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da if (force || (inflictor && inflictor->flags & MF_MISSILE && inflictor->flags2 & MF2_SUPERFIRE)) // Super Sonic is stunned! { - if (!LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) + if (!LUA_HookMobjDamage(target, inflictor, source, damage, damagetype)) P_SuperDamage(player, inflictor, source, damage); return true; } return false; } - else if (LUAh_MobjDamage(target, inflictor, source, damage, damagetype)) + 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_lights.c b/src/p_lights.c index d396e92d3..4c783f884 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -30,7 +30,7 @@ void P_RemoveLighting(sector_t *sector) // The thinker is the first member in all the lighting action structs, // so just let the thinker get freed, and that will free the whole // structure. - P_RemoveThinker(&((elevator_t *)sector->lightingdata)->thinker); + P_RemoveThinker(&((thinkerdata_t *)sector->lightingdata)->thinker); sector->lightingdata = NULL; } } @@ -54,43 +54,36 @@ void T_FireFlicker(fireflicker_t *flick) amount = (INT16)((UINT8)(P_RandomByte() & 3) * 16); if (flick->sector->lightlevel - amount < flick->minlight) - flick->sector->lightlevel = (INT16)flick->minlight; + flick->sector->lightlevel = flick->minlight; else - flick->sector->lightlevel = (INT16)((INT16)flick->maxlight - amount); + flick->sector->lightlevel = flick->maxlight - amount; flick->count = flick->resetcount; } /** Spawns an adjustable fire flicker effect in a sector. * - * \param minsector Sector whose light level is used as the darkest. - * \param maxsector Sector whose light level is used as the brightest, - * and also the target sector for the effect. + * \param sector Target sector for the effect. + * \param lighta One of the two light levels to move between. + * \param lightb The other light level. * \param length Four times the number of tics between flickers. * \sa T_FireFlicker */ -fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *minsector, sector_t *maxsector, INT32 length) +fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *sector, INT16 lighta, INT16 lightb, INT32 length) { fireflicker_t *flick; - P_RemoveLighting(maxsector); // out with the old, in with the new + P_RemoveLighting(sector); // out with the old, in with the new flick = Z_Calloc(sizeof (*flick), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &flick->thinker); flick->thinker.function.acp1 = (actionf_p1)T_FireFlicker; - flick->sector = maxsector; - flick->maxlight = maxsector->lightlevel; - flick->minlight = minsector->lightlevel; - if (flick->minlight > flick->maxlight) - { - // You mixed them up, you dummy. - INT32 oops = flick->minlight; - flick->minlight = flick->maxlight; - flick->maxlight = oops; - } + flick->sector = sector; + flick->maxlight = max(lighta, lightb); + flick->minlight = min(lighta, lightb); flick->count = flick->resetcount = length/4; - maxsector->lightingdata = flick; + sector->lightingdata = flick; // input bounds checking and stuff if (!flick->resetcount) @@ -103,6 +96,9 @@ fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *minsector, sector_t *maxse flick->maxlight++; } + // Make sure the starting light level is in range. + sector->lightlevel = max(flick->minlight, min(flick->maxlight, sector->lightlevel)); + return flick; } @@ -148,7 +144,7 @@ void P_SpawnLightningFlash(sector_t *sector) minlight = ((lightflash_t *)sector->lightingdata)->minlight; } - P_RemoveThinker(&((elevator_t *)sector->lightingdata)->thinker); + P_RemoveThinker(&((thinkerdata_t *)sector->lightingdata)->thinker); } sector->lightingdata = NULL; @@ -182,21 +178,21 @@ void T_StrobeFlash(strobe_t *flash) if (flash->sector->lightlevel == flash->minlight) { - flash->sector->lightlevel = (INT16)flash->maxlight; + flash->sector->lightlevel = flash->maxlight; flash->count = flash->brighttime; } else { - flash->sector->lightlevel = (INT16)flash->minlight; + flash->sector->lightlevel = flash->minlight; flash->count = flash->darktime; } } /** Spawns an adjustable strobe light effect in a sector. * - * \param minsector Sector whose light level is used as the darkest. - * \param maxsector Sector whose light level is used as the brightest, - * and also the target sector for the effect. + * \param sector Target sector for the effect. + * \param lighta One of the two light levels to move between. + * \param lightb The other light level. * \param darktime Time in tics for the light to be dark. * \param brighttime Time in tics for the light to be bright. * \param inSync If true, the effect will be kept in sync @@ -207,29 +203,21 @@ void T_StrobeFlash(strobe_t *flash) * the strobe flash is random. * \sa T_StrobeFlash */ -strobe_t *P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector, INT32 darktime, INT32 brighttime, boolean inSync) +strobe_t *P_SpawnAdjustableStrobeFlash(sector_t *sector, INT16 lighta, INT16 lightb, INT32 darktime, INT32 brighttime, boolean inSync) { strobe_t *flash; - P_RemoveLighting(maxsector); // out with the old, in with the new + P_RemoveLighting(sector); // out with the old, in with the new flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &flash->thinker); - flash->sector = maxsector; + flash->sector = sector; flash->darktime = darktime; flash->brighttime = brighttime; flash->thinker.function.acp1 = (actionf_p1)T_StrobeFlash; - flash->maxlight = maxsector->lightlevel; - flash->minlight = minsector->lightlevel; - - if (flash->minlight > flash->maxlight) - { - // You mixed them up, you dummy. - INT32 oops = flash->minlight; - flash->minlight = flash->maxlight; - flash->maxlight = oops; - } + flash->maxlight = max(lighta, lightb); + flash->minlight = min(lighta, lightb); if (flash->minlight == flash->maxlight) flash->minlight = 0; @@ -239,7 +227,10 @@ strobe_t *P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector, else flash->count = 1; - maxsector->lightingdata = flash; + // Make sure the starting light level is in range. + sector->lightlevel = max(flash->minlight, min(flash->maxlight, sector->lightlevel)); + + sector->lightingdata = flash; return flash; } @@ -254,20 +245,20 @@ void T_Glow(glow_t *g) { case -1: // DOWN - g->sector->lightlevel = (INT16)(g->sector->lightlevel - (INT16)g->speed); + g->sector->lightlevel -= g->speed; if (g->sector->lightlevel <= g->minlight) { - g->sector->lightlevel = (INT16)(g->sector->lightlevel + (INT16)g->speed); + g->sector->lightlevel += g->speed; g->direction = 1; } break; case 1: // UP - g->sector->lightlevel = (INT16)(g->sector->lightlevel + (INT16)g->speed); + g->sector->lightlevel += g->speed; if (g->sector->lightlevel >= g->maxlight) { - g->sector->lightlevel = (INT16)(g->sector->lightlevel - (INT16)g->speed); + g->sector->lightlevel -= g->speed; g->direction = -1; } break; @@ -276,34 +267,27 @@ void T_Glow(glow_t *g) /** Spawns an adjustable glowing light effect in a sector. * - * \param minsector Sector whose light level is used as the darkest. - * \param maxsector Sector whose light level is used as the brightest, - * and also the target sector for the effect. + * \param sector Target sector for the effect. + * \param lighta One of the two light levels to move between. + * \param lightb The other light level. * \param length The speed of the effect. * \sa T_Glow */ -glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, INT32 length) +glow_t *P_SpawnAdjustableGlowingLight(sector_t *sector, INT16 lighta, INT16 lightb, INT32 length) { glow_t *g; - P_RemoveLighting(maxsector); // out with the old, in with the new + P_RemoveLighting(sector); // out with the old, in with the new g = Z_Calloc(sizeof (*g), PU_LEVSPEC, NULL); P_AddThinker(THINK_MAIN, &g->thinker); - g->sector = maxsector; - g->minlight = minsector->lightlevel; - g->maxlight = maxsector->lightlevel; - if (g->minlight > g->maxlight) - { - // You mixed them up, you dummy. - INT32 oops = g->minlight; - g->minlight = g->maxlight; - g->maxlight = oops; - } + g->sector = sector; + g->minlight = min(lighta, lightb); + g->maxlight = max(lighta, lightb); g->thinker.function.acp1 = (actionf_p1)T_Glow; g->direction = 1; - g->speed = length/4; + g->speed = (INT16)(length/4); if (g->speed > (g->maxlight - g->minlight)/2) // don't make it ridiculous speed g->speed = (g->maxlight - g->minlight)/2; @@ -317,7 +301,10 @@ glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, g->speed = (g->maxlight - g->minlight)/2; } - maxsector->lightingdata = g; + // Make sure the starting light level is in range. + sector->lightlevel = max(g->minlight, min(g->maxlight, sector->lightlevel)); + + sector->lightingdata = g; return g; } @@ -371,13 +358,13 @@ void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean } } -void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, boolean force) +void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, boolean force, boolean relative) { INT32 i; - TAG_ITER_DECLARECOUNTER(0); + INT32 realdestvalue; // search all sectors for ones with tag - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) { if (!force && ticbased // always let speed fader execute && sectors[i].lightingdata @@ -387,7 +374,9 @@ void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, bool CONS_Debug(DBG_GAMELOGIC, "Line type 420 Executor: Fade light thinker already exists, timer: %d\n", ((lightlevel_t*)sectors[i].lightingdata)->timer); continue; } - P_FadeLightBySector(§ors[i], destvalue, speed, ticbased); + + realdestvalue = relative ? max(0, min(255, sectors[i].lightlevel + destvalue)) : destvalue; + P_FadeLightBySector(§ors[i], realdestvalue, speed, ticbased); } } diff --git a/src/p_local.h b/src/p_local.h index 8caab0d27..f50606117 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -143,16 +143,18 @@ angle_t P_GetLocalAngle(player_t *player); void P_SetLocalAngle(player_t *player, angle_t angle); void P_ForceLocalAngle(player_t *player, angle_t angle); boolean P_PlayerFullbright(player_t *player); +boolean P_PlayerCanEnterSpinGaps(player_t *player); +boolean P_PlayerShouldUseSpinHeight(player_t *player); boolean P_IsObjectInGoop(mobj_t *mo); boolean P_IsObjectOnGround(mobj_t *mo); -boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec); boolean P_InSpaceSector(mobj_t *mo); boolean P_InQuicksand(mobj_t *mo); boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff); void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); +void P_SetPower(player_t *player, powertype_t power, UINT16 value); void P_SpawnShieldOrb(player_t *player); void P_SwitchShield(player_t *player, UINT16 shieldtype); mobj_t *P_SpawnGhostMobj(mobj_t *mobj); @@ -347,6 +349,7 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration); #define PAL_MIXUP 2 #define PAL_RECYCLE 3 #define PAL_NUKE 4 +#define PAL_INVERT 5 // // P_ENEMY @@ -369,7 +372,7 @@ void P_NewChaseDir(mobj_t *actor); boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist); mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers, SINT8 moveforward); -void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo); +void P_InternalFlickySetColor(mobj_t *actor, UINT8 color); #define P_IsFlickyCenter(type) (type > MT_FLICKY_01 && type < MT_SEED && (type - MT_FLICKY_01) % 2 ? 1 : 0) void P_InternalFlickyBubble(mobj_t *actor); void P_InternalFlickyFly(mobj_t *actor, fixed_t flyspeed, fixed_t targetdist, fixed_t chasez); @@ -407,6 +410,7 @@ void P_SetUnderlayPosition(mobj_t *thing); boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y); boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam); +boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_Move(mobj_t *actor, fixed_t speed); boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); diff --git a/src/p_map.c b/src/p_map.c index da68b9511..93ff2b630 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -419,16 +419,23 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) } else if (object->player->dashmode >= DASHMODE_THRESHOLD) P_SetPlayerMobjState(object, S_PLAY_DASH); - else if (P_IsObjectOnGround(object) && horizspeed >= FixedMul(object->player->runspeed, object->scale)) - P_SetPlayerMobjState(object, S_PLAY_RUN); + else if (P_IsObjectOnGround(object)) + P_SetPlayerMobjState(object, (horizspeed >= FixedMul(object->player->runspeed, object->scale)) ? S_PLAY_RUN : S_PLAY_WALK); else - P_SetPlayerMobjState(object, S_PLAY_WALK); + P_SetPlayerMobjState(object, (object->momz > 0) ? S_PLAY_SPRING : S_PLAY_FALL); } else if (P_MobjFlip(object)*vertispeed > 0) P_SetPlayerMobjState(object, S_PLAY_SPRING); else P_SetPlayerMobjState(object, S_PLAY_FALL); } + else if (horizspeed + && object->tracer + && object->tracer->player + && object->tracer->player->powers[pw_carry] != CR_NONE + && object->tracer->tracer == object + && (!demoplayback || P_ControlStyle(object->tracer->player) == CS_LMAOGALOG)) + P_SetPlayerAngle(object->tracer->player, spring->angle); object->standingslope = NULL; // And again. @@ -485,7 +492,7 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) switch (spring->type) { case MT_FAN: // fan - if (zdist > (spring->health << FRACBITS)) // max z distance determined by health (set by map thing angle) + if (zdist > (spring->health << FRACBITS)) // max z distance determined by health (set by map thing args[0]) break; if (flipval*object->momz >= FixedMul(speed, spring->scale)) // if object's already moving faster than your best, don't bother break; @@ -512,6 +519,7 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) if (spring->state != &states[S_STEAM1]) // Only when it bursts break; + object->eflags |= MFE_SPRUNG; object->momz = flipval*FixedMul(speed, FixedSqrt(FixedMul(spring->scale, object->scale))); // scale the speed with both objects' scales, just like with springs! if (p) @@ -747,7 +755,7 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath // REX HAS SEEN YOU - if (!LUAh_SeenPlayer(tmthing->target->player, thing->player)) + if (!LUA_HookSeenPlayer(tmthing->target->player, thing->player)) return false; seenplayer = thing->player; @@ -936,7 +944,7 @@ static boolean PIT_CheckThing(mobj_t *thing) } { - UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type + UINT8 shouldCollide = LUA_Hook2Mobj(thing, tmthing, MOBJ_HOOK(MobjCollide)); // checks hook for thing's type if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) return true; // one of them was removed??? if (shouldCollide == 1) @@ -944,7 +952,7 @@ static boolean PIT_CheckThing(mobj_t *thing) else if (shouldCollide == 2) return true; // force no collide - shouldCollide = LUAh_MobjMoveCollide(tmthing, thing); // checks hook for tmthing's type + shouldCollide = LUA_Hook2Mobj(tmthing, thing, MOBJ_HOOK(MobjMoveCollide)); // checks hook for tmthing's type if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) return true; // one of them was removed??? if (shouldCollide == 1) @@ -1145,11 +1153,11 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (tmthing->eflags & MFE_VERTICALFLIP) - thing->z = tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale); + P_TeleportMove(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale)); else - thing->z = tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale); + P_TeleportMove(thing, thing->x, thing->y, tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale)); if (thing->flags & MF_SHOOTABLE) - P_DamageMobj(thing, tmthing, tmthing, 1, 0); + P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); return true; } @@ -1928,7 +1936,7 @@ static boolean PIT_CheckLine(line_t *ld) blockingline = ld; { - UINT8 shouldCollide = LUAh_MobjLineCollide(tmthing, blockingline); // checks hook for thing's type + UINT8 shouldCollide = LUA_HookMobjLineCollide(tmthing, blockingline); // checks hook for thing's type if (P_MobjWasRemoved(tmthing)) return true; // one of them was removed??? if (shouldCollide == 1) @@ -2022,7 +2030,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) subsector_t *newsubsec; boolean blockval = true; - ps_checkposition_calls++; + ps_checkposition_calls.value.i++; I_Assert(thing != NULL); #ifdef PARANOIA @@ -2258,6 +2266,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y) { if (!P_BlockThingsIterator(bx, by, PIT_CheckThing)) blockval = false; + else + tmhitthing = tmfloorthing; if (P_MobjWasRemoved(tmthing)) return false; } @@ -2322,7 +2332,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) mapcampointer = thiscam; - if (GETSECSPECIAL(newsubsec->sector->special, 4) == 12) + if (newsubsec->sector->flags & MSF_NOCLIPCAMERA) { // Camera noclip on entire sector. tmfloorz = tmdropoffz = thiscam->z; tmceilingz = tmdrpoffceilz = thiscam->z + thiscam->height; @@ -2362,7 +2372,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) for (rover = newsubsec->sector->ffloors; rover; rover = rover->next) { fixed_t topheight, bottomheight; - if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) + if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, x, y, NULL); @@ -2434,7 +2444,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam) // We're inside it! Yess... polysec = po->lines[0]->backsector; - if (GETSECSPECIAL(polysec->special, 4) == 12) + if (polysec->flags & MSF_NOCLIPCAMERA) { // Camera noclip polyobj. plink = (polymaplink_t *)(plink->link.next); continue; @@ -2657,17 +2667,17 @@ boolean PIT_PushableMoved(mobj_t *thing) return true; } -// -// P_TryMove -// Attempt to move to a new position. -// -boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +static boolean +increment_move +( mobj_t * thing, + fixed_t x, + fixed_t y, + boolean allowdropoff) { fixed_t tryx = thing->x; fixed_t tryy = thing->y; fixed_t radius = thing->radius; fixed_t thingtop; - fixed_t startingonground = P_IsObjectOnGround(thing); floatok = false; if (radius < MAXRADIUS/2) @@ -2702,14 +2712,14 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) if (thing->player) { - // If using type Section1:13, double the maxstep. - if (P_PlayerTouchingSectorSpecial(thing->player, 1, 13) - || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 13) + // If using SSF_DOUBLESTEPUP, double the maxstep. + if (P_PlayerTouchingSectorSpecialFlag(thing->player, SSF_DOUBLESTEPUP) + || (R_PointInSubsector(x, y)->sector->specialflags & SSF_DOUBLESTEPUP)) maxstep <<= 1; - // If using type Section1:14, no maxstep. - if (P_PlayerTouchingSectorSpecial(thing->player, 1, 14) - || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14) + // If using SSF_NOSTEPDOWN, no maxstep. + if (P_PlayerTouchingSectorSpecialFlag(thing->player, SSF_NOSTEPDOWN) + || (R_PointInSubsector(x, y)->sector->specialflags & SSF_NOSTEPDOWN)) maxstep = 0; // Don't 'step up' while springing, @@ -2718,11 +2728,24 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) && P_MobjFlip(thing)*thing->momz > FixedMul(FRACUNIT, thing->scale)) maxstep = 0; } + else if (thing->flags & MF_PUSHABLE) + { + // If using SSF_DOUBLESTEPUP, double the maxstep. + if (R_PointInSubsector(x, y)->sector->specialflags & SSF_DOUBLESTEPUP) + maxstep <<= 1; + + // If using SSF_NOSTEPDOWN, no maxstep. + if (R_PointInSubsector(x, y)->sector->specialflags & SSF_NOSTEPDOWN) + maxstep = 0; + } if (thing->type == MT_SKIM) maxstep = 0; - if (tmceilingz - tmfloorz < thing->height) + if (tmceilingz - tmfloorz < thing->height + || (thing->player + && tmceilingz - tmfloorz < P_GetPlayerHeight(thing->player) + && !P_PlayerCanEnterSpinGaps(thing->player))) { if (tmfloorthing) tmhitthing = tmfloorthing; @@ -2792,7 +2815,38 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } } while (tryx != x || tryy != y); + return true; +} + +// +// P_CheckMove +// Check if a P_TryMove would be successful. +// +boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +{ + boolean moveok; + mobj_t *hack = P_SpawnMobjFromMobj(thing, 0, 0, 0, MT_RAY); + + hack->radius = thing->radius; + hack->height = thing->height; + + moveok = increment_move(hack, x, y, allowdropoff); + P_RemoveMobj(hack); + + return moveok; +} + +// +// P_TryMove +// Attempt to move to a new position. +// +boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) +{ + fixed_t startingonground = P_IsObjectOnGround(thing); + // The move is ok! + if (!increment_move(thing, x, y, allowdropoff)) + return false; // If it's a pushable object, check if anything is // standing on top and move it, too. @@ -3048,7 +3102,7 @@ static void P_HitCameraSlideLine(line_t *ld, camera_t *thiscam) } side = P_PointOnLineSide(thiscam->x, thiscam->y, ld); - lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy); + lineangle = ld->angle; if (side == 1) lineangle += ANGLE_180; @@ -3094,7 +3148,7 @@ static void P_HitSlideLine(line_t *ld) side = P_PointOnLineSide(slidemo->x, slidemo->y, ld); - lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy); + lineangle = ld->angle; if (side == 1) lineangle += ANGLE_180; @@ -3137,7 +3191,7 @@ static void P_HitBounceLine(line_t *ld) return; } - lineangle = R_PointToAngle2(0, 0, ld->dx, ld->dy); + lineangle = ld->angle; if (lineangle >= ANGLE_180) lineangle -= ANGLE_180; @@ -3330,6 +3384,11 @@ static boolean PTR_LineIsBlocking(line_t *li) if (openbottom - slidemo->z > FixedMul(MAXSTEPMOVE, slidemo->scale)) return true; // too big a step up + if (slidemo->player + && openrange < P_GetPlayerHeight(slidemo->player) + && !P_PlayerCanEnterSpinGaps(slidemo->player)) + return true; // nonspin character should not take this path + return false; } @@ -3440,7 +3499,7 @@ static boolean PTR_SlideTraverse(intercept_t *in) // see if it is closer than best so far if (li->polyobj && slidemo->player) { - if ((li->polyobj->lines[0]->backsector->flags & SF_TRIGGERSPECIAL_TOUCH) && !(li->polyobj->flags & POF_NOSPECIALS)) + if ((li->polyobj->lines[0]->backsector->flags & MSF_TRIGGERSPECIAL_TOUCH) && !(li->polyobj->flags & POF_NOSPECIALS)) P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector); } @@ -3579,10 +3638,7 @@ static void P_CheckLavaWall(mobj_t *mo, sector_t *sec) if (!(rover->flags & FF_SWIMMABLE)) continue; - if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 3) - continue; - - if (rover->master->flags & ML_BLOCKMONSTERS) + if (rover->master->frontsector->damagetype != SD_LAVA) continue; topheight = P_GetFFloorTopZAt(rover, mo->x, mo->y); diff --git a/src/p_maputl.c b/src/p_maputl.c index 90718a41c..614db93e3 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -374,7 +374,7 @@ void P_CameraLineOpening(line_t *linedef) for (rover = front->ffloors; rover; rover = rover->next) { fixed_t topheight, bottomheight; - if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) + if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tmx, tmy, linedef); @@ -398,7 +398,7 @@ void P_CameraLineOpening(line_t *linedef) for (rover = back->ffloors; rover; rover = rover->next) { fixed_t topheight, bottomheight; - if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) + if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tmx, tmy, linedef); @@ -491,7 +491,7 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) fixed_t thingtop = mobj->z + mobj->height; // Check for collision with front side's midtexture if Effect 4 is set - if (linedef->flags & ML_EFFECT4 + if (linedef->flags & ML_MIDSOLID && !linedef->polyobj // don't do anything for polyobjects! ...for now ) { side_t *side = &sides[linedef->sidenum[0]]; @@ -508,10 +508,10 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) // don't remove this code unless solid midtextures // on non-solid polyobjects should NEVER happen in the future if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) { - if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat + if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat texbottom = back->floorheight + side->rowoffset; textop = back->ceilingheight + side->rowoffset; - } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { + } else if (linedef->flags & ML_MIDTEX) { texbottom = back->floorheight + side->rowoffset; textop = texbottom + texheight*(side->repeatcnt+1); } else { @@ -521,10 +521,10 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) } else #endif { - if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat + if (linedef->flags & ML_WRAPMIDTEX && !side->repeatcnt) { // "infinite" repeat texbottom = openbottom + side->rowoffset; textop = opentop + side->rowoffset; - } else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) { + } else if (linedef->flags & ML_MIDPEG) { texbottom = openbottom + side->rowoffset; textop = texbottom + texheight*(side->repeatcnt+1); } else { diff --git a/src/p_maputl.h b/src/p_maputl.h index 08b606833..b7779d88a 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_mobj.c b/src/p_mobj.c index a1edcfe77..36253569b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -11,6 +11,7 @@ /// \file p_mobj.c /// \brief Moving object handling. Spawn functions +#include "dehacked.h" #include "doomdef.h" #include "g_game.h" #include "g_input.h" @@ -78,7 +79,7 @@ void P_AddCachedAction(mobj_t *mobj, INT32 statenum) // // P_SetupStateAnimation // -FUNCINLINE static ATTRINLINE void P_SetupStateAnimation(mobj_t *mobj, state_t *st) +static void P_SetupStateAnimation(mobj_t *mobj, state_t *st) { INT32 animlength = (mobj->sprite == SPR_PLAY && mobj->skin) ? (INT32)(((skin_t *)mobj->skin)->sprites[mobj->sprite2].numframes) - 1 @@ -325,9 +326,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) mobj->tics = st->tics; // Adjust the player's animation speed to match their velocity. - if (state == S_PLAY_STND && player->powers[pw_super] && skins[player->skin].sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0) // if no super wait, don't wait at all - mobj->tics = -1; - else if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE)) + if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE)) mobj->tics = 2; else if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST)) { @@ -396,8 +395,28 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) if (skin) { - spr2 = P_GetSkinSprite2(skin, (((player->powers[pw_super] && !(player->charflags & SF_NOSUPERSPRITES)) ? FF_SPR2SUPER : 0)|st->frame) & FF_FRAMEMASK, mobj->player); + UINT16 stateframe = st->frame; + + // Add/Remove FF_SPR2SUPER based on certain conditions + if (player->charflags & SF_NOSUPERSPRITES) + stateframe = stateframe & ~FF_SPR2SUPER; + else if (player->powers[pw_super]) + stateframe = stateframe | FF_SPR2SUPER; + + if (stateframe & FF_SPR2SUPER) + { + if (mobj->eflags & MFE_FORCENOSUPER) + stateframe = stateframe & ~FF_SPR2SUPER; + } + else if (mobj->eflags & MFE_FORCESUPER) + stateframe = stateframe | FF_SPR2SUPER; + + // Get the sprite2 and frame number + spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), mobj->player); numframes = skin->sprites[spr2].numframes; + + if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0) + mobj->tics = -1; // If no super wait, don't wait at all } else { @@ -522,8 +541,23 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state) if (skin) { - spr2 = P_GetSkinSprite2(skin, st->frame & FF_FRAMEMASK, mobj->player); + UINT16 stateframe = st->frame; + + // Add/Remove FF_SPR2SUPER based on certain conditions + if (stateframe & FF_SPR2SUPER) + { + if (mobj->eflags & MFE_FORCENOSUPER) + stateframe = stateframe & ~FF_SPR2SUPER; + } + else if (mobj->eflags & MFE_FORCESUPER) + stateframe = stateframe | FF_SPR2SUPER; + + // Get the sprite2 and frame number + spr2 = P_GetSkinSprite2(skin, (stateframe & FF_FRAMEMASK), NULL); numframes = skin->sprites[spr2].numframes; + + if (state == S_PLAY_STND && (spr2 & FF_SPR2SUPER) && skin->sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0) + mobj->tics = -1; // If no super wait, don't wait at all } else { @@ -1412,6 +1446,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if (mo->subsector->sector->ffloors) // Check for 3D floor gravity too. { ffloor_t *rover; + fixed_t gravfactor; for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next) { @@ -1421,13 +1456,14 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER)) goopgravity = true; - if (!(rover->master->frontsector->gravity)) + gravfactor = P_GetSectorGravityFactor(rover->master->frontsector); + + if (gravfactor == FRACUNIT) continue; - gravityadd = -FixedMul(gravity, - (FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000))); + gravityadd = -FixedMul(gravity, gravfactor); - if (rover->master->frontsector->verticalflip && gravityadd > 0) + if ((rover->master->frontsector->flags & MSF_GRAVITYFLIP) && gravityadd > 0) mo->eflags |= MFE_VERTICALFLIP; no3dfloorgrav = false; @@ -1437,13 +1473,9 @@ fixed_t P_GetMobjGravity(mobj_t *mo) if (no3dfloorgrav) { - if (mo->subsector->sector->gravity) - gravityadd = -FixedMul(gravity, - (FixedDiv(*mo->subsector->sector->gravity>>FRACBITS, 1000))); - else - gravityadd = -gravity; + gravityadd = -FixedMul(gravity, P_GetSectorGravityFactor(mo->subsector->sector)); - if (mo->subsector->sector->verticalflip && gravityadd > 0) + if ((mo->subsector->sector->flags & MSF_GRAVITYFLIP) && gravityadd > 0) mo->eflags |= MFE_VERTICALFLIP; } @@ -1688,8 +1720,7 @@ static void P_PushableCheckBustables(mobj_t *mo) if (!(rover->flags & FF_BUSTUP)) continue; - // Needs ML_EFFECT4 flag for pushables to break it - if (!(rover->master->flags & ML_EFFECT4)) + if (!(rover->bustflags & FB_PUSHABLES)) continue; if (rover->master->frontsector->crumblestate != CRUMBLE_NONE) @@ -1699,7 +1730,7 @@ static void P_PushableCheckBustables(mobj_t *mo) bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); // Height checks - if (rover->flags & FF_SHATTERBOTTOM) + if (rover->bustflags & FB_ONLYBOTTOM) { if (mo->z + mo->momz + mo->height < bottomheight) continue; @@ -1707,36 +1738,42 @@ static void P_PushableCheckBustables(mobj_t *mo) if (mo->z + mo->height > bottomheight) continue; } - else if (rover->flags & FF_SPINBUST) - { - if (mo->z + mo->momz > topheight) - continue; - - if (mo->z + mo->height < bottomheight) - continue; - } - else if (rover->flags & FF_SHATTER) - { - if (mo->z + mo->momz > topheight) - continue; - - if (mo->z + mo->momz + mo->height < bottomheight) - continue; - } else { - if (mo->z >= topheight) - continue; + switch (rover->busttype) + { + case BT_TOUCH: + if (mo->z + mo->momz > topheight) + continue; - if (mo->z + mo->height < bottomheight) - continue; + if (mo->z + mo->momz + mo->height < bottomheight) + continue; + + break; + case BT_SPINBUST: + if (mo->z + mo->momz > topheight) + continue; + + if (mo->z + mo->height < bottomheight) + continue; + + break; + default: + if (mo->z >= topheight) + continue; + + if (mo->z + mo->height < bottomheight) + continue; + + break; + } } EV_CrumbleChain(NULL, rover); // node->m_sector // Run a linedef executor?? - if (rover->master->flags & ML_EFFECT5) - P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), mo, node->m_sector); + if (rover->bustflags & FB_EXECUTOR) + P_LinedefExecute(rover->busttag, mo, node->m_sector); goto bustupdone; } @@ -1839,12 +1876,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 (LUAh_MobjMoveBlocked(mo)) + if (LUA_HookMobjMoveBlocked(mo, tmhitthing, blockingline)) { if (P_MobjWasRemoved(mo)) return; @@ -2287,11 +2322,11 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) return false; if (((mo->z <= mo->subsector->sector->floorheight - && ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR)) + && ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_FLOOR)) || (mo->z + mo->height >= mo->subsector->sector->ceilingheight - && ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING))) - && (GETSECSPECIAL(mo->subsector->sector->special, 1) == 6 - || GETSECSPECIAL(mo->subsector->sector->special, 1) == 7)) + && ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_CEILING))) + && (mo->subsector->sector->damagetype == SD_DEATHPITTILT + || mo->subsector->sector->damagetype == SD_DEATHPITNOTILT)) return true; return false; @@ -2299,11 +2334,7 @@ boolean P_CheckDeathPitCollide(mobj_t *mo) boolean P_CheckSolidLava(ffloor_t *rover) { - if (rover->flags & FF_SWIMMABLE && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3 - && !(rover->master->flags & ML_BLOCKMONSTERS)) - return true; - - return false; + return (rover->flags & FF_SWIMMABLE) && (rover->master->frontsector->damagetype == SD_LAVA); } // @@ -2491,7 +2522,7 @@ boolean P_ZMovement(mobj_t *mo) { P_KillMobj(mo, NULL, NULL, 0); } - return false; + return !P_MobjWasRemoved(mo); // allows explosion states to run } else { @@ -2549,6 +2580,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; @@ -2640,7 +2675,7 @@ boolean P_ZMovement(mobj_t *mo) { if (mo->flags2 & MF2_AMBUSH) { - // If deafed, give the tumbleweed another random kick if it runs out of steam. + // Give the tumbleweed another random kick if it runs out of steam. mom.z += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale); if (P_RandomChance(FRACUNIT/2)) @@ -2805,7 +2840,7 @@ static void P_CheckMarioBlocks(mobj_t *mo) if (*rover->bottomheight != mo->ceilingz) continue; - if (rover->flags & FF_SHATTERBOTTOM) // Brick block! + if (rover->flags & FF_GOOWATER) // Brick block! EV_CrumbleChain(node->m_sector, rover); else // Question block! EV_MarioBlock(rover, node->m_sector, mo); @@ -3188,13 +3223,16 @@ boolean P_SceneryZMovement(mobj_t *mo) // boolean P_CanRunOnWater(player_t *player, ffloor_t *rover) { - fixed_t topheight = P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); + boolean flip = player->mo->eflags & MFE_VERTICALFLIP; + fixed_t surfaceheight = flip ? P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y) : P_GetFFloorTopZAt(rover, player->mo->x, player->mo->y); + fixed_t playerbottom = flip ? (player->mo->z + player->mo->height) : player->mo->z; + boolean doifit = flip ? (surfaceheight - player->mo->floorz >= player->mo->height) : (player->mo->ceilingz - surfaceheight >= player->mo->height); if (!player->powers[pw_carry] && !player->homing - && ((player->powers[pw_super] || player->charflags & SF_RUNONWATER || player->dashmode >= DASHMODE_THRESHOLD) && player->mo->ceilingz-topheight >= player->mo->height) + && ((player->powers[pw_super] || player->charflags & SF_RUNONWATER || player->dashmode >= DASHMODE_THRESHOLD) && doifit) && (rover->flags & FF_SWIMMABLE) && !(player->pflags & PF_SPINNING) && player->speed > FixedMul(player->runspeed, player->mo->scale) && !(player->pflags & PF_SLIDING) - && abs(player->mo->z - topheight) < FixedMul(30*FRACUNIT, player->mo->scale)) + && abs(playerbottom - surfaceheight) < FixedMul(30*FRACUNIT, player->mo->scale)) return true; return false; @@ -3231,8 +3269,8 @@ void P_MobjCheckWater(mobj_t *mobj) || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player))) continue; - topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y); - bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y); + topheight = P_GetSpecialTopZ(mobj, sectors + rover->secnum, sector); + bottomheight = P_GetSpecialBottomZ(mobj, sectors + rover->secnum, sector); if (mobj->eflags & MFE_VERTICALFLIP) { @@ -3263,7 +3301,7 @@ void P_MobjCheckWater(mobj_t *mobj) if (mobj->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) { - if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 3) + if (rover->master->frontsector->damagetype == SD_FIRE || rover->master->frontsector->damagetype == SD_LAVA) mobj->eflags |= MFE_TOUCHLAVA; if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY)) @@ -3283,11 +3321,9 @@ void P_MobjCheckWater(mobj_t *mobj) boolean electric = !!(p->powers[pw_shield] & SH_PROTECTELECTRIC); if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER) && !(mobj->eflags & MFE_TOUCHLAVA))) { // Water removes electric and non-water fire shields... - P_FlashPal(p, - electric - ? PAL_WHITE - : PAL_NUKE, - 1); + if (electric) + P_FlashPal(p, PAL_WHITE, 1); + p->powers[pw_shield] = p->powers[pw_shield] & SH_STACK; } } @@ -3509,19 +3545,16 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) { sector_t *sector; fixed_t halfheight = thiscam->z + (thiscam->height >> 1); - size_t i; // see if we are in water sector = thiscam->subsector->sector; - for (i = 0; i < sector->tags.count; i++) - if (Tag_FindLineSpecial(13, sector->tags.tags[i]) != -1) - return true; + if (sector->flags & MSF_HEATWAVE) + return true; if (sector->ffloors) { ffloor_t *rover; - size_t j; for (rover = sector->ffloors; rover; rover = rover->next) { @@ -3533,8 +3566,7 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) if (halfheight <= P_GetFFloorBottomZAt(rover, thiscam->x, thiscam->y)) continue; - for (j = 0; j < rover->master->frontsector->tags.count; j++) - if (Tag_FindLineSpecial(13, rover->master->frontsector->tags.tags[j]) != -1) + if (rover->master->frontsector->flags & MSF_HEATWAVE) return true; } } @@ -4060,9 +4092,11 @@ static void P_KillRingsInLava(mobj_t *mo) { if (!(rover->flags & FF_EXISTS)) continue; // fof must be real - if (!(rover->flags & FF_SWIMMABLE // fof must be water - && GETSECSPECIAL(rover->master->frontsector->special, 1) == 3)) // fof must be lava water - continue; + if (!(rover->flags & FF_SWIMMABLE)) + continue; // fof must be water + + if (rover->master->frontsector->damagetype != SD_FIRE && rover->master->frontsector->damagetype != SD_LAVA) + continue; // fof must have fire or lava damage // find heights of FOF topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); @@ -4135,7 +4169,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)) @@ -4176,7 +4210,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) @@ -4305,7 +4339,8 @@ static void P_Boss2Thinker(mobj_t *mobj) { mobj->flags &= ~MF_NOGRAVITY; A_Boss2Pogo(mobj); - P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); + if (mobj->spawnpoint) + P_LinedefExecute(mobj->spawnpoint->args[4], mobj, NULL); } } @@ -4434,7 +4469,8 @@ static void P_Boss3Thinker(mobj_t *mobj) dummy->cusval = mobj->cusval; CONS_Debug(DBG_GAMELOGIC, "Eggman path %d - Dummy selected paths %d and %d\n", way0, way1, way2); - P_LinedefExecute(LE_PINCHPHASE+(mobj->cusval*LE_PARAMWIDTH), mobj, NULL); + if (mobj->spawnpoint) + P_LinedefExecute(mobj->spawnpoint->args[3], mobj, NULL); } } else if (mobj->movecount) // Firing mode @@ -4476,27 +4512,21 @@ static void P_Boss3Thinker(mobj_t *mobj) if (!(mobj->flags2 & MF2_STRONGBOX)) { - thinker_t *th; mobj_t *mo2; + INT32 i; P_SetTarget(&mobj->tracer, NULL); - // scan the thinkers - // to find a point that matches - // the number - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + // Find waypoint + TAG_ITER_THINGS(mobj->cusval, i) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + mo2 = mapthings[i].mobj; - mo2 = (mobj_t *)th; + if (!mo2) + continue; if (mo2->type != MT_BOSS3WAYPOINT) continue; - if (!mo2->spawnpoint) - continue; - if (mo2->spawnpoint->angle != mobj->threshold) - continue; - if (mo2->spawnpoint->extrainfo != mobj->cusval) + if (mapthings[i].args[0] != mobj->threshold) continue; P_SetTarget(&mobj->tracer, mo2); @@ -4600,13 +4630,14 @@ static void P_Boss3Thinker(mobj_t *mobj) // Move Boss4's sectors by delta. static boolean P_Boss4MoveCage(mobj_t *mobj, fixed_t delta) { - const UINT16 tag = 65534 + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0); INT32 snum; sector_t *sector; boolean gotcage = false; - TAG_ITER_DECLARECOUNTER(0); - TAG_ITER_SECTORS(0, tag, snum) + if (!mobj->spawnpoint) + return false; + + TAG_ITER_SECTORS(mobj->spawnpoint->args[4], snum) { sector = §ors[snum]; sector->floorheight += delta; @@ -4685,14 +4716,15 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) // Destroy cage FOFs. static void P_Boss4DestroyCage(mobj_t *mobj) { - const UINT16 tag = 65534 + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0); INT32 snum; size_t a; sector_t *sector, *rsec; ffloor_t *rover; - TAG_ITER_DECLARECOUNTER(0); - TAG_ITER_SECTORS(0, tag, snum) + if (!mobj->spawnpoint) + return; + + TAG_ITER_SECTORS(mobj->spawnpoint->args[4], snum) { sector = §ors[snum]; @@ -4965,13 +4997,15 @@ static void P_Boss4Thinker(mobj_t *mobj) { // Proceed to pinch phase! P_Boss4DestroyCage(mobj); mobj->movedir = 3; - P_LinedefExecute(LE_PINCHPHASE + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0), mobj, NULL); + if (mobj->spawnpoint) + P_LinedefExecute(mobj->spawnpoint->args[4], mobj, NULL); P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); var1 = 3; A_BossJetFume(mobj); return; } - P_LinedefExecute(LE_BOSS4DROP - (mobj->info->spawnhealth-mobj->health) + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0), mobj, NULL); + if (mobj->spawnpoint) + P_LinedefExecute(mobj->spawnpoint->args[5] - (mobj->info->spawnhealth-mobj->health), mobj, NULL); // 1 -> 1.5 second timer mobj->threshold = TICRATE+(TICRATE*(mobj->info->spawnhealth-mobj->health)/10); if (mobj->threshold < 1) @@ -5003,7 +5037,8 @@ static void P_Boss4Thinker(mobj_t *mobj) { // Proceed to pinch phase! P_Boss4DestroyCage(mobj); mobj->movedir = 3; - P_LinedefExecute(LE_PINCHPHASE + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0), mobj, NULL); + if (mobj->spawnpoint) + P_LinedefExecute(mobj->spawnpoint->args[4], mobj, NULL); var1 = 3; A_BossJetFume(mobj); return; @@ -5143,7 +5178,8 @@ static void P_Boss7Thinker(mobj_t *mobj) // Begin platform destruction mobj->flags2 |= MF2_FRET; P_SetMobjState(mobj, mobj->info->raisestate); - P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); + if (mobj->spawnpoint) + P_LinedefExecute(mobj->spawnpoint->args[4], mobj, NULL); } } else if (mobj->state == &states[S_BLACKEGG_HITFACE4] && mobj->tics == mobj->state->tics) @@ -5233,11 +5269,10 @@ static void P_Boss7Thinker(mobj_t *mobj) fixed_t vertical, horizontal; fixed_t airtime = 5*TICRATE; INT32 waypointNum = 0; - thinker_t *th; - INT32 i; + INT32 i, j; boolean foundgoop = false; INT32 closestNum; - UINT8 extrainfo = (mobj->spawnpoint ? mobj->spawnpoint->extrainfo : 0); + UINT8 bossid = (mobj->spawnpoint ? mobj->spawnpoint->args[0] : 0); // Looks for players in goop. If you find one, try to jump on him. for (i = 0; i < MAXPLAYERS; i++) @@ -5257,19 +5292,15 @@ static void P_Boss7Thinker(mobj_t *mobj) closestdist = INT32_MAX; // Just in case... // Find waypoint he is closest to - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + TAG_ITER_THINGS(bossid, j) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + mo2 = mapthings[j].mobj; - mo2 = (mobj_t *)th; + if (!mo2) + continue; if (mo2->type != MT_BOSS3WAYPOINT) continue; - if (!mo2->spawnpoint) - continue; - if (mo2->spawnpoint->extrainfo != extrainfo) - continue; - if (mobj->health <= mobj->info->damage && !(mo2->spawnpoint->options & 7)) + if (mobj->health <= mobj->info->damage && !mapthings[j].args[1]) continue; // don't jump to center dist = P_AproxDistance(players[i].mo->x - mo2->x, players[i].mo->y - mo2->y); @@ -5277,7 +5308,7 @@ static void P_Boss7Thinker(mobj_t *mobj) if (!(closestNum == -1 || dist < closestdist)) continue; - closestNum = (mo2->spawnpoint->options & 7); + closestNum = mapthings[j].args[1]; closestdist = dist; foundgoop = true; } @@ -5297,7 +5328,7 @@ static void P_Boss7Thinker(mobj_t *mobj) } if (mobj->tracer && mobj->tracer->type == MT_BOSS3WAYPOINT - && mobj->tracer->spawnpoint && (mobj->tracer->spawnpoint->options & 7) == waypointNum) + && mobj->tracer->spawnpoint && mobj->tracer->spawnpoint->args[1] == waypointNum) { if (P_RandomChance(FRACUNIT/2)) waypointNum++; @@ -5310,28 +5341,25 @@ static void P_Boss7Thinker(mobj_t *mobj) waypointNum = ((waypointNum + 5) % 5); } - // scan the thinkers to find - // the waypoint to use - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + // Scan mapthings to find the waypoint to use + TAG_ITER_THINGS(bossid, i) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + mo2 = mapthings[i].mobj; + + if (!mo2) continue; - mo2 = (mobj_t *)th; if (mo2->type != MT_BOSS3WAYPOINT) continue; - if (!mo2->spawnpoint) - continue; - if ((mo2->spawnpoint->options & 7) != waypointNum) - continue; - if (mo2->spawnpoint->extrainfo != extrainfo) + + if (mapthings[i].args[1] != waypointNum) continue; hitspot = mo2; break; } - if (hitspot == NULL) + if (!hitspot) { CONS_Debug(DBG_GAMELOGIC, "BlackEggman unable to find waypoint #%d!\n", waypointNum); P_SetMobjState(mobj, mobj->info->spawnstate); @@ -6000,7 +6028,8 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->watertop = mobj->floorz + 16*FRACUNIT; else mobj->watertop = mobj->target->floorz + 16*FRACUNIT; - P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); + if (mobj->spawnpoint) + P_LinedefExecute(mobj->spawnpoint->args[4], mobj, NULL); #if 0 whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct @@ -6836,7 +6865,7 @@ void P_RunOverlays(void) mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP) | (mo->target->eflags & MFE_VERTICALFLIP); mo->scale = mo->destscale = mo->target->scale; - mo->angle = mo->target->angle + mo->movedir; + mo->angle = (mo->target->player ? mo->target->player->drawangle : mo->target->angle) + mo->movedir; if (!(mo->state->frame & FF_ANIMATE)) zoffs = FixedMul(((signed)mo->state->var2)*FRACUNIT, mo->scale); @@ -6899,7 +6928,6 @@ static void P_RemoveOverlay(mobj_t *thing) } } -void A_BossDeath(mobj_t *mo); // AI for the Koopa boss. static void P_KoopaThinker(mobj_t *koopa) { @@ -6907,7 +6935,8 @@ static void P_KoopaThinker(mobj_t *koopa) if (koopa->watertop > koopa->z + koopa->height + FixedMul(128*FRACUNIT, koopa->scale) && koopa->health > 0) { - A_BossDeath(koopa); + if (koopa->spawnpoint) + EV_DoCeiling(koopa->spawnpoint->args[0], NULL, raiseToHighest); P_RemoveMobj(koopa); return; } @@ -7025,6 +7054,8 @@ static void P_PyreFlyBurn(mobj_t *mobj, fixed_t hoffs, INT16 vrange, mobjtype_t fixed_t zoffs = P_RandomRange(-vrange, vrange)*FRACUNIT; mobj_t *particle = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, zoffs, mobjtype); particle->momz = momz; + particle->flags2 |= MF2_LINKDRAW; + P_SetTarget(&particle->tracer, mobj); } static void P_MobjScaleThink(mobj_t *mobj) @@ -7189,8 +7220,7 @@ static void P_FlameJetSceneryThink(mobj_t *mobj) else flame->angle += FixedAngle(mobj->fuse<movedir; + strength = (mobj->movedir ? mobj->movedir : 80)<<(FRACBITS-2); P_InstaThrust(flame, flame->angle, strength); S_StartSound(flame, sfx_fire); @@ -7220,8 +7250,7 @@ static void P_VerticalFlameJetSceneryThink(mobj_t *mobj) flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); - strength = 20*FRACUNIT; - strength -= ((20*FRACUNIT)/16)*mobj->movedir; + strength = (mobj->movedir ? mobj->movedir : 80)<<(FRACBITS-2); // If deaf'd, the object spawns on the ceiling. if (mobj->flags2 & MF2_AMBUSH) @@ -7255,8 +7284,22 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj) mobj->fuse = (tic_t)mobj->reactiontime; - bottomheight = lines[line].frontsector->floorheight; - topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; + if (line != -1) + { + bottomheight = lines[line].frontsector->floorheight; + topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; + } + else if (mobj->flags2 & MF2_OBJECTFLIP) + { + bottomheight = mobj->z - mobj->extravalue1; + topheight = mobj->z - mobjinfo[(mobjtype_t)type].height; + } + else + { + bottomheight = mobj->z; + topheight = mobj->z + mobj->extravalue1 - mobjinfo[(mobjtype_t)type].height; + } + if (mobj->waterbottom != bottomheight || mobj->watertop != topheight) { @@ -7265,7 +7308,8 @@ static boolean P_ParticleGenSceneryThink(mobj_t *mobj) else mobj->health = 0; - mobj->z = ((mobj->flags2 & MF2_OBJECTFLIP) ? topheight : bottomheight); + if (line != -1) + mobj->z = ((mobj->flags2 & MF2_OBJECTFLIP) ? topheight : bottomheight); } if (!mobj->health) @@ -7307,7 +7351,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; @@ -7509,7 +7553,7 @@ static void P_RosySceneryThink(mobj_t *mobj) static void P_MobjSceneryThink(mobj_t *mobj) { - if (LUAh_MobjThinker(mobj)) + if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker))) return; if (P_MobjWasRemoved(mobj)) return; @@ -7704,7 +7748,8 @@ static void P_MobjSceneryThink(mobj_t *mobj) break; case MT_WATERDROP: P_SceneryCheckWater(mobj); - if ((mobj->z <= mobj->floorz || mobj->z <= mobj->watertop) + if (((!(mobj->eflags & MFE_VERTICALFLIP) && (mobj->z <= mobj->floorz || mobj->z <= mobj->watertop)) + || (mobj->eflags & MFE_VERTICALFLIP && mobj->z + mobj->height >= mobj->ceilingz)) && mobj->health > 0) { mobj->health = 0; @@ -7827,7 +7872,8 @@ static void P_MobjSceneryThink(mobj_t *mobj) case MT_WOODDEBRIS: case MT_BRICKDEBRIS: case MT_BROKENROBOT: - if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) + if (((!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height)) + || (mobj->eflags & MFE_VERTICALFLIP && mobj->z + mobj->height >= P_CeilingzAtPos(mobj->x, mobj->y, mobj->z, mobj->height))) && mobj->state != &states[mobj->info->deathstate]) { P_SetMobjState(mobj, mobj->info->deathstate); @@ -7857,7 +7903,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) if (!mobj->fuse) { - if (!LUAh_MobjFuse(mobj)) + if (!LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse))) P_RemoveMobj(mobj); return; } @@ -7899,6 +7945,9 @@ static void P_MobjSceneryThink(mobj_t *mobj) P_SetScale(mobj, mobj->target->scale); } break; + case MT_TUTORIALFLOWER: + mobj->angle += FixedAngle(3*FRACUNIT); + break; case MT_VWREF: case MT_VWREB: { @@ -7916,7 +7965,7 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->fuse--; if (!mobj->fuse) { - if (!LUAh_MobjFuse(mobj)) + if (!LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse))) P_RemoveMobj(mobj); return; } @@ -7945,7 +7994,7 @@ static boolean P_MobjPushableThink(mobj_t *mobj) static boolean P_MobjBossThink(mobj_t *mobj) { - if (LUAh_BossThinker(mobj)) + if (LUA_HookMobj(mobj, MOBJ_HOOK(BossThinker))) { if (P_MobjWasRemoved(mobj)) return false; @@ -8393,7 +8442,10 @@ static boolean P_HangsterThink(mobj_t *mobj) } //after swooping back up, check for ceiling else if ((st == S_HANGSTER_RETURN1 || st == S_HANGSTER_RETURN2) && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height)) + { P_SetMobjState(mobj, (st = S_HANGSTER_RETURN3)); + mobj->momx = mobj->momy = 0; + } //should you roost on a ceiling with F_SKY1 as its flat, disappear forever if (st == S_HANGSTER_RETURN3 && mobj->momz == 0 && mobj->ceilingz == (mobj->z + mobj->height) @@ -8540,9 +8592,9 @@ static boolean P_EggRobo1Think(mobj_t *mobj) { fixed_t basex = mobj->cusval, basey = mobj->cvmem; - if (mobj->spawnpoint && mobj->spawnpoint->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) + if (mobj->spawnpoint && mobj->spawnpoint->args[0] != TMED_NONE) { - angle_t sideang = mobj->movedir + ((mobj->spawnpoint->options & MTF_AMBUSH) ? ANGLE_90 : -ANGLE_90); + angle_t sideang = mobj->movedir + ((mobj->spawnpoint->args[0] == TMED_LEFT) ? ANGLE_90 : -ANGLE_90); fixed_t oscillate = FixedMul(FINESINE(((leveltime * ANG1) >> (ANGLETOFINESHIFT + 2)) & FINEMASK), 250*mobj->scale); basex += P_ReturnThrustX(mobj, sideang, oscillate); basey += P_ReturnThrustY(mobj, sideang, oscillate); @@ -8637,245 +8689,242 @@ static boolean P_EggRobo1Think(mobj_t *mobj) static void P_NiGHTSDroneThink(mobj_t *mobj) { + mobj_t *goalpost = NULL; + mobj_t *sparkle = NULL; + mobj_t *droneman = NULL; + + boolean flip = mobj->flags2 & MF2_OBJECTFLIP; + boolean topaligned = (mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); + boolean middlealigned = (mobj->flags & MF_GRENADEBOUNCE) && !(mobj->flags & MF_SLIDEME); + boolean bottomoffsetted = !(mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); + boolean flipchanged = false; + + fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff; + + if (mobj->target && mobj->target->type == MT_NIGHTSDRONE_GOAL) { - // variable setup - mobj_t *goalpost = NULL; - mobj_t *sparkle = NULL; - mobj_t *droneman = NULL; + goalpost = mobj->target; + if (goalpost->target && goalpost->target->type == MT_NIGHTSDRONE_SPARKLING) + sparkle = goalpost->target; + if (goalpost->tracer && goalpost->tracer->type == MT_NIGHTSDRONE_MAN) + droneman = goalpost->tracer; + } - boolean flip = mobj->flags2 & MF2_OBJECTFLIP; - boolean topaligned = (mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); - boolean middlealigned = (mobj->flags & MF_GRENADEBOUNCE) && !(mobj->flags & MF_SLIDEME); - boolean bottomoffsetted = !(mobj->flags & MF_SLIDEME) && !(mobj->flags & MF_GRENADEBOUNCE); - boolean flipchanged = false; + if (!goalpost || !sparkle || !droneman) + return; - fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff; + // did NIGHTSDRONE position, scale, flip, or flags change? all elements need to be synced + droneboxmandiff = max(mobj->height - droneman->height, 0); + dronemangoaldiff = max(droneman->height - goalpost->height, 0); - if (mobj->target && mobj->target->type == MT_NIGHTSDRONE_GOAL) + if (!(goalpost->flags2 & MF2_OBJECTFLIP) && (mobj->flags2 & MF2_OBJECTFLIP)) + { + goalpost->eflags |= MFE_VERTICALFLIP; + goalpost->flags2 |= MF2_OBJECTFLIP; + sparkle->eflags |= MFE_VERTICALFLIP; + sparkle->flags2 |= MF2_OBJECTFLIP; + droneman->eflags |= MFE_VERTICALFLIP; + droneman->flags2 |= MF2_OBJECTFLIP; + flipchanged = true; + } + else if ((goalpost->flags2 & MF2_OBJECTFLIP) && !(mobj->flags2 & MF2_OBJECTFLIP)) + { + goalpost->eflags &= ~MFE_VERTICALFLIP; + goalpost->flags2 &= ~MF2_OBJECTFLIP; + sparkle->eflags &= ~MFE_VERTICALFLIP; + sparkle->flags2 &= ~MF2_OBJECTFLIP; + droneman->eflags &= ~MFE_VERTICALFLIP; + droneman->flags2 &= ~MF2_OBJECTFLIP; + flipchanged = true; + } + + if (goalpost->destscale != mobj->destscale + || goalpost->movefactor != mobj->z + || goalpost->friction != mobj->height + || flipchanged + || goalpost->threshold != (INT32)(mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE))) + { + goalpost->destscale = sparkle->destscale = droneman->destscale = mobj->destscale; + + // straight copy-pasta from P_SpawnMapThing, case MT_NIGHTSDRONE + if (!flip) { - goalpost = mobj->target; - if (goalpost->target && goalpost->target->type == MT_NIGHTSDRONE_SPARKLING) - sparkle = goalpost->target; - if (goalpost->tracer && goalpost->tracer->type == MT_NIGHTSDRONE_MAN) - droneman = goalpost->tracer; - } - - if (!goalpost || !sparkle || !droneman) - return; - - // did NIGHTSDRONE position, scale, flip, or flags change? all elements need to be synced - droneboxmandiff = max(mobj->height - droneman->height, 0); - dronemangoaldiff = max(droneman->height - goalpost->height, 0); - - if (!(goalpost->flags2 & MF2_OBJECTFLIP) && (mobj->flags2 & MF2_OBJECTFLIP)) - { - goalpost->eflags |= MFE_VERTICALFLIP; - goalpost->flags2 |= MF2_OBJECTFLIP; - sparkle->eflags |= MFE_VERTICALFLIP; - sparkle->flags2 |= MF2_OBJECTFLIP; - droneman->eflags |= MFE_VERTICALFLIP; - droneman->flags2 |= MF2_OBJECTFLIP; - flipchanged = true; - } - else if ((goalpost->flags2 & MF2_OBJECTFLIP) && !(mobj->flags2 & MF2_OBJECTFLIP)) - { - goalpost->eflags &= ~MFE_VERTICALFLIP; - goalpost->flags2 &= ~MF2_OBJECTFLIP; - sparkle->eflags &= ~MFE_VERTICALFLIP; - sparkle->flags2 &= ~MF2_OBJECTFLIP; - droneman->eflags &= ~MFE_VERTICALFLIP; - droneman->flags2 &= ~MF2_OBJECTFLIP; - flipchanged = true; - } - - if (goalpost->destscale != mobj->destscale - || goalpost->movefactor != mobj->z - || goalpost->friction != mobj->height - || flipchanged - || goalpost->threshold != (INT32)(mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE))) - { - goalpost->destscale = sparkle->destscale = droneman->destscale = mobj->destscale; - - // straight copy-pasta from P_SpawnMapThing, case MT_NIGHTSDRONE - if (!flip) + if (topaligned) // Align droneman to top of hitbox { - if (topaligned) // Align droneman to top of hitbox - { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff/2; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = 24*FRACUNIT; - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = 0; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - - sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale); + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (middlealigned) // Align droneman to center of hitbox + { + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + } + else if (bottomoffsetted) + { + dronemanoffset = 24*FRACUNIT; + goaloffset = dronemangoaldiff + dronemanoffset; } else { - if (topaligned) // Align droneman to top of hitbox - { - dronemanoffset = 0; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff/2; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - - sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; } - P_TeleportMove(goalpost, mobj->x, mobj->y, mobj->z + goaloffset); - P_TeleportMove(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset); - if (goalpost->movefactor != mobj->z || goalpost->friction != mobj->height) - { - P_TeleportMove(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset); - goalpost->movefactor = mobj->z; - goalpost->friction = mobj->height; - } - goalpost->threshold = mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE); + sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale); } else { - if (goalpost->x != mobj->x || goalpost->y != mobj->y) + if (topaligned) // Align droneman to top of hitbox { - P_TeleportMove(goalpost, mobj->x, mobj->y, goalpost->z); - P_TeleportMove(sparkle, mobj->x, mobj->y, sparkle->z); + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; } - - if (droneman->x != mobj->x || droneman->y != mobj->y) - P_TeleportMove(droneman, mobj->x, mobj->y, - droneman->z >= mobj->floorz && droneman->z <= mobj->ceilingz ? droneman->z : mobj->z); - } - - // now toggle states! - // GOAL mode? - if (sparkle->state >= &states[S_NIGHTSDRONE_SPARKLING1] && sparkle->state <= &states[S_NIGHTSDRONE_SPARKLING16]) - { - INT32 i; - boolean bonustime = false; - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) - { - bonustime = true; - break; - } - - if (!bonustime) + else if (middlealigned) // Align droneman to center of hitbox { - CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); - if (goalpost && goalpost->state != &states[S_INVISIBLE]) - P_SetMobjState(goalpost, S_INVISIBLE); - if (sparkle && sparkle->state != &states[S_INVISIBLE]) - P_SetMobjState(sparkle, S_INVISIBLE); + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; } - } - // Invisible/bouncing mode. - else - { - INT32 i; - boolean bonustime = false; - fixed_t zcomp; - - // Bouncy bouncy! - if (!flip) + else if (bottomoffsetted) { - if (topaligned) - zcomp = droneboxmandiff + mobj->z; - else if (middlealigned) - zcomp = (droneboxmandiff/2) + mobj->z; - else if (bottomoffsetted) - zcomp = mobj->z + FixedMul(24*FRACUNIT, mobj->scale); - else - zcomp = mobj->z; + dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); + goaloffset = dronemangoaldiff + dronemanoffset; } else { - if (topaligned) - zcomp = mobj->z; - else if (middlealigned) - zcomp = (droneboxmandiff/2) + mobj->z; - else if (bottomoffsetted) - zcomp = mobj->z + droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); - else - zcomp = mobj->z + droneboxmandiff; + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; } - droneman->angle += ANG10; - if (!flip && droneman->z <= zcomp) - droneman->momz = FixedMul(5*FRACUNIT, droneman->scale); - else if (flip && droneman->z >= zcomp) - droneman->momz = FixedMul(-5*FRACUNIT, droneman->scale); + sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); + } - // state switching logic + P_TeleportMove(goalpost, mobj->x, mobj->y, mobj->z + goaloffset); + P_TeleportMove(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset); + if (goalpost->movefactor != mobj->z || goalpost->friction != mobj->height) + { + P_TeleportMove(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset); + goalpost->movefactor = mobj->z; + goalpost->friction = mobj->height; + } + goalpost->threshold = mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE); + } + else + { + if (goalpost->x != mobj->x || goalpost->y != mobj->y) + { + P_TeleportMove(goalpost, mobj->x, mobj->y, goalpost->z); + P_TeleportMove(sparkle, mobj->x, mobj->y, sparkle->z); + } + + if (droneman->x != mobj->x || droneman->y != mobj->y) + P_TeleportMove(droneman, mobj->x, mobj->y, + droneman->z >= mobj->floorz && droneman->z <= mobj->ceilingz ? droneman->z : mobj->z); + } + + // now toggle states! + // GOAL mode? + if (sparkle->state >= &states[S_NIGHTSDRONE_SPARKLING1] && sparkle->state <= &states[S_NIGHTSDRONE_SPARKLING16]) + { + INT32 i; + boolean bonustime = false; + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) + { + bonustime = true; + break; + } + + if (!bonustime) + { + CONS_Debug(DBG_NIGHTSBASIC, "Removing goal post\n"); + if (goalpost && goalpost->state != &states[S_INVISIBLE]) + P_SetMobjState(goalpost, S_INVISIBLE); + if (sparkle && sparkle->state != &states[S_INVISIBLE]) + P_SetMobjState(sparkle, S_INVISIBLE); + } + } + // Invisible/bouncing mode. + else + { + INT32 i; + boolean bonustime = false; + fixed_t zcomp; + + // Bouncy bouncy! + if (!flip) + { + if (topaligned) + zcomp = droneboxmandiff + mobj->z; + else if (middlealigned) + zcomp = (droneboxmandiff/2) + mobj->z; + else if (bottomoffsetted) + zcomp = mobj->z + FixedMul(24*FRACUNIT, mobj->scale); + else + zcomp = mobj->z; + } + else + { + if (topaligned) + zcomp = mobj->z; + else if (middlealigned) + zcomp = (droneboxmandiff/2) + mobj->z; + else if (bottomoffsetted) + zcomp = mobj->z + droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); + else + zcomp = mobj->z + droneboxmandiff; + } + + droneman->angle += ANG10; + if (!flip && droneman->z <= zcomp) + droneman->momz = FixedMul(5*FRACUNIT, droneman->scale); + else if (flip && droneman->z >= zcomp) + droneman->momz = FixedMul(-5*FRACUNIT, droneman->scale); + + // state switching logic + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) + { + bonustime = true; + break; + } + + if (bonustime) + { + CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n"); + if (!(droneman->flags2 & MF2_DONTDRAW)) + droneman->flags2 |= MF2_DONTDRAW; + if (goalpost->state == &states[S_INVISIBLE]) + P_SetMobjState(goalpost, mobjinfo[goalpost->type].meleestate); + if (sparkle->state == &states[S_INVISIBLE]) + P_SetMobjState(sparkle, mobjinfo[sparkle->type].meleestate); + } + else if (!G_IsSpecialStage(gamemap)) + { for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].bonustime && players[i].powers[pw_carry] == CR_NIGHTSMODE) + if (playeringame[i] && players[i].powers[pw_carry] != CR_NIGHTSMODE) { - bonustime = true; + bonustime = true; // variable reuse break; } if (bonustime) { - CONS_Debug(DBG_NIGHTSBASIC, "Adding goal post\n"); + // show droneman if at least one player is non-nights + if (goalpost->state != &states[S_INVISIBLE]) + P_SetMobjState(goalpost, S_INVISIBLE); + if (sparkle->state != &states[S_INVISIBLE]) + P_SetMobjState(sparkle, S_INVISIBLE); + if (droneman->state != &states[mobjinfo[droneman->type].meleestate]) + P_SetMobjState(droneman, mobjinfo[droneman->type].meleestate); + if (droneman->flags2 & MF2_DONTDRAW) + droneman->flags2 &= ~MF2_DONTDRAW; + } + else + { + // else, hide it if (!(droneman->flags2 & MF2_DONTDRAW)) droneman->flags2 |= MF2_DONTDRAW; - if (goalpost->state == &states[S_INVISIBLE]) - P_SetMobjState(goalpost, mobjinfo[goalpost->type].meleestate); - if (sparkle->state == &states[S_INVISIBLE]) - P_SetMobjState(sparkle, mobjinfo[sparkle->type].meleestate); - } - else if (!G_IsSpecialStage(gamemap)) - { - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i] && players[i].powers[pw_carry] != CR_NIGHTSMODE) - { - bonustime = true; // variable reuse - break; - } - - if (bonustime) - { - // show droneman if at least one player is non-nights - if (goalpost->state != &states[S_INVISIBLE]) - P_SetMobjState(goalpost, S_INVISIBLE); - if (sparkle->state != &states[S_INVISIBLE]) - P_SetMobjState(sparkle, S_INVISIBLE); - if (droneman->state != &states[mobjinfo[droneman->type].meleestate]) - P_SetMobjState(droneman, mobjinfo[droneman->type].meleestate); - if (droneman->flags2 & MF2_DONTDRAW) - droneman->flags2 &= ~MF2_DONTDRAW; - } - else - { - // else, hide it - if (!(droneman->flags2 & MF2_DONTDRAW)) - droneman->flags2 |= MF2_DONTDRAW; - } } } } @@ -9194,6 +9243,118 @@ static void P_DragonbomberThink(mobj_t *mobj) #undef DRAGONTURNSPEED } +static mobj_t *pushmobj; + +#define PUSH_FACTOR 7 + +static inline boolean PIT_PushThing(mobj_t *thing) +{ + if (thing->eflags & MFE_PUSHED) + return false; + + if (thing->player && thing->player->powers[pw_carry] == CR_ROPEHANG) + return false; + + if (!pushmobj) + return false; + + if (!pushmobj->spawnpoint) + return false; + + // Allow this to affect pushable objects at some point? + if (thing->player && !(thing->flags & (MF_NOGRAVITY|MF_NOCLIP))) + { + INT32 dist; + INT32 speed; + INT32 sx = pushmobj->x; + INT32 sy = pushmobj->y; + INT32 sz = pushmobj->z; + fixed_t radius = pushmobj->spawnpoint->args[0] << FRACBITS; + + if (pushmobj->spawnpoint->args[2] & TMPP_NOZFADE) + dist = P_AproxDistance(thing->x - sx, thing->y - sy); + else + { + // Make sure the Z is in range + if (thing->z < sz - radius || thing->z > sz + radius) + return false; + + dist = P_AproxDistance(P_AproxDistance(thing->x - sx, thing->y - sy), thing->z - sz); + } + + speed = (abs(pushmobj->spawnpoint->args[1]) - ((dist>>FRACBITS)>>1))<<(FRACBITS - PUSH_FACTOR - 1); + + // If speed <= 0, you're outside the effective radius. You also have + // to be able to see the push/pull source point. + + // Written with bits and pieces of P_HomingAttack + if ((speed > 0) && (P_CheckSight(thing, pushmobj))) + { + fixed_t tmpmomx, tmpmomy, tmpmomz; + + if (pushmobj->spawnpoint->args[2] & TMPP_PUSHZ) + { + tmpmomx = FixedMul(FixedDiv(sx - thing->x, dist), speed); + tmpmomy = FixedMul(FixedDiv(sy - thing->y, dist), speed); + tmpmomz = FixedMul(FixedDiv(sz - thing->z, dist), speed); + } + else + { + angle_t pushangle = R_PointToAngle2(thing->x, thing->y, sx, sy) >> ANGLETOFINESHIFT; + tmpmomx = FixedMul(speed, FINECOSINE(pushangle)); + tmpmomy = FixedMul(speed, FINESINE(pushangle)); + tmpmomz = 0; + } + + if (pushmobj->spawnpoint->args[1] > 0) // away! + { + tmpmomx *= -1; + tmpmomy *= -1; + tmpmomz *= -1; + } + + thing->momx += tmpmomx; + thing->momy += tmpmomy; + thing->momz += tmpmomz; + + if (thing->player) + { + thing->player->cmomx += tmpmomx; + thing->player->cmomy += tmpmomy; + thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); + thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); + } + } + } + + if (!(pushmobj->spawnpoint->args[2] & TMPP_NONEXCLUSIVE)) + thing->eflags |= MFE_PUSHED; + + return true; +} + +static void P_PointPushThink(mobj_t *mobj) +{ + INT32 xl, xh, yl, yh, bx, by; + fixed_t radius; + + if (!mobj->spawnpoint) + return; + + // Seek out all pushable things within the force radius of this + // point pusher. Crosses sectors, so use blockmap. + radius = mobj->spawnpoint->args[0] << FRACBITS; + + pushmobj = mobj; + xl = (unsigned)(mobj->x - radius - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; + xh = (unsigned)(mobj->x + radius - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; + yl = (unsigned)(mobj->y - radius - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; + yh = (unsigned)(mobj->y + radius - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; + for (bx = xl; bx <= xh; bx++) + for (by = yl; by <= yh; by++) + P_BlockThingsIterator(bx, by, PIT_PushThing); +} + static boolean P_MobjRegularThink(mobj_t *mobj) { if ((mobj->flags & MF_ENEMY) && (mobj->state->nextstate == mobj->info->spawnstate && mobj->tics == 1)) @@ -9205,7 +9366,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) switch (mobj->type) { case MT_WALLSPIKEBASE: - if (!mobj->target) { + if (!mobj->target) + { P_RemoveMobj(mobj); return false; } @@ -9572,13 +9734,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj) break; case MT_BLUEFLAG: case MT_REDFLAG: - { - sector_t* sec2; - sec2 = P_ThingOnSpecial3DFloor(mobj); - if ((sec2 && GETSECSPECIAL(sec2->special, 4) == 2) || (GETSECSPECIAL(mobj->subsector->sector->special, 4) == 2)) + if (P_MobjTouchingSectorSpecialFlag(mobj, SSF_RETURNFLAG)) mobj->fuse = 1; // Return to base. break; - } case MT_SPINDUST: // Spindash dust mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same @@ -9683,7 +9841,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (P_IsObjectOnGround(mobj)) mobj->rollangle = 0; else - mobj->rollangle = R_PointToAngle2(0, 0, mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1)); + mobj->rollangle = R_PointToAngle2(0, 0, P_MobjFlip(mobj)*mobj->momz, (mobj->scale << 1) - min(abs(mobj->momz), mobj->scale << 1)); + break; + case MT_PUSH: + P_PointPushThink(mobj); break; case MT_SPINFIRE: if (mobj->flags & MF_NOGRAVITY) @@ -9837,7 +9998,7 @@ static void P_FlagFuseThink(mobj_t *mobj) if (mobj->type == MT_REDFLAG) { if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80); + CONS_Printf(M_GetText("The \205Red flag\200 has returned to base.\n")); // Assumedly in splitscreen players will be on opposing teams if (players[consoleplayer].ctfteam == 1 || splitscreen) @@ -9850,7 +10011,7 @@ static void P_FlagFuseThink(mobj_t *mobj) else // MT_BLUEFLAG { if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80); + CONS_Printf(M_GetText("The \204Blue flag\200 has returned to base.\n")); // Assumedly in splitscreen players will be on opposing teams if (players[consoleplayer].ctfteam == 2 || splitscreen) @@ -9872,7 +10033,7 @@ static boolean P_FuseThink(mobj_t *mobj) if (mobj->fuse) return true; - if (LUAh_MobjFuse(mobj) || P_MobjWasRemoved(mobj)) + if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse)) || P_MobjWasRemoved(mobj)) ; else if (mobj->info->flags & MF_MONITOR) { @@ -9909,16 +10070,9 @@ static boolean P_FuseThink(mobj_t *mobj) case MT_METALSONIC_BATTLE: break; // don't remove case MT_SPIKE: - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += mobj->spawnpoint->angle; - break; case MT_WALLSPIKE: P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += (mobj->spawnpoint->angle / 360); + mobj->fuse = mobj->spawnpoint ? mobj->spawnpoint->args[0] : mobj->info->speed; break; case MT_NIGHTSCORE: P_RemoveMobj(mobj); @@ -9991,7 +10145,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->flags & MF_NOTHINK) return; - if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<spawnpoint->extrainfo))) + if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<spawnpoint->args[0]))) return; // Remove dead target/tracer. @@ -10008,16 +10162,8 @@ void P_MobjThinker(mobj_t *mobj) tmfloorthing = tmhitthing = NULL; - // Sector special (2,8) allows ANY mobj to trigger a linedef exec - if (mobj->subsector && GETSECSPECIAL(mobj->subsector->sector->special, 2) == 8) - { - sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); - if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1) - { - mtag_t tag = Tag_FGet(&sec2->tags); - P_LinedefExecute(tag, mobj, sec2); - } - } + // Sector flag MSF_TRIGGERLINE_MOBJ allows ANY mobj to trigger a linedef exec + P_CheckMobjTrigger(mobj, false); if (mobj->scale != mobj->destscale) P_MobjScaleThink(mobj); // Slowly scale up/down to reach your destscale. @@ -10048,13 +10194,13 @@ void P_MobjThinker(mobj_t *mobj) // Check for a Lua thinker first if (!mobj->player) { - if (LUAh_MobjThinker(mobj) || P_MobjWasRemoved(mobj)) + if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)) || P_MobjWasRemoved(mobj)) return; } else if (!mobj->player->spectator) { // You cannot short-circuit the player thinker like you can other thinkers. - LUAh_MobjThinker(mobj); + LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)); if (P_MobjWasRemoved(mobj)) return; } @@ -10087,10 +10233,12 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->flags2 & MF2_FIRING) P_FiringThink(mobj); - if (mobj->flags & MF_AMBIENT) + if (mobj->type == MT_AMBIENT) { - if (!(leveltime % mobj->health) && mobj->info->seesound) - S_StartSound(mobj, mobj->info->seesound); + if (leveltime % mobj->health) + return; + if (mobj->threshold) + S_StartSound(mobj, mobj->threshold); return; } @@ -10232,28 +10380,10 @@ boolean P_RailThinker(mobj_t *mobj) // Unquick, unoptimized function for pushables void P_PushableThinker(mobj_t *mobj) { - sector_t *sec; - I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); - sec = mobj->subsector->sector; - - if (GETSECSPECIAL(sec->special, 2) == 1 && mobj->z == sec->floorheight) - { - mtag_t tag = Tag_FGet(&sec->tags); - P_LinedefExecute(tag, mobj, sec); - } - -// else if (GETSECSPECIAL(sec->special, 2) == 8) - { - sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); - if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1) - { - mtag_t tag = Tag_FGet(&sec2->tags); - P_LinedefExecute(tag, mobj, sec2); - } - } + P_CheckMobjTrigger(mobj, true); // it has to be pushable RIGHT NOW for this part to happen if (mobj->flags & MF_PUSHABLE && !(mobj->momx || mobj->momy)) @@ -10372,6 +10502,7 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) switch (thing->type) { case MT_PLAYER: + case MT_METALSONIC_RACE: case MT_ROLLOUTROCK: case MT_EGGMOBILE4_MACE: @@ -10389,6 +10520,9 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) case MT_RING: case MT_FLINGRING: + case MT_COIN: + case MT_FLINGCOIN: + case MT_BLUESPHERE: case MT_FLINGBLUESPHERE: case MT_BOMBSPHERE: @@ -10413,6 +10547,27 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) return 2*FRACUNIT/3; + case MT_FLICKY_01: + case MT_FLICKY_02: + case MT_FLICKY_03: + case MT_FLICKY_04: + case MT_FLICKY_05: + case MT_FLICKY_06: + case MT_FLICKY_07: + case MT_FLICKY_08: + case MT_FLICKY_09: + case MT_FLICKY_10: + case MT_FLICKY_11: + case MT_FLICKY_12: + case MT_FLICKY_13: + case MT_FLICKY_14: + case MT_FLICKY_15: + case MT_FLICKY_16: + case MT_SECRETFLICKY_01: + case MT_SECRETFLICKY_02: + + return FRACUNIT; + default: if (thing->flags & (MF_ENEMY|MF_BOSS)) @@ -10430,7 +10585,24 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) const mobjinfo_t *info = &mobjinfo[type]; SINT8 sc = -1; state_t *st; - mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); + mobj_t *mobj; + + if (type == MT_NULL) + { +#if 0 +#ifdef PARANOIA + I_Error("Tried to spawn MT_NULL\n"); +#endif + return NULL; +#endif + // Hack: Some code assumes that P_SpawnMobj can never return NULL + // So replace MT_NULL with MT_RAY in the meantime + // Remove when dealt properly + CONS_Debug(DBG_GAMELOGIC, "Tried to spawn MT_NULL, using MT_RAY\n"); + type = MT_RAY; + } + + mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); // this is officially a mobj, declared as soon as possible. mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; @@ -10483,9 +10655,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) P_SetThingPosition(mobj); I_Assert(mobj->subsector != NULL); - // Make sure scale matches destscale immediately when spawned - P_SetScale(mobj, mobj->destscale); - mobj->floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y); mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y); @@ -10525,7 +10694,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // DANGER! This can cause P_SpawnMobj to return NULL! // Avoid using P_RemoveMobj on the newly created mobj in "MobjSpawn" Lua hooks! - if (LUAh_MobjSpawn(mobj)) + if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjSpawn))) { if (P_MobjWasRemoved(mobj)) return NULL; @@ -10856,8 +11025,8 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype if (mobj->floorz != starting_floorz) mobj->precipflags |= PCF_FOF; - else if (GETSECSPECIAL(mobj->subsector->sector->special, 1) == 7 - || GETSECSPECIAL(mobj->subsector->sector->special, 1) == 6 + else if (mobj->subsector->sector->damagetype == SD_DEATHPITNOTILT + || mobj->subsector->sector->damagetype == SD_DEATHPITTILT || mobj->subsector->sector->floorpic == skyflatnum) mobj->precipflags |= PCF_PIT; @@ -10912,7 +11081,7 @@ void P_RemoveMobj(mobj_t *mobj) return; // something already removing this mobj. mobj->thinker.function.acp1 = (actionf_p1)P_RemoveThinkerDelayed; // shh. no recursing. - LUAh_MobjRemoved(mobj); + LUA_HookMobj(mobj, MOBJ_HOOK(MobjRemoved)); mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; // needed for P_UnsetThingPosition, etc. to work. // Rings only, please! @@ -11055,7 +11224,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 @@ -11084,7 +11253,7 @@ void P_SpawnPrecipitation(void) if (curWeather == PRECIP_SNOW) { // Not in a sector with visible sky -- exception for NiGHTS. - if ((!(maptol & TOL_NIGHTS) && (precipsector->sector->ceilingpic != skyflatnum)) == !(precipsector->sector->flags & SF_INVERTPRECIP)) + if ((!(maptol & TOL_NIGHTS) && (precipsector->sector->ceilingpic != skyflatnum)) == !(precipsector->sector->flags & MSF_INVERTPRECIP)) continue; rainmo = P_SpawnSnowMobj(x, y, height, MT_SNOWFLAKE); @@ -11097,26 +11266,18 @@ void P_SpawnPrecipitation(void) else // everything else. { // Not in a sector with visible sky. - if ((precipsector->sector->ceilingpic != skyflatnum) == !(precipsector->sector->flags & SF_INVERTPRECIP)) + if ((precipsector->sector->ceilingpic != skyflatnum) == !(precipsector->sector->flags & MSF_INVERTPRECIP)) 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)<z << FRACBITS; - // Flagging a player's ambush will make them start on the ceiling + // Setting the spawnpoint's args[0] will make the player start on the ceiling // Objectflip inverts - if (!!(mthing->options & MTF_AMBUSH) ^ !!(mthing->options & MTF_OBJECTFLIP)) + if (!!(mthing->args[0]) ^ !!(mthing->options & MTF_OBJECTFLIP)) z = ceilingspawn - offset; else z = floor + offset; @@ -11523,7 +11684,7 @@ void P_MovePlayerToSpawn(INT32 playernum, mapthing_t *mthing) mobj->eflags |= MFE_VERTICALFLIP; mobj->flags2 |= MF2_OBJECTFLIP; } - if (mthing->options & MTF_AMBUSH) + if (mthing->args[0]) P_SetPlayerMobjState(mobj, S_PLAY_FALL); else if (metalrecording) P_SetPlayerMobjState(mobj, S_PLAY_WAIT); @@ -11637,11 +11798,6 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt switch (mobjtype) { - // Bumpers never spawn flipped. - case MT_NIGHTSBUMPER: - flip = false; - break; - // Objects with a non-zero default height. case MT_CRAWLACOMMANDER: case MT_DETON: @@ -11661,14 +11817,14 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt dz = 288*FRACUNIT; break; - // Horizontal springs, may float additional units with MTF_AMBUSH. + // Horizontal springs, float additional units unless args[0] is set. case MT_YELLOWHORIZ: case MT_REDHORIZ: case MT_BLUEHORIZ: - offset += mthing->options & MTF_AMBUSH ? 16*FRACUNIT : 0; + offset += mthing->args[0] ? 0 : 16*FRACUNIT; break; - // Ring-like items, may float additional units with MTF_AMBUSH. + // Ring-like items, float additional units unless args[0] is set. case MT_SPIKEBALL: case MT_EMERHUNT: case MT_EMERALDSPAWN: @@ -11682,13 +11838,13 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt case MT_BOMBSPHERE: case MT_NIGHTSCHIP: case MT_NIGHTSSTAR: - offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; + offset += mthing->args[0] ? 0 : 24*FRACUNIT; break; // Remaining objects. default: if (P_WeaponOrPanel(mobjtype)) - offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0; + offset += mthing->args[0] ? 0 : 24*FRACUNIT; } if (!(dz + offset)) // Snap to the surfaces when there's no offset set. @@ -11750,8 +11906,8 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) return true; } else if (mthing->type == 750 // Slope vertex point (formerly chaos spawn) - || (mthing->type >= 600 && mthing->type <= 609) // Special placement patterns - || mthing->type == 1705 || mthing->type == 1713) // Hoops + || (mthing->type >= 600 && mthing->type <= 611) // Special placement patterns + || mthing->type == 1713) // Hoops return true; // These are handled elsewhere. else if (mthing->type == mobjinfo[MT_EMERHUNT].doomednum) { @@ -11795,10 +11951,10 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) runemeraldmanager = true; break; case MT_ROSY: - if (!(G_CoopGametype() || (mthing->options & MTF_EXTRA))) + if (!(G_CoopGametype() || mthing->args[0])) return false; // she doesn't hang out here - if (!mariomode && !(netgame || multiplayer) && players[consoleplayer].skin == 3) + if (!(netgame || multiplayer) && players[consoleplayer].skin == 3) return false; // no doubles break; @@ -11919,7 +12075,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) case 2: // Unchanging if (i == MT_MYSTERY_BOX) return MT_NULL; // don't spawn - mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning! + mthing->args[1] = TMMR_SAME; // no random respawning! return i; case 3: // Don't spawn return MT_NULL; @@ -11949,8 +12105,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i) if (modeattacking && i == MT_1UP_BOX) // 1UPs -->> Score TVs { - // Either or, doesn't matter which. - if (mthing->options & (MTF_AMBUSH | MTF_OBJECTSPECIAL)) + if (mthing->args[2]) return MT_SCORE10K_BOX; // 10,000 else return MT_SCORE1K_BOX; // 1,000 @@ -11964,10 +12119,11 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) INT32 j; emblem_t* emblem = M_GetLevelEmblems(gamemap); skincolornum_t emcolor; + boolean validEmblem = true; while (emblem) { - if ((emblem->type == ET_GLOBAL || emblem->type == ET_SKIN) && emblem->tag == mthing->angle) + if ((emblem->type == ET_GLOBAL || emblem->type == ET_SKIN) && emblem->tag == Tag_FGet(&mthing->tags)) break; emblem = M_GetLevelEmblems(-1); @@ -11975,7 +12131,7 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) if (!emblem) { - CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, mthing->angle); + CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, Tag_FGet(&mthing->tags)); return false; } @@ -11988,8 +12144,19 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj) emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting mobj->color = (UINT16)emcolor; - if (emblemlocations[j].collected - || (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin)) + validEmblem = !emblemlocations[j].collected; + + if (emblemlocations[j].type == ET_SKIN) + { + INT32 skinnum = M_EmblemSkinNum(&emblemlocations[j]); + + if (players[0].skin != skinnum) + { + validEmblem = false; + } + } + + if (validEmblem == false) { P_UnsetThingPosition(mobj); mobj->flags |= MF_NOCLIP; @@ -12026,59 +12193,20 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) mobjflag_t mflagsapply; mobjflag2_t mflags2apply; mobjeflag_t meflagsapply; - INT32 line; const size_t mthingi = (size_t)(mthing - mapthings); - // Find the corresponding linedef special, using angle as tag - line = Tag_FindLineSpecial(9, mthing->angle); - - if (line == -1) - { - CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs to be tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); - return false; - } - /* - mapthing - - MTF_AMBUSH : - MT_SPRINGBALLPOINT - upgrade from yellow to red spring - anything else - bigger mace/chain theory - MTF_OBJECTSPECIAL - force silent - MTF_GRAVFLIP - flips objects, doesn't affect chain arrangements - Parameter value : number of "spokes" - - linedef - - ML_NOCLIMB : - MT_CHAINPOINT/MT_CHAINMACEPOINT with ML_EFFECT1 applied - Direction not controllable - anything else - no functionality - ML_EFFECT1 : Swings instead of spins - ML_EFFECT2 : Linktype is replaced with macetype for all spokes not ending in chains (inverted for MT_FIREBARPOINT) - ML_EFFECT3 : Spawn a bonus linktype at the hinge point - ML_EFFECT4 : Don't clip inside the ground - ML_EFFECT5 : Don't stop thinking when too far away - */ - mlength = abs(lines[line].dx >> FRACBITS); - mspeed = abs(lines[line].dy >> (FRACBITS - 4)); - mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360; - if ((mminlength = -sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) < 0) - mminlength = 0; - else if (mminlength > mlength - 1) - mminlength = mlength - 1; - mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360; - myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360; - - mnumspokes = mthing->extrainfo + 1; + mlength = abs(mthing->args[0]); + mnumspokes = mthing->args[1] + 1; mspokeangle = FixedAngle((360*FRACUNIT)/mnumspokes) >> ANGLETOFINESHIFT; - - if (lines[line].backsector) - { - mpinch = (lines[line].backsector->floorheight >> FRACBITS) % 360; - mroll = (lines[line].backsector->ceilingheight >> FRACBITS) % 360; - mnumnospokes = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS); - if ((mwidth = sides[lines[line].sidenum[1]].rowoffset >> FRACBITS) < 0) - mwidth = 0; - } - else - mpinch = mroll = mnumnospokes = mwidth = 0; + mwidth = max(0, mthing->args[2]); + mspeed = abs(mthing->args[3] << 4); + mphase = mthing->args[4] % 360; + mpinch = mthing->args[5] % 360; + mnumnospokes = mthing->args[6]; + mminlength = max(0, min(mlength - 1, mthing->args[7])); + mpitch = mthing->pitch % 360; + myaw = mthing->angle % 360; + mroll = mthing->roll % 360; CONS_Debug(DBG_GAMELOGIC, "Mace/Chain (mapthing #%s):\n" "Length is %d (minus %d)\n" @@ -12109,26 +12237,23 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) switch (mobj->type) { case MT_SPRINGBALLPOINT: - macetype = ((mthing->options & MTF_AMBUSH) + macetype = ((mthing->args[8] & TMM_DOUBLESIZE) ? MT_REDSPRINGBALL : MT_YELLOWSPRINGBALL); chainlink = MT_SMALLMACECHAIN; break; case MT_FIREBARPOINT: - macetype = ((mthing->options & MTF_AMBUSH) + macetype = ((mthing->args[8] & TMM_DOUBLESIZE) ? MT_BIGFIREBAR : MT_SMALLFIREBAR); chainlink = MT_NULL; break; case MT_CUSTOMMACEPOINT: - macetype = (mobjtype_t)sides[lines[line].sidenum[0]].toptexture; - if (lines[line].backsector) - chainlink = (mobjtype_t)sides[lines[line].sidenum[1]].toptexture; - else - chainlink = MT_NULL; + macetype = mthing->stringargs[0] ? get_number(mthing->stringargs[0]) : MT_NULL; + chainlink = mthing->stringargs[1] ? get_number(mthing->stringargs[1]) : MT_NULL; break; case MT_CHAINPOINT: - if (mthing->options & MTF_AMBUSH) + if (mthing->args[8] & TMM_DOUBLESIZE) { macetype = MT_BIGGRABCHAIN; chainlink = MT_BIGMACECHAIN; @@ -12141,7 +12266,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) mchainlike = true; break; default: - if (mthing->options & MTF_AMBUSH) + if (mthing->args[8] & TMM_DOUBLESIZE) { macetype = MT_BIGMACE; chainlink = MT_BIGMACECHAIN; @@ -12168,11 +12293,11 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) firsttype = macetype; // Adjustable direction - if (lines[line].flags & ML_NOCLIMB) + if (mthing->args[8] & TMM_ALLOWYAWCONTROL) mobj->flags |= MF_SLIDEME; // Swinging - if (lines[line].flags & ML_EFFECT1) + if (mthing->args[8] & TMM_SWING) { mobj->flags2 |= MF2_STRONGBOX; mmin = ((mnumnospokes > 1) ? 1 : 0); @@ -12181,11 +12306,11 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) mmin = mnumspokes; // If over distance away, don't move UNLESS this flag is applied - if (lines[line].flags & ML_EFFECT5) + if (mthing->args[8] & TMM_ALWAYSTHINK) mobj->flags2 |= MF2_BOSSNOTRAP; // Make the links the same type as the end - repeated below - if ((mobj->type != MT_CHAINPOINT) && (((lines[line].flags & ML_EFFECT2) == ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or + if ((mobj->type != MT_CHAINPOINT) && (((mthing->args[8] & TMM_MACELINKS) == TMM_MACELINKS) != (mobj->type == MT_FIREBARPOINT))) // exclusive or { linktype = macetype; radiusfactor = 2; // Double the radius. @@ -12197,7 +12322,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) mchainlike = (firsttype == chainlink); widthfactor = (mchainlike ? 1 : 2); - mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP | MF_NOCLIPHEIGHT)); + mflagsapply = (mthing->args[8] & TMM_CLIP) ? 0 : (MF_NOCLIP|MF_NOCLIPHEIGHT); mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0); meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0); @@ -12223,14 +12348,14 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) hprev = spawnee;\ } - mdosound = (mspeed && !(mthing->options & MTF_OBJECTSPECIAL)); - mdocenter = (macetype && (lines[line].flags & ML_EFFECT3)); + mdosound = (mspeed && !(mthing->args[8] & TMM_SILENT)); + mdocenter = (macetype && (mthing->args[8] & TMM_CENTERLINK)); // The actual spawning of spokes while (mnumspokes-- > 0) { // Offsets - if (lines[line].flags & ML_EFFECT1) // Swinging + if (mthing->args[8] & TMM_SWING) // Swinging mroll = (mroll - mspokeangle) & FINEMASK; else // Spinning mphase = (mphase - mspokeangle) & FINEMASK; @@ -12241,7 +12366,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) continue; linktype = chainlink; - firsttype = ((mthing->options & MTF_AMBUSH) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN); + firsttype = ((mthing->args[8] & TMM_DOUBLESIZE) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN); mmaxlength = 1 + (mlength - 1) * radiusfactor; radiusfactor = widthfactor = 1; } @@ -12250,7 +12375,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) if (mobj->type == MT_CHAINMACEPOINT) { // Make the links the same type as the end - repeated above - if (lines[line].flags & ML_EFFECT2) + if (mthing->args[8] & TMM_MACELINKS) { linktype = macetype; radiusfactor = 2; @@ -12333,50 +12458,43 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) { - fixed_t radius, speed; + fixed_t radius, speed, zdist; INT32 type, numdivisions, anglespeed, ticcount; angle_t angledivision; INT32 line; const size_t mthingi = (size_t)(mthing - mapthings); - // Find the corresponding linedef special, using angle as tag - line = Tag_FindLineSpecial(15, mthing->angle); + // Find the corresponding linedef special, using args[6] as tag + line = mthing->args[6] ? Tag_FindLineSpecial(15, mthing->args[6]) : -1; - if (line == -1) - { - CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs to be tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); - return false; - } + type = mthing->stringargs[0] ? get_number(mthing->stringargs[0]) : MT_PARTICLE; - if (sides[lines[line].sidenum[0]].toptexture) - type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c... - else - type = (INT32)MT_PARTICLE; - - if (!lines[line].backsector - || (ticcount = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS)) < 1) + ticcount = mthing->args[4]; + if (ticcount < 1) ticcount = 3; - numdivisions = mthing->z; + numdivisions = mthing->args[0]; if (numdivisions) { - radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y); - anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360; + radius = mthing->args[1] << FRACBITS; + anglespeed = (mthing->args[3]) % 360; angledivision = 360/numdivisions; } else { - numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler. + numdivisions = 1; // Simple trick to make P_ParticleGenSceneryThink simpler. radius = 0; anglespeed = 0; angledivision = 0; } - speed = abs(sides[lines[line].sidenum[0]].textureoffset); + speed = abs(mthing->args[2]) << FRACBITS; if (mthing->options & MTF_OBJECTFLIP) speed *= -1; + zdist = abs(mthing->args[5]) << FRACBITS; + CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n" "Radius is %d\n" "Speed is %d\n" @@ -12384,9 +12502,14 @@ static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) "Numdivisions is %d\n" "Angledivision is %d\n" "Type is %d\n" - "Tic seperation is %d\n", + "Tic separation is %d\n", sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, type, ticcount); + if (line == -1) + CONS_Debug(DBG_GAMELOGIC, "Spawn Z is %d\nZ dist is %d\n", mobj->z, zdist); + else + CONS_Debug(DBG_GAMELOGIC, "Heights are taken from control sector\n"); + mobj->angle = 0; mobj->movefactor = speed; mobj->lastlook = numdivisions; @@ -12395,21 +12518,19 @@ static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) mobj->friction = radius; mobj->threshold = type; mobj->reactiontime = ticcount; + mobj->extravalue1 = zdist; mobj->cvmem = line; mobj->watertop = mobj->waterbottom = 0; return true; } -static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) +static boolean P_SetupNiGHTSDrone(mapthing_t *mthing, mobj_t *mobj) { boolean flip = mthing->options & MTF_OBJECTFLIP; - boolean topaligned = (mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA); - boolean middlealigned = (mthing->options & MTF_EXTRA) && !(mthing->options & MTF_OBJECTSPECIAL); - boolean bottomoffsetted = !(mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA); - - INT16 timelimit = mthing->angle & 0xFFF; - fixed_t hitboxradius = ((mthing->angle & 0xF000) >> 12)*32*FRACUNIT; - fixed_t hitboxheight = mthing->extrainfo*32*FRACUNIT; + INT16 timelimit = mthing->args[0]; + fixed_t hitboxheight = mthing->args[1] << FRACBITS; + fixed_t hitboxradius = mthing->args[2] << FRACBITS; + INT32 dronemanalignment = mthing->args[3]; fixed_t oldheight = mobj->height; fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff; @@ -12424,6 +12545,9 @@ static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) else mobj->height = mobjinfo[MT_NIGHTSDRONE].height; + if (mthing->args[4]) + mobj->flags2 |= MF2_AMBUSH; //Kill player upon time up + droneboxmandiff = max(mobj->height - mobjinfo[MT_NIGHTSDRONE_MAN].height, 0); dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0); @@ -12432,25 +12556,25 @@ static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) if (!flip) { - if (topaligned) // Align droneman to top of hitbox + switch (dronemanalignment) { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff/2; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = 24*FRACUNIT; - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = 0; - goaloffset = dronemangoaldiff/2 + dronemanoffset; + case TMDA_BOTTOMOFFSET: + default: + dronemanoffset = FixedMul(24*FRACUNIT, mobj->scale); + goaloffset = dronemangoaldiff + dronemanoffset; + break; + case TMDA_BOTTOM: + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + break; + case TMDA_MIDDLE: + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + break; + case TMDA_TOP: + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + break; } sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale); @@ -12460,25 +12584,25 @@ static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) mobj->eflags |= MFE_VERTICALFLIP; mobj->flags2 |= MF2_OBJECTFLIP; - if (topaligned) // Align droneman to top of hitbox + switch (dronemanalignment) { - dronemanoffset = 0; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (middlealigned) // Align droneman to center of hitbox - { - dronemanoffset = droneboxmandiff/2; - goaloffset = dronemangoaldiff/2 + dronemanoffset; - } - else if (bottomoffsetted) - { - dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); - goaloffset = dronemangoaldiff + dronemanoffset; - } - else - { - dronemanoffset = droneboxmandiff; - goaloffset = dronemangoaldiff/2 + dronemanoffset; + case TMDA_BOTTOMOFFSET: + default: + dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale); + goaloffset = dronemangoaldiff + dronemanoffset; + break; + case TMDA_BOTTOM: + dronemanoffset = droneboxmandiff; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + break; + case TMDA_MIDDLE: + dronemanoffset = droneboxmandiff/2; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + break; + case TMDA_TOP: + dronemanoffset = 0; + goaloffset = dronemangoaldiff/2 + dronemanoffset; + break; } sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); @@ -12486,9 +12610,9 @@ static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) // spawn visual elements { - mobj_t* goalpost = P_SpawnMobjFromMobj(mobj, 0, 0, goaloffset, MT_NIGHTSDRONE_GOAL); - mobj_t* sparkle = P_SpawnMobjFromMobj(mobj, 0, 0, sparkleoffset, MT_NIGHTSDRONE_SPARKLING); - mobj_t* droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN); + mobj_t *goalpost = P_SpawnMobjFromMobj(mobj, 0, 0, goaloffset, MT_NIGHTSDRONE_GOAL); + mobj_t *sparkle = P_SpawnMobjFromMobj(mobj, 0, 0, sparkleoffset, MT_NIGHTSDRONE_SPARKLING); + mobj_t *droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN); P_SetTarget(&mobj->target, goalpost); P_SetTarget(&goalpost->target, sparkle); @@ -12504,12 +12628,21 @@ static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) // Remember position preference for later mobj->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE); - if (topaligned) - mobj->flags |= MF_SLIDEME; - else if (middlealigned) - mobj->flags |= MF_GRENADEBOUNCE; - else if (!bottomoffsetted) - mobj->flags |= MF_SLIDEME|MF_GRENADEBOUNCE; + switch (dronemanalignment) + { + case TMDA_BOTTOMOFFSET: + default: + mobj->flags |= MF_SLIDEME|MF_GRENADEBOUNCE; + break; + case TMDA_BOTTOM: + break; + case TMDA_MIDDLE: + mobj->flags |= MF_GRENADEBOUNCE; + break; + case TMDA_TOP: + mobj->flags |= MF_SLIDEME; + break; + } // Remember old Z position and flags for correction detection goalpost->movefactor = mobj->z; @@ -12560,9 +12693,40 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) return true; } +static mobj_t *P_MakeSoftwareCorona(mobj_t *mo, INT32 height) +{ + mobj_t *corona = P_SpawnMobjFromMobj(mo, 0, 0, height<sprite = SPR_FLAM; + corona->frame = (FF_FULLBRIGHT|FF_TRANS90|12); + corona->tics = -1; + return corona; +} + +static boolean P_MapAlreadyHasStarPost(mobj_t *mobj) +{ + thinker_t *th; + mobj_t *mo2; + + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo2 = (mobj_t *)th; + + if (mo2 == mobj) + continue; + + if (mo2->type == MT_STARPOST && mo2->health == mobj->health) + return true; + } + + return false; +} + static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) { - boolean override = LUAh_MapThingSpawn(mobj, mthing); + boolean override = LUA_HookMapThingSpawn(mobj, mthing); if (P_MobjWasRemoved(mobj)) return false; @@ -12587,24 +12751,32 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean break; } - if (mthing->options & MTF_OBJECTSPECIAL) + if (mthing->args[0]) skyboxcenterpnts[tag] = mobj; else skyboxviewpnts[tag] = mobj; break; } case MT_EGGSTATUE: - if (mthing->options & MTF_EXTRA) + if (mthing->args[1]) { mobj->color = SKINCOLOR_GOLD; mobj->colorized = true; } break; + case MT_EGGMOBILE2: + if (!mthing->args[5]) + mobj->flags2 |= MF2_AMBUSH; + break; case MT_EGGMOBILE3: - mobj->cusval = mthing->extrainfo; + mobj->cusval = mthing->args[0]; + break; + case MT_BUBBLES: + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; break; case MT_FAN: - if (mthing->options & MTF_OBJECTSPECIAL) + if (mthing->args[1] & TMF_INVISIBLE) { P_UnsetThingPosition(mobj); if (sector_list) @@ -12615,16 +12787,34 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->flags |= MF_NOSECTOR; // this flag basically turns it invisible P_SetThingPosition(mobj); } - if (mthing->angle) - mobj->health = mthing->angle; + if (mthing->args[1] & TMF_NODISTANCECHECK) + mobj->flags2 |= MF2_AMBUSH; + if (mthing->args[0]) + mobj->health = mthing->args[0]; else mobj->health = FixedMul(mobj->subsector->sector->ceilingheight - mobj->subsector->sector->floorheight, 3*(FRACUNIT/4)) >> FRACBITS; break; - case MT_METALSONIC_RACE: - case MT_METALSONIC_BATTLE: case MT_FANG: + if (mthing->args[5] & TMF_GRAYSCALE) + { + mobj->color = SKINCOLOR_SILVER; + mobj->colorized = true; + mobj->flags2 |= MF2_SLIDEPUSH; + } + if (mthing->args[5] & TMF_SKIPINTRO) + mobj->flags2 |= MF2_AMBUSH; + break; + case MT_METALSONIC_BATTLE: + if (mthing->args[5]) + { + mobj->color = SKINCOLOR_SILVER; + mobj->colorized = true; + mobj->flags2 |= MF2_SLIDEPUSH; + } + break; + case MT_METALSONIC_RACE: case MT_ROSY: - if (mthing->options & MTF_EXTRA) + if (mthing->args[0]) { mobj->color = SKINCOLOR_SILVER; mobj->colorized = true; @@ -12632,33 +12822,28 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean } break; case MT_BALLOON: - if (mthing->angle > 0) - mobj->color = ((mthing->angle - 1) % (numskincolors - 1)) + 1; + if (mthing->stringargs[0]) + mobj->color = get_number(mthing->stringargs[0]); + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; break; -#define makesoftwarecorona(mo, h) \ - corona = P_SpawnMobjFromMobj(mo, 0, 0, h<sprite = SPR_FLAM;\ - corona->frame = (FF_FULLBRIGHT|FF_TRANS90|12);\ - corona->tics = -1 case MT_FLAME: - if (mthing->options & MTF_EXTRA) + if (mthing->args[0]) { - mobj_t *corona; - makesoftwarecorona(mobj, 20); + mobj_t *corona = P_MakeSoftwareCorona(mobj, 20); P_SetScale(corona, (corona->destscale = mobj->scale*3)); P_SetTarget(&mobj->tracer, corona); } break; case MT_FLAMEHOLDER: - if (!(mthing->options & MTF_OBJECTSPECIAL)) // Spawn the fire + if (!(mthing->args[0] & TMFH_NOFLAME)) // Spawn the fire { mobj_t *flame = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_FLAME); P_SetTarget(&flame->target, mobj); flame->flags2 |= MF2_BOSSNOTRAP; - if (mthing->options & MTF_EXTRA) + if (mthing->args[0] & TMFH_CORONA) { - mobj_t *corona; - makesoftwarecorona(flame, 20); + mobj_t *corona = P_MakeSoftwareCorona(flame, 20); P_SetScale(corona, (corona->destscale = flame->scale*3)); P_SetTarget(&flame->tracer, corona); } @@ -12666,17 +12851,13 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean break; case MT_CANDLE: case MT_CANDLEPRICKET: - if (mthing->options & MTF_EXTRA) - { - mobj_t *corona; - makesoftwarecorona(mobj, ((mobj->type == MT_CANDLE) ? 42 : 176)); - } + if (mthing->args[0]) + P_MakeSoftwareCorona(mobj, ((mobj->type == MT_CANDLE) ? 42 : 176)); break; -#undef makesoftwarecorona case MT_JACKO1: case MT_JACKO2: case MT_JACKO3: - if (!(mthing->options & MTF_EXTRA)) // take the torch out of the crafting recipe + if (!(mthing->args[0])) // take the torch out of the crafting recipe { mobj_t *overlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_OVERLAY); P_SetTarget(&overlay->target, mobj); @@ -12684,17 +12865,15 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean } break; case MT_WATERDRIP: - mobj->tics = 3*TICRATE + mthing->angle; + mobj->tics = 3*TICRATE + mthing->args[0]; break; case MT_FLAMEJET: case MT_VERTICALFLAMEJET: - mobj->threshold = (mthing->angle >> 10) & 7; - mobj->movecount = (mthing->angle >> 13); - - mobj->threshold *= (TICRATE/2); - mobj->movecount *= (TICRATE/2); - - mobj->movedir = mthing->extrainfo; + mobj->movecount = mthing->args[0]; + mobj->threshold = mthing->args[1]; + mobj->movedir = mthing->args[2]; + if (mthing->args[3]) + mobj->flags2 |= MF2_AMBUSH; break; case MT_MACEPOINT: case MT_CHAINMACEPOINT: @@ -12709,60 +12888,50 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean if (!P_SetupParticleGen(mthing, mobj)) return false; break; - case MT_ROCKSPAWNER: - mobj->threshold = mthing->angle; - mobj->movecount = mthing->extrainfo; - break; case MT_POPUPTURRET: - if (mthing->angle) - mobj->threshold = mthing->angle; - else - mobj->threshold = (TICRATE*2)-1; + mobj->threshold = mthing->args[0] ? mthing->args[0] : (TICRATE*2)-1; break; case MT_NIGHTSBUMPER: - // Lower 4 bits specify the angle of - // the bumper in 30 degree increments. - mobj->threshold = (mthing->options & 15) % 12; // It loops over, etc + // Pitch of the bumper is set in 30 degree increments. + mobj->threshold = ((mthing->pitch/30) + 3) % 12; P_SetMobjState(mobj, mobj->info->spawnstate + mobj->threshold); break; case MT_EGGCAPSULE: - if (mthing->angle <= 0) - mthing->angle = 20; // prevent 0 health - - mobj->health = mthing->angle; - mobj->threshold = min(mthing->extrainfo, 7); + mobj->threshold = min(mthing->args[0], 7); + mobj->health = mthing->args[1]; + if (mobj->health <= 0) + mobj->health = 20; // prevent 0 health break; case MT_TUBEWAYPOINT: { - UINT8 sequence = mthing->angle >> 8; - UINT8 id = mthing->angle & 255; + UINT8 sequence = mthing->args[0]; + UINT8 id = mthing->args[1]; mobj->health = id; mobj->threshold = sequence; P_AddWaypoint(sequence, id, mobj); break; } case MT_IDEYAANCHOR: - mobj->health = mthing->extrainfo; + mobj->health = mthing->args[0]; break; case MT_NIGHTSDRONE: if (!P_SetupNiGHTSDrone(mthing, mobj)) return false; break; case MT_HIVEELEMENTAL: - if (mthing->extrainfo) - mobj->extravalue1 = mthing->extrainfo; + if (mthing->args[0]) + mobj->extravalue1 = mthing->args[0]; break; case MT_GLAREGOYLE: case MT_GLAREGOYLEUP: case MT_GLAREGOYLEDOWN: case MT_GLAREGOYLELONG: - if (mthing->angle >= 360) - mobj->tics += 7*(mthing->angle/360) + 1; // starting delay + mobj->tics += mthing->args[1]; // starting delay break; case MT_DSZSTALAGMITE: case MT_DSZ2STALAGMITE: case MT_KELP: - if (mthing->options & MTF_OBJECTSPECIAL) { // make mobj twice as big as normal + if (mthing->args[0]) { // make mobj twice as big as normal P_SetScale(mobj, 2*mobj->scale); // not 2*FRACUNIT in case of something like the old ERZ3 mode mobj->destscale = mobj->scale; } @@ -12775,6 +12944,25 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; } break; + case MT_TUTORIALPLANT: + { + INT32 i; + mobj_t *segment; + for (i = 0; i < 6; i++) + { + segment = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_TUTORIALLEAF); + segment->angle = mobj->angle + FixedAngle(i*60*FRACUNIT); + P_SetMobjState(segment, S_TUTORIALLEAF1 + mthing->args[0]); + } + for (i = 0; i < 3; i++) + { + segment = P_SpawnMobjFromMobj(mobj, 0, 0, 112*FRACUNIT, MT_TUTORIALFLOWER); + segment->angle = mobj->angle + FixedAngle(i*120*FRACUNIT); + P_SetMobjState(segment, S_TUTORIALFLOWER1 + mthing->args[0]); + } + P_SetMobjState(P_SpawnMobjFromMobj(mobj, 0, 0, 112*FRACUNIT, MT_TUTORIALFLOWERF), S_TUTORIALFLOWERF1 + mthing->args[0]); + } + break; case MT_CEZPOLE1: case MT_CEZPOLE2: { // Spawn the banner @@ -12802,20 +12990,20 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean } break; case MT_SMASHINGSPIKEBALL: - if (mthing->angle > 0) - mobj->tics += mthing->angle; + if (mthing->args[0] > 0) + mobj->tics += mthing->args[0]; break; case MT_LAVAFALL: - mobj->fuse = 30 + mthing->angle; - if (mthing->options & MTF_AMBUSH) + mobj->fuse = 30 + mthing->args[0]; + if (mthing->args[1]) { P_SetScale(mobj, 2*mobj->scale); mobj->destscale = mobj->scale; } break; case MT_PYREFLY: - //start on fire if Ambush flag is set, otherwise behave normally - if (mthing->options & MTF_AMBUSH) + //start on fire if args[0], otherwise behave normally + if (mthing->args[0]) { P_SetMobjState(mobj, mobj->info->meleestate); mobj->extravalue2 = 2; @@ -12843,20 +13031,19 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean return false; break; case MT_AXIS: - // Inverted if uppermost bit is set - if (mthing->angle & 16384) + // Inverted if args[3] is set + if (mthing->args[3]) mobj->flags2 |= MF2_AMBUSH; - if (mthing->angle > 0) - mobj->radius = (mthing->angle & 16383) << FRACBITS; + mobj->radius = abs(mthing->args[2]) << FRACBITS; // FALLTHRU case MT_AXISTRANSFER: case MT_AXISTRANSFERLINE: // Mare it belongs to - mobj->threshold = min(mthing->extrainfo, 7); + mobj->threshold = min(mthing->args[0], 7); // # in the mare - mobj->health = mthing->options; + mobj->health = mthing->args[1]; mobj->flags2 |= MF2_AXIS; break; @@ -12866,7 +13053,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->health = 1 << (tokenbits - 1); break; case MT_CYBRAKDEMON: - if (mthing->options & MTF_AMBUSH) + if (mthing->args[6] & TMB_BARRIER) { mobj_t* elecmobj; elecmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_CYBRAKDEMON_ELECTRIC_BARRIER); @@ -12877,54 +13064,21 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean } break; case MT_STARPOST: - { - thinker_t* th; - mobj_t* mo2; - boolean foundanother = false; - - if (mthing->extrainfo) - // Allow thing Parameter to define star post num too! - // For starposts above param 15 (the 16th), add 360 to the angle like before and start parameter from 1 (NOT 0)! - // So the 16th starpost is angle=0 param=15, the 17th would be angle=360 param=1. - // This seems more intuitive for mappers to use until UDMF is ready, since most SP maps won't have over 16 consecutive star posts. - mobj->health = mthing->extrainfo + (mthing->angle/360)*15 + 1; - else - // Old behavior if Parameter is 0; add 360 to the angle for each consecutive star post. - mobj->health = (mthing->angle/360) + 1; - - // See if other starposts exist in this level that have the same value. - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - - mo2 = (mobj_t*)th; - - if (mo2 == mobj) - continue; - - if (mo2->type == MT_STARPOST && mo2->health == mobj->health) - { - foundanother = true; - break; - } - } - - if (!foundanother) + mobj->health = mthing->args[0] + 1; + if (!P_MapAlreadyHasStarPost(mobj)) numstarposts++; break; - } case MT_SPIKE: // Pop up spikes! - if (mthing->options & MTF_OBJECTSPECIAL) + if (mthing->args[0]) { mobj->flags &= ~MF_SCENERY; - mobj->fuse = (16 - mthing->extrainfo)*(mthing->angle + mobj->info->speed)/16; - if (mthing->options & MTF_EXTRA) - P_SetMobjState(mobj, mobj->info->meleestate); + mobj->fuse = mthing->args[1]; } - // Use per-thing collision for spikes if the deaf flag isn't checked. - if (!(mthing->options & MTF_AMBUSH) && !metalrecording) + if (mthing->args[2] & TMSF_RETRACTED) + P_SetMobjState(mobj, mobj->info->meleestate); + // Use per-thing collision for spikes unless the intangible flag is checked. + if (!(mthing->args[2] & TMSF_INTANGIBLE) && !metalrecording) { P_UnsetThingPosition(mobj); mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT); @@ -12934,22 +13088,21 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean break; case MT_WALLSPIKE: // Pop up spikes! - if (mthing->options & MTF_OBJECTSPECIAL) + if (mthing->args[0]) { mobj->flags &= ~MF_SCENERY; - mobj->fuse = (16 - mthing->extrainfo)*((mthing->angle/360) + mobj->info->speed)/16; - if (mthing->options & MTF_EXTRA) - P_SetMobjState(mobj, mobj->info->meleestate); + mobj->fuse = mthing->args[1]; } - // Use per-thing collision for spikes if the deaf flag isn't checked. - if (!(mthing->options & MTF_AMBUSH) && !metalrecording) + if (mthing->args[2] & TMSF_RETRACTED) + P_SetMobjState(mobj, mobj->info->meleestate); + // Use per-thing collision for spikes unless the intangible flag is checked. + if (!(mthing->args[2] & TMSF_INTANGIBLE) && !metalrecording) { P_UnsetThingPosition(mobj); mobj->flags &= ~(MF_NOBLOCKMAP | MF_NOCLIPHEIGHT); mobj->flags |= MF_SOLID; P_SetThingPosition(mobj); } - // spawn base { const angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS); // the mobj's own angle hasn't been set quite yet so... @@ -12972,12 +13125,13 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean break; case MT_BIGTUMBLEWEED: case MT_LITTLETUMBLEWEED: - if (mthing->options & MTF_AMBUSH) + if (mthing->args[0]) { fixed_t offset = FixedMul(16*FRACUNIT, mobj->scale); mobj->momx += P_RandomChance(FRACUNIT/2) ? offset : -offset; mobj->momy += P_RandomChance(FRACUNIT/2) ? offset : -offset; mobj->momz += offset; + mobj->flags2 |= MF2_AMBUSH; } break; case MT_REDFLAG: @@ -12988,89 +13142,121 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean blueflag = mobj; bflagpoint = mobj->spawnpoint; break; - case MT_PUSH: - case MT_PULL: - mobj->health = 0; // Default behaviour: pushing uses XY, fading uses XYZ - - if (mthing->options & MTF_AMBUSH) - mobj->health |= 1; // If ambush is set, push using XYZ - if (mthing->options & MTF_OBJECTSPECIAL) - mobj->health |= 2; // If object special is set, fade using XY - - if (G_IsSpecialStage(gamemap)) - P_SetMobjState(mobj, (mobj->type == MT_PUSH) ? S_GRAVWELLGREEN : S_GRAVWELLRED); - break; case MT_NIGHTSSTAR: if (maptol & TOL_XMAS) P_SetMobjState(mobj, mobj->info->seestate); break; + case MT_YELLOWDIAG: + case MT_REDDIAG: + case MT_BLUEDIAG: + mobj->angle = FixedAngle(mthing->angle << FRACBITS); + if (mthing->args[0] & TMDS_NOGRAVITY) + mobj->flags |= MF_NOGRAVITY; + if (mthing->args[0] & TMDS_ROTATEEXTRA) + mobj->angle += ANGLE_22h; + *doangle = false; + break; + case MT_AMBIENT: + if (mthing->stringargs[0]) + mobj->threshold = get_number(mthing->stringargs[0]); + mobj->health = mthing->args[0] ? mthing->args[0] : TICRATE; + break; + case MT_GOLDBUZZ: + case MT_REDBUZZ: + case MT_JETTBOMBER: + case MT_JETTGUNNER: + case MT_ROBOHOOD: + case MT_CRUSHSTACEAN: + case MT_BANPYURA: + case MT_BUMBLEBORE: + case MT_CACOLANTERN: + case MT_PIAN: + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; + break; + case MT_EGGGUARD: + if (mthing->args[1]) + mobj->flags2 |= MF2_AMBUSH; + break; + case MT_STEAM: + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; + break; + case MT_SALOONDOORCENTER: + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; + break; + case MT_MINECARTSWITCHPOINT: + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; + break; + case MT_ROLLOUTSPAWN: + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; + break; default: break; } if (mobj->flags & MF_BOSS) { - if (mthing->options & MTF_OBJECTSPECIAL) // No egg trap for this boss + if (mthing->args[1]) // No egg trap for this boss mobj->flags2 |= MF2_BOSSNOTRAP; } + if (mobj->flags & MF_NIGHTSITEM) + { + // Requires you to be in bonus time to activate + if (mthing->args[0] & TMNI_BONUSONLY) + mobj->flags2 |= MF2_STRONGBOX; + // Spawn already displayed + if (mthing->args[0] & TMNI_REVEAL) + { + mobj->flags |= MF_SPECIAL; + mobj->flags &= ~MF_NIGHTSITEM; + } + } + if (mobj->flags & MF_PUSHABLE) + { + switch (mthing->args[0]) + { + case TMP_NORMAL: + default: + break; + case TMP_SLIDE: + mobj->flags2 |= MF2_SLIDEPUSH; + mobj->flags |= MF_BOUNCE; + break; + case TMP_IMMOVABLE: + mobj->flags &= ~MF_PUSHABLE; + break; + case TMP_CLASSIC: + mobj->flags2 |= MF2_CLASSICPUSH; + break; + } + } + if (mobj->flags & MF_SPRING && mobj->info->painchance == 3) + { + if (mthing->args[0]) + mobj->flags2 |= MF2_AMBUSH; + } + if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) + { + switch (mthing->args[1]) + { + case TMMR_SAME: + default: + break; + case TMMR_WEAK: + mobj->flags2 |= MF2_AMBUSH; + break; + case TMMR_STRONG: + mobj->flags2 |= MF2_STRONGBOX; + } + } return true; } -static void P_SetAmbush(mobj_t *mobj) -{ - if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG) - mobj->angle += ANGLE_22h; - - if (mobj->flags & MF_NIGHTSITEM) - { - // Spawn already displayed - mobj->flags |= MF_SPECIAL; - mobj->flags &= ~MF_NIGHTSITEM; - } - - if (mobj->flags & MF_PUSHABLE) - mobj->flags &= ~MF_PUSHABLE; - - if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) - { - // flag for strong/weak random boxes - // any monitor with nonzero speed is allowed to respawn like this - mobj->flags2 |= MF2_AMBUSH; - } - - else if (mobj->type != MT_AXIS && - mobj->type != MT_AXISTRANSFER && - mobj->type != MT_AXISTRANSFERLINE && - mobj->type != MT_NIGHTSBUMPER && - mobj->type != MT_STARPOST) - mobj->flags2 |= MF2_AMBUSH; -} - -static void P_SetObjectSpecial(mobj_t *mobj) -{ - if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG) - mobj->flags |= MF_NOGRAVITY; - - if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) - { - // flag for strong/weak random boxes - // any monitor with nonzero speed is allowed to respawn like this - mobj->flags2 |= MF2_STRONGBOX; - } - - // Requires you to be in bonus time to activate - if (mobj->flags & MF_NIGHTSITEM) - mobj->flags2 |= MF2_STRONGBOX; - - // Pushables bounce and slide coolly with object special flag set - if (mobj->flags & MF_PUSHABLE) - { - mobj->flags2 |= MF2_SLIDEPUSH; - mobj->flags |= MF_BOUNCE; - } -} - static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t i) { mobj_t *mobj = NULL; @@ -13093,23 +13279,6 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, mthing->mobj = mobj; - // ignore MTF_ flags and return early - if (i == MT_NIGHTSBUMPER) - return mobj; - - if ((mthing->options & MTF_AMBUSH) - && (mthing->options & MTF_OBJECTSPECIAL) - && (mobj->flags & MF_PUSHABLE)) - mobj->flags2 |= MF2_CLASSICPUSH; - else - { - if (mthing->options & MTF_AMBUSH) - P_SetAmbush(mobj); - - if (mthing->options & MTF_OBJECTSPECIAL) - P_SetObjectSpecial(mobj); - } - // Generic reverse gravity for individual objects flag. if (mthing->options & MTF_OBJECTFLIP) { @@ -13117,16 +13286,6 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, mobj->flags2 |= MF2_OBJECTFLIP; } - // Extra functionality - if (mthing->options & MTF_EXTRA) - { - if (mobj->flags & MF_MONITOR && (mthing->angle & 16384)) - { - // Store line exec tag to run upon popping - mobj->lastlook = (mthing->angle & 16383); - } - } - // Final set of not being able to draw nightsitems. if (mobj->flags & MF_NIGHTSITEM) mobj->flags2 |= MF2_DONTDRAW; @@ -13175,13 +13334,18 @@ mobj_t *P_SpawnMapThing(mapthing_t *mthing) return P_SpawnMobjFromMapThing(mthing, x, y, z, i); } -static void P_SpawnHoopInternal(mapthing_t *mthing, INT32 hoopsize, fixed_t sizefactor) +void P_SpawnHoop(mapthing_t *mthing) { + if (metalrecording) + return; + mobj_t *mobj = NULL; mobj_t *nextmobj = NULL; mobj_t *hoopcenter; TMatrix *pitchmatrix, *yawmatrix; - fixed_t radius = hoopsize*sizefactor; + fixed_t radius = mthing->args[0] << FRACBITS; + fixed_t sizefactor = 4*FRACUNIT; + fixed_t hoopsize = radius/sizefactor; INT32 i; angle_t fa; TVector v, *res; @@ -13198,10 +13362,9 @@ static void P_SpawnHoopInternal(mapthing_t *mthing, INT32 hoopsize, fixed_t size hoopcenter->y = y; P_SetThingPosition(hoopcenter); - // Scale 0-255 to 0-359 =( - hoopcenter->movedir = ((mthing->angle & 255)*360)/256; // Pitch + hoopcenter->movedir = mthing->pitch; pitchmatrix = RotateXMatrix(FixedAngle(hoopcenter->movedir << FRACBITS)); - hoopcenter->movecount = (((UINT16)mthing->angle >> 8)*360)/256; // Yaw + hoopcenter->movecount = mthing->angle; yawmatrix = RotateZMatrix(FixedAngle(hoopcenter->movecount << FRACBITS)); // For the hoop when it flies away @@ -13281,19 +13444,6 @@ static void P_SpawnHoopInternal(mapthing_t *mthing, INT32 hoopsize, fixed_t size } while (hoopsize >= 8); } -void P_SpawnHoop(mapthing_t *mthing) -{ - if (metalrecording) - return; - - if (mthing->type == 1705) // Generic hoop - P_SpawnHoopInternal(mthing, 24, 4*FRACUNIT); - else // Customizable hoop - // For each flag add 16 fracunits to the size - // Default (0 flags) is 32 fracunits - P_SpawnHoopInternal(mthing, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT); -} - void P_SetBonusTime(mobj_t *mobj) { if (!mobj) @@ -13305,7 +13455,7 @@ void P_SetBonusTime(mobj_t *mobj) P_SetMobjState(mobj, mobj->info->raisestate); } -static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t* itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) +static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) { mapthing_t dummything; mobj_t *mobj = NULL; @@ -13356,7 +13506,7 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t* itemtypes, UINT8 numi } } -static void P_SpawnSingularItemRow(mapthing_t* mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) +static void P_SpawnSingularItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime) { mobjtype_t itemtypes[1] = { itemtype }; return P_SpawnItemRow(mthing, itemtypes, 1, numitems, horizontalspacing, verticalspacing, fixedangle, bonustime); @@ -13420,6 +13570,35 @@ static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 n } } +static void P_ParseItemTypes(char *itemstring, mobjtype_t *itemtypes, UINT8 *numitemtypes) +{ + char *tok; + + *numitemtypes = 0; + if (itemstring) + { + char *stringcopy = Z_Malloc(strlen(itemstring) + 1, PU_LEVEL, NULL); + M_Memcpy(stringcopy, itemstring, strlen(itemstring)); + stringcopy[strlen(itemstring)] = '\0'; + + tok = strtok(stringcopy, " "); + while (tok && *numitemtypes < 128) + { + itemtypes[*numitemtypes] = get_number(tok); + tok = strtok(NULL, " "); + (*numitemtypes)++; + } + + Z_Free(stringcopy); + } + else + { + //If no types are supplied, default to ring + itemtypes[0] = MT_RING; + *numitemtypes = 1; + } +} + void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) { switch (mthing->type) @@ -13457,6 +13636,27 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime) P_SpawnItemCircle(mthing, itemtypes, 2, numitems, size, bonustime); return; } + case 610: // Generic item row + { + mobjtype_t itemtypes[128]; //If you want to have a row with more than 128 different object types, you're crazy. + UINT8 numitemtypes; + if (!udmf) + return; + P_ParseItemTypes(mthing->stringargs[0], itemtypes, &numitemtypes); + P_SpawnItemRow(mthing, itemtypes, numitemtypes, mthing->args[0], mthing->args[1] << FRACBITS, mthing->args[2] << FRACBITS, mthing->angle, bonustime); + return; + } + case 611: // Generic item circle + { + mobjtype_t itemtypes[128]; //If you want to have a circle with more than 128 different object types, you're crazy. + UINT8 numitemtypes; + if (!udmf) + return; + CONS_Printf("Itemstring: %s\n", mthing->stringargs[0]); + P_ParseItemTypes(mthing->stringargs[0], itemtypes, &numitemtypes); + P_SpawnItemCircle(mthing, itemtypes, numitemtypes, mthing->args[0], mthing->args[1] << FRACBITS, bonustime); + return; + } default: return; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 5bb7c908e..da8d9ea2b 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -118,7 +118,7 @@ typedef enum // Don't apply gravity (every tic); object will float, keeping current height // or changing it actively. MF_NOGRAVITY = 1<<9, - // This object is an ambient sound. + // This object is an ambient sound. Obsolete, but keep this around for backwards compatibility. MF_AMBIENT = 1<<10, // Slide this object when it hits a wall. MF_SLIDEME = 1<<11, @@ -218,33 +218,40 @@ typedef enum typedef enum { // The mobj stands on solid floor (not on another mobj or in air) - MFE_ONGROUND = 1, + MFE_ONGROUND = 1, // The mobj just hit the floor while falling, this is cleared on next frame // (instant damage in lava/slime sectors to prevent jump cheat..) - MFE_JUSTHITFLOOR = 1<<1, + MFE_JUSTHITFLOOR = 1<<1, // The mobj stands in a sector with water, and touches the surface // this bit is set once and for all at the start of mobjthinker - MFE_TOUCHWATER = 1<<2, + MFE_TOUCHWATER = 1<<2, // The mobj stands in a sector with water, and his waist is BELOW the water surface // (for player, allows swimming up/down) - MFE_UNDERWATER = 1<<3, + MFE_UNDERWATER = 1<<3, // used for ramp sectors - MFE_JUSTSTEPPEDDOWN = 1<<4, + MFE_JUSTSTEPPEDDOWN = 1<<4, // Vertically flip sprite/allow upside-down physics - MFE_VERTICALFLIP = 1<<5, + MFE_VERTICALFLIP = 1<<5, // Goo water - MFE_GOOWATER = 1<<6, + MFE_GOOWATER = 1<<6, // The mobj is touching a lava block - MFE_TOUCHLAVA = 1<<7, + MFE_TOUCHLAVA = 1<<7, // Mobj was already pushed this tic - MFE_PUSHED = 1<<8, + MFE_PUSHED = 1<<8, // Mobj was already sprung this tic - MFE_SPRUNG = 1<<9, + MFE_SPRUNG = 1<<9, // Platform movement - MFE_APPLYPMOMZ = 1<<10, + MFE_APPLYPMOMZ = 1<<10, // Compute and trigger on mobj angle relative to tracer // See Linedef Exec 457 (Track mobj angle to point) - MFE_TRACERANGLE = 1<<11, + MFE_TRACERANGLE = 1<<11, + // Forces an object to use super sprites with SPR_PLAY. + MFE_FORCESUPER = 1<<12, + // Forces an object to NOT use super sprites with SPR_PLAY. + MFE_FORCENOSUPER = 1<<13, + // Makes an object use super sprites where they wouldn't have otherwise and vice-versa + MFE_REVERSESUPER = MFE_FORCESUPER|MFE_FORCENOSUPER + // free: to and including 1<<15 } mobjeflag_t; diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 874edbd50..77e514bee 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by James Haley -// Copyright (C) 2006-2020 by Sonic Team Junior. +// Copyright (C) 2006-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -785,7 +785,7 @@ static void Polyobj_pushThing(polyobj_t *po, line_t *line, mobj_t *mo) vertex_t closest; // calculate angle of line and subtract 90 degrees to get normal - lineangle = R_PointToAngle2(0, 0, line->dx, line->dy) - ANGLE_90; + lineangle = line->angle - ANGLE_90; lineangle >>= ANGLETOFINESHIFT; momx = FixedMul(po->thrust, FINECOSINE(lineangle)); momy = FixedMul(po->thrust, FINESINE(lineangle)); @@ -963,7 +963,7 @@ static INT32 Polyobj_clipThings(polyobj_t *po, line_t *line) else Polyobj_pushThing(po, line, mo); - if (mo->player && (po->lines[0]->backsector->flags & SF_TRIGGERSPECIAL_TOUCH) && !(po->flags & POF_NOSPECIALS)) + if (mo->player && (po->lines[0]->backsector->flags & MSF_TRIGGERSPECIAL_TOUCH) && !(po->flags & POF_NOSPECIALS)) P_ProcessSpecialSector(mo->player, mo->subsector->sector, po->lines[0]->backsector); hitflags |= 1; @@ -1060,6 +1060,8 @@ static void Polyobj_rotateLine(line_t *ld) ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; + ld->angle = R_PointToAngle2(0, 0, ld->dx, ld->dy); + // determine slopetype ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL : ((ld->dy > 0) == (ld->dx > 0)) ? ST_POSITIVE : ST_NEGATIVE; @@ -1089,7 +1091,7 @@ static void Polyobj_rotateLine(line_t *ld) } // Causes objects resting on top of the rotating polyobject to 'ride' with its movement. -static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, UINT8 turnthings) +static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, boolean turnplayers, boolean turnothers) { static INT32 pomovecount = 10000; INT32 x, y; @@ -1151,7 +1153,7 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, Polyobj_slideThing(mo, newxoff, newyoff); - if (turnthings == 2 || (turnthings == 1 && !mo->player)) { + if ((turnplayers && mo->player) || (turnothers && !mo->player)) { mo->angle += delta; if (mo->player) P_SetPlayerAngle(mo->player, (angle_t)(mo->player->angleturn << 16) + delta); @@ -1163,7 +1165,7 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta, } // Rotates a polyobject around its start point. -boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, boolean checkmobjs) +boolean Polyobj_rotate(polyobj_t *po, angle_t delta, boolean turnplayers, boolean turnothers, boolean checkmobjs) { size_t i; angle_t angle; @@ -1201,7 +1203,7 @@ boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, boolean c for (i = 0; i < po->numLines; ++i) hitflags |= Polyobj_clipThings(po, po->lines[i]); - Polyobj_rotateThings(po, origin, delta, turnthings); + Polyobj_rotateThings(po, origin, delta, turnplayers, turnothers); } if (hitflags & 2) @@ -1409,7 +1411,7 @@ void Polyobj_MoveOnLoad(polyobj_t *po, angle_t angle, fixed_t x, fixed_t y) fixed_t dx, dy; // first, rotate to the saved angle - Polyobj_rotate(po, angle, false, false); + Polyobj_rotate(po, angle, false, false, false); // determine component distances to translate dx = x - po->spawnSpot.x; @@ -1452,7 +1454,7 @@ void T_PolyObjRotate(polyrotate_t *th) // rotate by 'speed' angle per frame // if distance == -1, this polyobject rotates perpetually - if (Polyobj_rotate(po, th->speed, th->turnobjs, true) && th->distance != -1) + if (Polyobj_rotate(po, th->speed, th->turnobjs & PTF_PLAYERS, th->turnobjs & PTF_OTHERS, true) && th->distance != -1) { INT32 avel = abs(th->speed); @@ -1854,7 +1856,7 @@ void T_PolyDoorSwing(polyswingdoor_t *th) // rotate by 'speed' angle per frame // if distance == -1, this polyobject rotates perpetually - if (Polyobj_rotate(po, th->speed, false, true) && th->distance != -1) + if (Polyobj_rotate(po, th->speed, false, false, true) && th->distance != -1) { INT32 avel = abs(th->speed); @@ -1985,7 +1987,7 @@ void T_PolyObjRotDisplace(polyrotdisplace_t *th) rotangle = FixedMul(th->rotscale, delta); - if (Polyobj_rotate(po, FixedAngle(rotangle), th->turnobjs, true)) + if (Polyobj_rotate(po, FixedAngle(rotangle), th->turnobjs & PTF_PLAYERS, th->turnobjs & PTF_OTHERS, true)) th->oldHeights = newheights; } @@ -2014,7 +2016,7 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata) return false; // check for override if this polyobj already has a thinker - if (po->thinker && !prdata->overRide) + if (po->thinker && !(prdata->flags & TMPR_OVERRIDE)) return false; // create a new thinker @@ -2029,10 +2031,10 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata) // use Hexen-style byte angles for speed and distance th->speed = Polyobj_AngSpeed(prdata->speed * prdata->direction); - if (prdata->distance == 360) // 360 means perpetual + if (prdata->flags & TMPR_CONTINUOUS) th->distance = -1; - else if (prdata->distance == 0) // 0 means 360 degrees - th->distance = 0xffffffff - 1; + else if (prdata->distance == 360) + th->distance = ANGLE_MAX - 1; else th->distance = FixedAngle(prdata->distance*FRACUNIT); @@ -2047,7 +2049,11 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata) oldpo = po; - th->turnobjs = prdata->turnobjs; + th->turnobjs = 0; + if (!(prdata->flags & TMPR_DONTROTATEOTHERS)) + th->turnobjs |= PTF_OTHERS; + if (prdata->flags & TMPR_ROTATEPLAYERS) + th->turnobjs |= PTF_PLAYERS; // apply action to mirroring polyobjects as well start = 0; diff --git a/src/p_polyobj.h b/src/p_polyobj.h index 8c2946965..e9d246168 100644 --- a/src/p_polyobj.h +++ b/src/p_polyobj.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by James Haley -// Copyright (C) 2006-2020 by Sonic Team Junior. +// Copyright (C) 2006-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -137,7 +137,7 @@ typedef struct polyrotate_s INT32 polyObjNum; // numeric id of polyobject (avoid C pointers here) INT32 speed; // speed of movement per frame INT32 distance; // distance to move - UINT8 turnobjs; // turn objects? 0=no, 1=everything but players, 2=everything + UINT8 turnobjs; // turn objects? PTF_ flags } polyrotate_t; typedef struct polymove_s @@ -247,14 +247,27 @@ typedef struct polyfade_s // Line Activation Data Structures // +typedef enum +{ + TMPR_DONTROTATEOTHERS = 1, + TMPR_ROTATEPLAYERS = 1<<1, + TMPR_CONTINUOUS = 1<<2, + TMPR_OVERRIDE = 1<<3, +} textmappolyrotate_t; + +typedef enum +{ + PTF_PLAYERS = 1, // Turn players with movement + PTF_OTHERS = 1<<1, // Turn other mobjs with movement +} polyturnflags_e; + typedef struct polyrotdata_s { INT32 polyObjNum; // numeric id of polyobject to affect INT32 direction; // direction of rotation INT32 speed; // angular speed INT32 distance; // distance to move - UINT8 turnobjs; // rotate objects being carried? - UINT8 overRide; // if true, will override any action on the object + UINT8 flags; // TMPR_ flags } polyrotdata_t; typedef struct polymovedata_s @@ -281,6 +294,20 @@ typedef struct polywaypointdata_s UINT8 flags; // PWF_ flags } polywaypointdata_t; +typedef enum +{ + TMPV_NOCHANGE = 1, + TMPV_VISIBLE = 1<<1, + TMPV_INVISIBLE = 1<<2, +} textmappolyvisibility_t; + +typedef enum +{ + TMPT_NOCHANGE = 1, + TMPT_TANGIBLE = 1<<1, + TMPT_INTANGIBLE = 1<<2, +} textmappolytangibility_t; + // polyobject door types typedef enum { @@ -322,6 +349,15 @@ typedef struct polyflagdata_s fixed_t momx; } polyflagdata_t; +typedef enum +{ + TMPF_RELATIVE = 1, + TMPF_OVERRIDE = 1<<1, + TMPF_TICBASED = 1<<2, + TMPF_IGNORECOLLISION = 1<<3, + TMPF_GHOSTFADE = 1<<4, +} textmappolyfade_t; + typedef struct polyfadedata_s { INT32 polyObjNum; @@ -337,7 +373,7 @@ typedef struct polyfadedata_s // boolean Polyobj_moveXY(polyobj_t *po, fixed_t x, fixed_t y, boolean checkmobjs); -boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings, boolean checkmobjs); +boolean Polyobj_rotate(polyobj_t *po, angle_t delta, boolean turnplayers, boolean turnothers, boolean checkmobjs); polyobj_t *Polyobj_GetForNum(INT32 id); void Polyobj_InitLevel(void); void Polyobj_MoveOnLoad(polyobj_t *po, angle_t angle, fixed_t x, fixed_t y); diff --git a/src/p_pspr.h b/src/p_pspr.h index 231262beb..4136c2118 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -41,9 +41,20 @@ /// \brief Frame flags - SPR2: Super sprite2 #define FF_SPR2SUPER 0x80 /// \brief Frame flags - SPR2: A change of state at the end of Sprite2 animation -#define FF_SPR2ENDSTATE 0x1000 +#define FF_SPR2ENDSTATE 0x100 /// \brief Frame flags - SPR2: 50% of starting in middle of Sprite2 animation -#define FF_SPR2MIDSTART 0x2000 +#define FF_SPR2MIDSTART 0x200 + +/// \brief Frame flags: blend types +#define FF_BLENDMASK 0x7000 +/// \brief shift for FF_BLENDMASK +#define FF_BLENDSHIFT 12 +/// \brief preshifted blend flags minus 1 as effects don't distinguish between AST_COPY and AST_TRANSLUCENT +#define FF_ADD ((AST_ADD-1)<skin + (botskin<<5); SINT8 pllives = player->lives; if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player pllives = startinglivesbalance[numgameovers]; // has less than that. - WRITEUINT16(save_p, skininfo); +#ifdef NEWSKINSAVES + // Write a specific value into the old skininfo location. + // If we read something other than this, it's an older save file that used skin numbers. + WRITEUINT16(save_p, NEWSKINSAVES); +#endif + + // Write skin names, so that loading skins in different orders + // doesn't change who the save file is for! + WRITESTRINGN(save_p, skins[player->skin].name, SKINNAMESIZE); + + if (botskin != 0) + { + WRITESTRINGN(save_p, skins[botskin-1].name, SKINNAMESIZE); + } + else + { + WRITESTRINGN(save_p, "\0", SKINNAMESIZE); + } + WRITEUINT8(save_p, numgameovers); WRITESINT8(save_p, pllives); WRITEUINT32(save_p, player->score); @@ -78,9 +95,27 @@ static inline void P_ArchivePlayer(void) static inline void P_UnArchivePlayer(void) { - INT16 skininfo = READUINT16(save_p); - savedata.skin = skininfo & ((1<<5) - 1); - savedata.botskin = skininfo >> 5; +#ifdef NEWSKINSAVES + INT16 backwardsCompat = READUINT16(save_p); + + if (backwardsCompat != NEWSKINSAVES) + { + // This is an older save file, which used direct skin numbers. + savedata.skin = backwardsCompat & ((1<<5) - 1); + savedata.botskin = backwardsCompat >> 5; + } + else +#endif + { + char ourSkinName[SKINNAMESIZE+1]; + char botSkinName[SKINNAMESIZE+1]; + + READSTRINGN(save_p, ourSkinName, SKINNAMESIZE); + savedata.skin = R_SkinAvailable(ourSkinName); + + READSTRINGN(save_p, botSkinName, SKINNAMESIZE); + savedata.botskin = R_SkinAvailable(botSkinName) + 1; + } savedata.numgameovers = READUINT8(save_p); savedata.lives = READSINT8(save_p); @@ -158,6 +193,19 @@ static void P_NetArchivePlayers(void) WRITEUINT32(save_p, players[i].dashmode); WRITEUINT32(save_p, players[i].skidtime); + ////////// + // Bots // + ////////// + WRITEUINT8(save_p, players[i].bot); + WRITEUINT8(save_p, players[i].botmem.lastForward); + WRITEUINT8(save_p, players[i].botmem.lastBlocked); + WRITEUINT8(save_p, players[i].botmem.catchup_tics); + WRITEUINT8(save_p, players[i].botmem.thinkstate); + WRITEUINT8(save_p, players[i].removing); + + WRITEUINT8(save_p, players[i].blocked); + WRITEUINT16(save_p, players[i].lastbuttons); + //////////////////////////// // Conveyor Belt Movement // //////////////////////////// @@ -372,6 +420,20 @@ static void P_NetUnArchivePlayers(void) players[i].dashmode = READUINT32(save_p); // counter for dashmode ability players[i].skidtime = READUINT32(save_p); // Skid timer + ////////// + // Bots // + ////////// + players[i].bot = READUINT8(save_p); + + players[i].botmem.lastForward = READUINT8(save_p); + players[i].botmem.lastBlocked = READUINT8(save_p); + players[i].botmem.catchup_tics = READUINT8(save_p); + players[i].botmem.thinkstate = READUINT8(save_p); + players[i].removing = READUINT8(save_p); + + players[i].blocked = READUINT8(save_p); + players[i].lastbuttons = READUINT16(save_p); + //////////////////////////// // Conveyor Belt Movement // //////////////////////////// @@ -788,6 +850,17 @@ static void P_NetUnArchiveWaypoints(void) #define SD_TAGLIST 0x01 #define SD_COLORMAP 0x02 #define SD_CRUMBLESTATE 0x04 +#define SD_FLOORLIGHT 0x08 +#define SD_CEILLIGHT 0x10 +#define SD_FLAG 0x20 +#define SD_SPECIALFLAG 0x40 +#define SD_DIFF4 0x80 + +//diff4 flags +#define SD_DAMAGETYPE 0x01 +#define SD_TRIGGERTAG 0x02 +#define SD_TRIGGERER 0x04 +#define SD_GRAVITY 0x08 #define LD_FLAG 0x01 #define LD_SPECIAL 0x02 @@ -926,11 +999,11 @@ static void ArchiveSectors(void) size_t i, j; const sector_t *ss = sectors; const sector_t *spawnss = spawnsectors; - UINT8 diff, diff2, diff3; + UINT8 diff, diff2, diff3, diff4; for (i = 0; i < numsectors; i++, ss++, spawnss++) { - diff = diff2 = diff3 = 0; + diff = diff2 = diff3 = diff4 = 0; if (ss->floorheight != spawnss->floorheight) diff |= SD_FLOORHT; if (ss->ceilingheight != spawnss->ceilingheight) @@ -969,9 +1042,29 @@ static void ArchiveSectors(void) if (ss->crumblestate) diff3 |= SD_CRUMBLESTATE; + if (ss->floorlightlevel != spawnss->floorlightlevel || ss->floorlightabsolute != spawnss->floorlightabsolute) + diff3 |= SD_FLOORLIGHT; + if (ss->ceilinglightlevel != spawnss->ceilinglightlevel || ss->ceilinglightabsolute != spawnss->ceilinglightabsolute) + diff3 |= SD_CEILLIGHT; + if (ss->flags != spawnss->flags) + diff3 |= SD_FLAG; + if (ss->specialflags != spawnss->specialflags) + diff3 |= SD_SPECIALFLAG; + if (ss->damagetype != spawnss->damagetype) + diff4 |= SD_DAMAGETYPE; + if (ss->triggertag != spawnss->triggertag) + diff4 |= SD_TRIGGERTAG; + if (ss->triggerer != spawnss->triggerer) + diff4 |= SD_TRIGGERER; + if (ss->gravity != spawnss->gravity) + diff4 |= SD_GRAVITY; + if (ss->ffloors && CheckFFloorDiff(ss)) diff |= SD_FFLOORS; + if (diff4) + diff3 |= SD_DIFF4; + if (diff3) diff2 |= SD_DIFF3; @@ -986,6 +1079,8 @@ static void ArchiveSectors(void) WRITEUINT8(save_p, diff2); if (diff2 & SD_DIFF3) WRITEUINT8(save_p, diff3); + if (diff3 & SD_DIFF4) + WRITEUINT8(save_p, diff4); if (diff & SD_FLOORHT) WRITEFIXED(save_p, ss->floorheight); if (diff & SD_CEILHT) @@ -1022,6 +1117,28 @@ static void ArchiveSectors(void) // returns existing index if already added, or appends to net_colormaps and returns new index if (diff3 & SD_CRUMBLESTATE) WRITEINT32(save_p, ss->crumblestate); + if (diff3 & SD_FLOORLIGHT) + { + WRITEINT16(save_p, ss->floorlightlevel); + WRITEUINT8(save_p, ss->floorlightabsolute); + } + if (diff3 & SD_CEILLIGHT) + { + WRITEINT16(save_p, ss->ceilinglightlevel); + WRITEUINT8(save_p, ss->ceilinglightabsolute); + } + if (diff3 & SD_FLAG) + WRITEUINT32(save_p, ss->flags); + if (diff3 & SD_SPECIALFLAG) + WRITEUINT32(save_p, ss->specialflags); + if (diff4 & SD_DAMAGETYPE) + WRITEUINT8(save_p, ss->damagetype); + if (diff4 & SD_TRIGGERTAG) + WRITEINT16(save_p, ss->triggertag); + if (diff4 & SD_TRIGGERER) + WRITEUINT8(save_p, ss->triggerer); + if (diff4 & SD_GRAVITY) + WRITEFIXED(save_p, ss->gravity); if (diff & SD_FFLOORS) ArchiveFFloors(ss); } @@ -1033,7 +1150,7 @@ static void ArchiveSectors(void) static void UnArchiveSectors(void) { UINT16 i, j; - UINT8 diff, diff2, diff3; + UINT8 diff, diff2, diff3, diff4; for (;;) { i = READUINT16(save_p); @@ -1053,6 +1170,10 @@ static void UnArchiveSectors(void) diff3 = READUINT8(save_p); else diff3 = 0; + if (diff3 & SD_DIFF4) + diff4 = READUINT8(save_p); + else + diff4 = 0; if (diff & SD_FLOORHT) sectors[i].floorheight = READFIXED(save_p); @@ -1113,6 +1234,31 @@ static void UnArchiveSectors(void) sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p)); if (diff3 & SD_CRUMBLESTATE) sectors[i].crumblestate = READINT32(save_p); + if (diff3 & SD_FLOORLIGHT) + { + sectors[i].floorlightlevel = READINT16(save_p); + sectors[i].floorlightabsolute = READUINT8(save_p); + } + if (diff3 & SD_CEILLIGHT) + { + sectors[i].ceilinglightlevel = READINT16(save_p); + sectors[i].ceilinglightabsolute = READUINT8(save_p); + } + if (diff3 & SD_FLAG) + { + sectors[i].flags = READUINT32(save_p); + CheckForReverseGravity |= (sectors[i].flags & MSF_GRAVITYFLIP); + } + if (diff3 & SD_SPECIALFLAG) + sectors[i].specialflags = READUINT32(save_p); + if (diff4 & SD_DAMAGETYPE) + sectors[i].damagetype = READUINT8(save_p); + if (diff4 & SD_TRIGGERTAG) + sectors[i].triggertag = READINT16(save_p); + if (diff4 & SD_TRIGGERER) + sectors[i].triggerer = READUINT8(save_p); + if (diff4 & SD_GRAVITY) + sectors[i].gravity = READFIXED(save_p); if (diff & SD_FFLOORS) UnArchiveFFloors(§ors[i]); @@ -1506,7 +1652,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { const mobj_t *mobj = (const mobj_t *)th; UINT32 diff; - UINT16 diff2; + UINT32 diff2; // Ignore stationary hoops - these will be respawned from mapthings. if (mobj->type == MT_HOOP) @@ -1541,7 +1687,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 = 0; // not the default but the most probable - if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0) + if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz !=0) diff |= MD_MOM; if (mobj->radius != mobj->info->radius) diff |= MD_RADIUS; @@ -1638,7 +1784,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_SHADOWSCALE; if (mobj->renderflags) diff2 |= MD2_RENDERFLAGS; - if (mobj->renderflags) + if (mobj->blendmode != AST_TRANSLUCENT) diff2 |= MD2_BLENDMODE; if (mobj->spritexscale != FRACUNIT) diff2 |= MD2_SPRITEXSCALE; @@ -1646,6 +1792,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_SPRITEYSCALE; if (mobj->spritexoffset) diff2 |= MD2_SPRITEXOFFSET; + if (mobj->spriteyoffset) + diff2 |= MD2_SPRITEYOFFSET; if (mobj->floorspriteslope) { pslope_t *slope = mobj->floorspriteslope; @@ -1667,7 +1815,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, type); WRITEUINT32(save_p, diff); if (diff & MD_MORE) - WRITEUINT16(save_p, diff2); + WRITEUINT32(save_p, diff2); // save pointer, at load time we will search this pointer to reinitilize pointers WRITEUINT32(save_p, (size_t)mobj); @@ -1714,6 +1862,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, mobj->momx); WRITEFIXED(save_p, mobj->momy); WRITEFIXED(save_p, mobj->momz); + WRITEFIXED(save_p, mobj->pmomz); } if (diff & MD_RADIUS) WRITEFIXED(save_p, mobj->radius); @@ -1920,7 +2069,6 @@ static void SaveEachTimeThinker(const thinker_t *th, const UINT8 type) for (i = 0; i < MAXPLAYERS; i++) { WRITECHAR(save_p, ht->playersInArea[i]); - WRITECHAR(save_p, ht->playersOnArea[i]); } WRITECHAR(save_p, ht->triggerOnExit); } @@ -1948,14 +2096,12 @@ static void SaveCeilingThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->bottomheight); WRITEFIXED(save_p, ht->topheight); WRITEFIXED(save_p, ht->speed); - WRITEFIXED(save_p, ht->oldspeed); WRITEFIXED(save_p, ht->delay); WRITEFIXED(save_p, ht->delaytimer); WRITEUINT8(save_p, ht->crush); WRITEINT32(save_p, ht->texture); WRITEINT32(save_p, ht->direction); - WRITEINT32(save_p, ht->tag); - WRITEINT32(save_p, ht->olddirection); + WRITEINT16(save_p, ht->tag); WRITEFIXED(save_p, ht->origspeed); WRITEFIXED(save_p, ht->sourceline); } @@ -1974,6 +2120,8 @@ static void SaveFloormoveThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, ht->origspeed); WRITEFIXED(save_p, ht->delay); WRITEFIXED(save_p, ht->delaytimer); + WRITEINT16(save_p, ht->tag); + WRITEFIXED(save_p, ht->sourceline); } static void SaveLightflashThinker(const thinker_t *th, const UINT8 type) @@ -1991,8 +2139,8 @@ static void SaveStrobeThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, type); WRITEUINT32(save_p, SaveSector(ht->sector)); WRITEINT32(save_p, ht->count); - WRITEINT32(save_p, ht->minlight); - WRITEINT32(save_p, ht->maxlight); + WRITEINT16(save_p, ht->minlight); + WRITEINT16(save_p, ht->maxlight); WRITEINT32(save_p, ht->darktime); WRITEINT32(save_p, ht->brighttime); } @@ -2002,10 +2150,10 @@ static void SaveGlowThinker(const thinker_t *th, const UINT8 type) const glow_t *ht = (const void *)th; WRITEUINT8(save_p, type); WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->minlight); - WRITEINT32(save_p, ht->maxlight); - WRITEINT32(save_p, ht->direction); - WRITEINT32(save_p, ht->speed); + WRITEINT16(save_p, ht->minlight); + WRITEINT16(save_p, ht->maxlight); + WRITEINT16(save_p, ht->direction); + WRITEINT16(save_p, ht->speed); } static inline void SaveFireflickerThinker(const thinker_t *th, const UINT8 type) @@ -2015,8 +2163,8 @@ static inline void SaveFireflickerThinker(const thinker_t *th, const UINT8 type) WRITEUINT32(save_p, SaveSector(ht->sector)); WRITEINT32(save_p, ht->count); WRITEINT32(save_p, ht->resetcount); - WRITEINT32(save_p, ht->maxlight); - WRITEINT32(save_p, ht->minlight); + WRITEINT16(save_p, ht->maxlight); + WRITEINT16(save_p, ht->minlight); } static void SaveElevatorThinker(const thinker_t *th, const UINT8 type) @@ -2090,13 +2238,9 @@ static inline void SavePusherThinker(const thinker_t *th, const UINT8 type) const pusher_t *ht = (const void *)th; WRITEUINT8(save_p, type); WRITEUINT8(save_p, ht->type); - WRITEINT32(save_p, ht->x_mag); - WRITEINT32(save_p, ht->y_mag); - WRITEINT32(save_p, ht->magnitude); - WRITEINT32(save_p, ht->radius); - WRITEINT32(save_p, ht->x); - WRITEINT32(save_p, ht->y); - WRITEINT32(save_p, ht->z); + WRITEFIXED(save_p, ht->x_mag); + WRITEFIXED(save_p, ht->y_mag); + WRITEFIXED(save_p, ht->z_mag); WRITEINT32(save_p, ht->affectee); WRITEUINT8(save_p, ht->roverpusher); WRITEINT32(save_p, ht->referrer); @@ -2194,18 +2338,30 @@ static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type) WRITEUINT8(save_p, ht->type); } -static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type) +static inline void SaveDynamicLineSlopeThinker(const thinker_t *th, const UINT8 type) { - const dynplanethink_t* ht = (const void*)th; + const dynlineplanethink_t* ht = (const void*)th; WRITEUINT8(save_p, type); WRITEUINT8(save_p, ht->type); WRITEUINT32(save_p, SaveSlope(ht->slope)); WRITEUINT32(save_p, SaveLine(ht->sourceline)); WRITEFIXED(save_p, ht->extent); +} - WRITEMEM(save_p, ht->tags, sizeof(ht->tags)); - WRITEMEM(save_p, ht->vex, sizeof(ht->vex)); +static inline void SaveDynamicVertexSlopeThinker(const thinker_t *th, const UINT8 type) +{ + size_t i; + const dynvertexplanethink_t* ht = (const void*)th; + + WRITEUINT8(save_p, type); + WRITEUINT32(save_p, SaveSlope(ht->slope)); + for (i = 0; i < 3; i++) + WRITEUINT32(save_p, SaveSector(ht->secs[i])); + WRITEMEM(save_p, ht->vex, sizeof(ht->vex)); + WRITEMEM(save_p, ht->origsecheights, sizeof(ht->origsecheights)); + WRITEMEM(save_p, ht->origvecheights, sizeof(ht->origvecheights)); + WRITEUINT8(save_p, ht->relative); } static inline void SavePolyrotatetThinker(const thinker_t *th, const UINT8 type) @@ -2530,12 +2686,12 @@ static void P_NetArchiveThinkers(void) } else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine) { - SaveDynamicSlopeThinker(th, tc_dynslopeline); + SaveDynamicLineSlopeThinker(th, tc_dynslopeline); continue; } else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeVert) { - SaveDynamicSlopeThinker(th, tc_dynslopevert); + SaveDynamicVertexSlopeThinker(th, tc_dynslopevert); continue; } #ifdef PARANOIA @@ -2615,14 +2771,14 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) thinker_t *next; mobj_t *mobj; UINT32 diff; - UINT16 diff2; + UINT32 diff2; INT32 i; fixed_t z, floorz, ceilingz; ffloor_t *floorrover = NULL, *ceilingrover = NULL; diff = READUINT32(save_p); if (diff & MD_MORE) - diff2 = READUINT16(save_p); + diff2 = READUINT32(save_p); else diff2 = 0; @@ -2650,7 +2806,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) { UINT16 spawnpointnum = READUINT16(save_p); - if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case + if (mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case { P_SpawnHoop(&mapthings[spawnpointnum]); return NULL; @@ -2712,6 +2868,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->momx = READFIXED(save_p); mobj->momy = READFIXED(save_p); mobj->momz = READFIXED(save_p); + mobj->pmomz = READFIXED(save_p); } // otherwise they're zero, and the memset took care of it if (diff & MD_RADIUS) @@ -2843,10 +3000,16 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->renderflags = READUINT32(save_p); if (diff2 & MD2_BLENDMODE) mobj->blendmode = READINT32(save_p); + else + mobj->blendmode = AST_TRANSLUCENT; if (diff2 & MD2_SPRITEXSCALE) mobj->spritexscale = READFIXED(save_p); + else + mobj->spritexscale = FRACUNIT; if (diff2 & MD2_SPRITEYSCALE) mobj->spriteyscale = READFIXED(save_p); + else + mobj->spriteyscale = FRACUNIT; if (diff2 & MD2_SPRITEXOFFSET) mobj->spritexoffset = READFIXED(save_p); if (diff2 & MD2_SPRITEYOFFSET) @@ -3018,7 +3181,6 @@ static thinker_t* LoadEachTimeThinker(actionf_p1 thinker) for (i = 0; i < MAXPLAYERS; i++) { ht->playersInArea[i] = READCHAR(save_p); - ht->playersOnArea[i] = READCHAR(save_p); } ht->triggerOnExit = READCHAR(save_p); return &ht->thinker; @@ -3048,14 +3210,12 @@ static thinker_t* LoadCeilingThinker(actionf_p1 thinker) ht->bottomheight = READFIXED(save_p); ht->topheight = READFIXED(save_p); ht->speed = READFIXED(save_p); - ht->oldspeed = READFIXED(save_p); ht->delay = READFIXED(save_p); ht->delaytimer = READFIXED(save_p); ht->crush = READUINT8(save_p); ht->texture = READINT32(save_p); ht->direction = READINT32(save_p); - ht->tag = READINT32(save_p); - ht->olddirection = READINT32(save_p); + ht->tag = READINT16(save_p); ht->origspeed = READFIXED(save_p); ht->sourceline = READFIXED(save_p); if (ht->sector) @@ -3077,6 +3237,8 @@ static thinker_t* LoadFloormoveThinker(actionf_p1 thinker) ht->origspeed = READFIXED(save_p); ht->delay = READFIXED(save_p); ht->delaytimer = READFIXED(save_p); + ht->tag = READINT16(save_p); + ht->sourceline = READFIXED(save_p); if (ht->sector) ht->sector->floordata = ht; return &ht->thinker; @@ -3100,8 +3262,8 @@ static thinker_t* LoadStrobeThinker(actionf_p1 thinker) ht->thinker.function.acp1 = thinker; ht->sector = LoadSector(READUINT32(save_p)); ht->count = READINT32(save_p); - ht->minlight = READINT32(save_p); - ht->maxlight = READINT32(save_p); + ht->minlight = READINT16(save_p); + ht->maxlight = READINT16(save_p); ht->darktime = READINT32(save_p); ht->brighttime = READINT32(save_p); if (ht->sector) @@ -3114,10 +3276,10 @@ static thinker_t* LoadGlowThinker(actionf_p1 thinker) glow_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; ht->sector = LoadSector(READUINT32(save_p)); - ht->minlight = READINT32(save_p); - ht->maxlight = READINT32(save_p); - ht->direction = READINT32(save_p); - ht->speed = READINT32(save_p); + ht->minlight = READINT16(save_p); + ht->maxlight = READINT16(save_p); + ht->direction = READINT16(save_p); + ht->speed = READINT16(save_p); if (ht->sector) ht->sector->lightingdata = ht; return &ht->thinker; @@ -3130,8 +3292,8 @@ static thinker_t* LoadFireflickerThinker(actionf_p1 thinker) ht->sector = LoadSector(READUINT32(save_p)); ht->count = READINT32(save_p); ht->resetcount = READINT32(save_p); - ht->maxlight = READINT32(save_p); - ht->minlight = READINT32(save_p); + ht->maxlight = READINT16(save_p); + ht->minlight = READINT16(save_p); if (ht->sector) ht->sector->lightingdata = ht; return &ht->thinker; @@ -3223,19 +3385,14 @@ static thinker_t* LoadPusherThinker(actionf_p1 thinker) pusher_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; ht->type = READUINT8(save_p); - ht->x_mag = READINT32(save_p); - ht->y_mag = READINT32(save_p); - ht->magnitude = READINT32(save_p); - ht->radius = READINT32(save_p); - ht->x = READINT32(save_p); - ht->y = READINT32(save_p); - ht->z = READINT32(save_p); + ht->x_mag = READFIXED(save_p); + ht->y_mag = READFIXED(save_p); + ht->z_mag = READFIXED(save_p); ht->affectee = READINT32(save_p); ht->roverpusher = READUINT8(save_p); ht->referrer = READINT32(save_p); ht->exclusive = READINT32(save_p); ht->slider = READINT32(save_p); - ht->source = P_GetPushThing(ht->affectee); return &ht->thinker; } @@ -3359,17 +3516,31 @@ static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker) return &ht->thinker; } -static inline thinker_t* LoadDynamicSlopeThinker(actionf_p1 thinker) +static inline thinker_t* LoadDynamicLineSlopeThinker(actionf_p1 thinker) { - dynplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); + dynlineplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; ht->type = READUINT8(save_p); ht->slope = LoadSlope(READUINT32(save_p)); ht->sourceline = LoadLine(READUINT32(save_p)); ht->extent = READFIXED(save_p); - READMEM(save_p, ht->tags, sizeof(ht->tags)); + return &ht->thinker; +} + +static inline thinker_t* LoadDynamicVertexSlopeThinker(actionf_p1 thinker) +{ + size_t i; + dynvertexplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + + ht->slope = LoadSlope(READUINT32(save_p)); + for (i = 0; i < 3; i++) + ht->secs[i] = LoadSector(READUINT32(save_p)); READMEM(save_p, ht->vex, sizeof(ht->vex)); + READMEM(save_p, ht->origsecheights, sizeof(ht->origsecheights)); + READMEM(save_p, ht->origvecheights, sizeof(ht->origvecheights)); + ht->relative = READUINT8(save_p); return &ht->thinker; } @@ -3682,11 +3853,11 @@ static void P_NetUnArchiveThinkers(void) break; case tc_dynslopeline: - th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeLine); + th = LoadDynamicLineSlopeThinker((actionf_p1)T_DynamicSlopeLine); break; case tc_dynslopevert: - th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeVert); + th = LoadDynamicVertexSlopeThinker((actionf_p1)T_DynamicSlopeVert); break; case tc_scroll: @@ -4182,7 +4353,10 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) tokenlist = READUINT32(save_p); if (!P_LoadLevel(true, reloading)) + { + CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n")); return false; + } // get the time leveltime = READUINT32(save_p); @@ -4260,19 +4434,26 @@ static inline boolean P_UnArchiveLuabanksAndConsistency(void) { switch (READUINT8(save_p)) { - case 0xb7: + case 0xb7: // luabanks marker { UINT8 i, banksinuse = READUINT8(save_p); if (banksinuse > NUM_LUABANKS) + { + CONS_Alert(CONS_ERROR, M_GetText("Corrupt Luabanks! (Too many banks in use)\n")); return false; + } for (i = 0; i < banksinuse; i++) luabanks[i] = READINT32(save_p); - if (READUINT8(save_p) != 0x1d) + if (READUINT8(save_p) != 0x1d) // consistency marker + { + CONS_Alert(CONS_ERROR, M_GetText("Corrupt Luabanks! (Failed consistency check)\n")); return false; + } } - case 0x1d: + case 0x1d: // consistency marker break; - default: + default: // anything else is nonsense + CONS_Alert(CONS_ERROR, M_GetText("Failed consistency check (???)\n")); return false; } diff --git a/src/p_saveg.h b/src/p_saveg.h index be98953eb..9f4a2633f 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -18,6 +18,8 @@ #pragma interface #endif +#define NEWSKINSAVES (INT16_MAX) // Purely for backwards compatibility, remove this for 2.3 + // Persistent storage/archiving. // These are the load / save game routines. diff --git a/src/p_setup.c b/src/p_setup.c index 41d8822e2..146d5d302 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -65,7 +65,7 @@ #include "md5.h" // map MD5 -// for LUAh_MapLoad +// for MapLoad hook #include "lua_script.h" #include "lua_hook.h" @@ -508,6 +508,17 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) return mapheaderinfo[map-1]->grades[mare].grade[grade-1]; } +UINT32 P_GetScoreForGradeOverall(INT16 map, UINT8 grade) +{ + UINT8 mares; + INT32 i; + UINT32 score = 0; + mares = mapheaderinfo[map-1]->numGradedMares; + for (i = 0; i < mares; ++i) + score += P_GetScoreForGrade(map, i, grade); + return score; +} + // // levelflats // @@ -734,7 +745,7 @@ void P_ReloadRings(void) mt->mobj = NULL; P_SetBonusTime(P_SpawnMapThing(mt)); } - else if (mt->type >= 600 && mt->type <= 609) // Item patterns + else if (mt->type >= 600 && mt->type <= 611) // Item patterns { mt->mobj = NULL; P_SpawnItemPattern(mt, true); @@ -893,9 +904,9 @@ static void P_SpawnMapThings(boolean spawnemblems) mt->mobj = NULL; - if (mt->type >= 600 && mt->type <= 609) // item patterns + if (mt->type >= 600 && mt->type <= 611) // item patterns P_SpawnItemPattern(mt, false); - else if (mt->type == 1705 || mt->type == 1713) // hoops + else if (mt->type == 1713) // hoops P_SpawnHoop(mt); else // Everything else P_SpawnMapThing(mt); @@ -907,7 +918,7 @@ static void P_SpawnMapThings(boolean spawnemblems) } // Experimental groovy write function! -void P_WriteThings(void) +/*void P_WriteThings(void) { size_t i, length; mapthing_t *mt; @@ -942,7 +953,7 @@ void P_WriteThings(void) savebuf_p = NULL; CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap); -} +}*/ // // MAP LOADING FUNCTIONS @@ -999,9 +1010,7 @@ static void P_InitializeSector(sector_t *ss) ss->extra_colormap = NULL; - ss->gravity = NULL; - ss->verticalflip = false; - ss->flags = SF_FLIPSPECIAL_FLOOR; + ss->gravityptr = NULL; ss->cullheight = NULL; @@ -1043,8 +1052,21 @@ static void P_LoadSectors(UINT8 *data) ss->floorpic_angle = ss->ceilingpic_angle = 0; + ss->floorlightlevel = ss->ceilinglightlevel = 0; + ss->floorlightabsolute = ss->ceilinglightabsolute = false; + ss->colormap_protected = false; + ss->gravity = FRACUNIT; + + ss->flags = MSF_FLIPSPECIAL_FLOOR; + ss->specialflags = 0; + ss->damagetype = SD_NONE; + ss->triggertag = 0; + ss->triggerer = TO_PLAYER; + + ss->friction = ORIG_FRICTION; + P_InitializeSector(ss); } } @@ -1058,6 +1080,8 @@ static void P_InitializeLinedef(line_t *ld) ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; + ld->angle = R_PointToAngle2(0, 0, ld->dx, ld->dy); + ld->bbox[BOXLEFT] = min(v1->x, v2->x); ld->bbox[BOXRIGHT] = max(v1->x, v2->x); ld->bbox[BOXBOTTOM] = min(v1->y, v2->y); @@ -1201,7 +1225,7 @@ static void P_LoadSidedefs(UINT8 *data) isfrontside = sd->line->sidenum[0] == i; // Repeat count for midtexture - if (((sd->line->flags & (ML_TWOSIDED|ML_EFFECT5)) == (ML_TWOSIDED|ML_EFFECT5)) + if (((sd->line->flags & (ML_TWOSIDED|ML_WRAPMIDTEX)) == (ML_TWOSIDED|ML_WRAPMIDTEX)) && !(sd->special >= 300 && sd->special < 500)) // exempt linedef exec specials { sd->repeatcnt = (INT16)(((UINT16)textureoffset) >> 12); @@ -1224,11 +1248,8 @@ static void P_LoadSidedefs(UINT8 *data) case 455: // Fade colormaps! mazmazz 9/12/2018 (:flag_us:) // SoM: R_CreateColormap will only create a colormap in software mode... // Perhaps we should just call it instead of doing the calculations here. - if (!udmf) - { - sd->colormap_data = R_CreateColormapFromLinedef(msd->toptexture, msd->midtexture, msd->bottomtexture); - sd->toptexture = sd->midtexture = sd->bottomtexture = 0; - } + sd->colormap_data = R_CreateColormapFromLinedef(msd->toptexture, msd->midtexture, msd->bottomtexture); + sd->toptexture = sd->midtexture = sd->bottomtexture = 0; break; case 413: // Change music @@ -1270,7 +1291,6 @@ static void P_LoadSidedefs(UINT8 *data) } case 4: // Speed pad parameters - case 414: // Play SFX { sd->toptexture = sd->midtexture = sd->bottomtexture = 0; if (msd->toptexture[0] != '-' || msd->toptexture[1] != '\0') @@ -1283,17 +1303,23 @@ static void P_LoadSidedefs(UINT8 *data) break; } + case 414: // Play SFX + { + sd->toptexture = sd->midtexture = sd->bottomtexture = 0; + if (msd->toptexture[0] != '-' || msd->toptexture[1] != '\0') + { + char process[8 + 1]; + M_Memcpy(process, msd->toptexture, 8); + process[8] = '\0'; + sd->text = Z_Malloc(strlen(process) + 1, PU_LEVEL, NULL); + M_Memcpy(sd->text, process, strlen(process) + 1); + } + break; + } + case 9: // Mace parameters case 14: // Bustable block parameters case 15: // Fan particle spawner parameters - case 334: // Trigger linedef executor: Object dye - Continuous - case 335: // Trigger linedef executor: Object dye - Each time - case 336: // Trigger linedef executor: Object dye - Once - case 425: // Calls P_SetMobjState on calling mobj - case 434: // Custom Power - case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors - case 461: // Spawns an object on the map based on texture offsets - case 463: // Colorizes an object { char process[8*3+1]; memset(process,0,8*3+1); @@ -1313,8 +1339,16 @@ static void P_LoadSidedefs(UINT8 *data) case 331: // Trigger linedef executor: Skin - Continuous case 332: // Trigger linedef executor: Skin - Each time case 333: // Trigger linedef executor: Skin - Once + case 334: // Trigger linedef executor: Object dye - Continuous + case 335: // Trigger linedef executor: Object dye - Each time + case 336: // Trigger linedef executor: Object dye - Once + case 425: // Calls P_SetMobjState on calling mobj + case 434: // Custom Power + case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors case 443: // Calls a named Lua function case 459: // Control text prompt (named tag) + case 461: // Spawns an object on the map based on texture offsets + case 463: // Colorizes an object { char process[8*3+1]; memset(process,0,8*3+1); @@ -1350,8 +1384,11 @@ static void P_LoadSidedefs(UINT8 *data) if (msd->toptexture[0] == '#') { char *col = msd->toptexture; - sd->toptexture = sd->bottomtexture = - ((col[1]-'0')*100 + (col[2]-'0')*10 + col[3]-'0') + 1; + sd->toptexture = + ((col[1]-'0')*100 + (col[2]-'0')*10 + col[3]-'0')+1; + if (col[4]) // extra num for blendmode + sd->toptexture += (col[4]-'0')*1000; + sd->bottomtexture = sd->toptexture; sd->midtexture = R_TextureNumForName(msd->midtexture); } else @@ -1404,9 +1441,9 @@ UINT32 vertexesPos[UINT16_MAX]; UINT32 sectorsPos[UINT16_MAX]; // Determine total amount of map data in TEXTMAP. -static boolean TextmapCount(UINT8 *data, size_t size) +static boolean TextmapCount(size_t size) { - char *tkn = M_GetToken((char *)data); + const char *tkn = M_TokenizerRead(0); UINT8 brackets = 0; nummapthings = 0; @@ -1418,20 +1455,16 @@ static boolean TextmapCount(UINT8 *data, size_t size) // Look for namespace at the beginning. if (!fastcmp(tkn, "namespace")) { - Z_Free(tkn); CONS_Alert(CONS_ERROR, "No namespace at beginning of lump!\n"); return false; } - Z_Free(tkn); // Check if namespace is valid. - tkn = M_GetToken(NULL); + tkn = M_TokenizerRead(0); if (!fastcmp(tkn, "srb2")) CONS_Alert(CONS_WARNING, "Invalid namespace '%s', only 'srb2' is supported.\n", tkn); - Z_Free(tkn); - tkn = M_GetToken(NULL); - while (tkn && M_GetTokenPos() < size) + while ((tkn = M_TokenizerRead(0)) && M_TokenizerGetEndPos() < size) { // Avoid anything inside bracketed stuff, only look for external keywords. if (brackets) @@ -1443,24 +1476,19 @@ static boolean TextmapCount(UINT8 *data, size_t size) brackets++; // Check for valid fields. else if (fastcmp(tkn, "thing")) - mapthingsPos[nummapthings++] = M_GetTokenPos(); + mapthingsPos[nummapthings++] = M_TokenizerGetEndPos(); else if (fastcmp(tkn, "linedef")) - linesPos[numlines++] = M_GetTokenPos(); + linesPos[numlines++] = M_TokenizerGetEndPos(); else if (fastcmp(tkn, "sidedef")) - sidesPos[numsides++] = M_GetTokenPos(); + sidesPos[numsides++] = M_TokenizerGetEndPos(); else if (fastcmp(tkn, "vertex")) - vertexesPos[numvertexes++] = M_GetTokenPos(); + vertexesPos[numvertexes++] = M_TokenizerGetEndPos(); else if (fastcmp(tkn, "sector")) - sectorsPos[numsectors++] = M_GetTokenPos(); + sectorsPos[numsectors++] = M_TokenizerGetEndPos(); else CONS_Alert(CONS_NOTICE, "Unknown field '%s'.\n", tkn); - - Z_Free(tkn); - tkn = M_GetToken(NULL); } - Z_Free(tkn); - if (brackets) { CONS_Alert(CONS_ERROR, "Unclosed brackets detected in textmap lump.\n"); @@ -1470,7 +1498,7 @@ static boolean TextmapCount(UINT8 *data, size_t size) return true; } -static void ParseTextmapVertexParameter(UINT32 i, char *param, char *val) +static void ParseTextmapVertexParameter(UINT32 i, const char *param, const char *val) { if (fastcmp(param, "x")) vertexes[i].x = FLOAT_TO_FIXED(atof(val)); @@ -1501,7 +1529,23 @@ typedef struct textmap_colormap_s { textmap_colormap_t textmap_colormap = { false, 0, 25, 0, 25, 0, 31, 0 }; -static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) +typedef enum +{ + PD_A = 1, + PD_B = 1<<1, + PD_C = 1<<2, + PD_D = 1<<3, +} planedef_t; + +typedef struct textmap_plane_s { + UINT8 defined; + fixed_t a, b, c, d; +} textmap_plane_t; + +textmap_plane_t textmap_planefloor = {0, 0, 0, 0, 0}; +textmap_plane_t textmap_planeceiling = {0, 0, 0, 0, 0}; + +static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char *val) { if (fastcmp(param, "heightfloor")) sectors[i].floorheight = atol(val) << FRACBITS; @@ -1513,13 +1557,19 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) sectors[i].ceilingpic = P_AddLevelFlat(val, foundflats); else if (fastcmp(param, "lightlevel")) sectors[i].lightlevel = atol(val); - else if (fastcmp(param, "special")) - sectors[i].special = atol(val); + else if (fastcmp(param, "lightfloor")) + sectors[i].floorlightlevel = atol(val); + else if (fastcmp(param, "lightfloorabsolute") && fastcmp("true", val)) + sectors[i].floorlightabsolute = true; + else if (fastcmp(param, "lightceiling")) + sectors[i].ceilinglightlevel = atol(val); + else if (fastcmp(param, "lightceilingabsolute") && fastcmp("true", val)) + sectors[i].ceilinglightabsolute = true; else if (fastcmp(param, "id")) Tag_FSet(§ors[i].tags, atol(val)); else if (fastcmp(param, "moreids")) { - char* id = val; + const char* id = val; while (id) { Tag_Add(§ors[i].tags, atol(id)); @@ -1539,6 +1589,46 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) sectors[i].floorpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); else if (fastcmp(param, "rotationceiling")) sectors[i].ceilingpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val))); + else if (fastcmp(param, "floorplane_a")) + { + textmap_planefloor.defined |= PD_A; + textmap_planefloor.a = FLOAT_TO_FIXED(atof(val)); + } + else if (fastcmp(param, "floorplane_b")) + { + textmap_planefloor.defined |= PD_B; + textmap_planefloor.b = FLOAT_TO_FIXED(atof(val)); + } + else if (fastcmp(param, "floorplane_c")) + { + textmap_planefloor.defined |= PD_C; + textmap_planefloor.c = FLOAT_TO_FIXED(atof(val)); + } + else if (fastcmp(param, "floorplane_d")) + { + textmap_planefloor.defined |= PD_D; + textmap_planefloor.d = FLOAT_TO_FIXED(atof(val)); + } + else if (fastcmp(param, "ceilingplane_a")) + { + textmap_planeceiling.defined |= PD_A; + textmap_planeceiling.a = FLOAT_TO_FIXED(atof(val)); + } + else if (fastcmp(param, "ceilingplane_b")) + { + textmap_planeceiling.defined |= PD_B; + textmap_planeceiling.b = FLOAT_TO_FIXED(atof(val)); + } + else if (fastcmp(param, "ceilingplane_c")) + { + textmap_planeceiling.defined |= PD_C; + textmap_planeceiling.c = FLOAT_TO_FIXED(atof(val)); + } + else if (fastcmp(param, "ceilingplane_d")) + { + textmap_planeceiling.defined |= PD_D; + textmap_planeceiling.d = FLOAT_TO_FIXED(atof(val)); + } else if (fastcmp(param, "lightcolor")) { textmap_colormap.used = true; @@ -1581,9 +1671,94 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) } else if (fastcmp(param, "colormapprotected") && fastcmp("true", val)) sectors[i].colormap_protected = true; + else if (fastcmp(param, "flipspecial_nofloor") && fastcmp("true", val)) + sectors[i].flags &= ~MSF_FLIPSPECIAL_FLOOR; + else if (fastcmp(param, "flipspecial_ceiling") && fastcmp("true", val)) + sectors[i].flags |= MSF_FLIPSPECIAL_CEILING; + else if (fastcmp(param, "triggerspecial_touch") && fastcmp("true", val)) + sectors[i].flags |= MSF_TRIGGERSPECIAL_TOUCH; + else if (fastcmp(param, "triggerspecial_headbump") && fastcmp("true", val)) + sectors[i].flags |= MSF_TRIGGERSPECIAL_HEADBUMP; + else if (fastcmp(param, "triggerline_plane") && fastcmp("true", val)) + sectors[i].flags |= MSF_TRIGGERLINE_PLANE; + else if (fastcmp(param, "triggerline_mobj") && fastcmp("true", val)) + sectors[i].flags |= MSF_TRIGGERLINE_MOBJ; + else if (fastcmp(param, "invertprecip") && fastcmp("true", val)) + sectors[i].flags |= MSF_INVERTPRECIP; + else if (fastcmp(param, "gravityflip") && fastcmp("true", val)) + sectors[i].flags |= MSF_GRAVITYFLIP; + else if (fastcmp(param, "heatwave") && fastcmp("true", val)) + sectors[i].flags |= MSF_HEATWAVE; + else if (fastcmp(param, "noclipcamera") && fastcmp("true", val)) + sectors[i].flags |= MSF_NOCLIPCAMERA; + else if (fastcmp(param, "outerspace") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_OUTERSPACE; + else if (fastcmp(param, "doublestepup") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_DOUBLESTEPUP; + else if (fastcmp(param, "nostepdown") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_NOSTEPDOWN; + else if (fastcmp(param, "speedpad") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_SPEEDPAD; + else if (fastcmp(param, "starpostactivator") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_STARPOSTACTIVATOR; + else if (fastcmp(param, "exit") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_EXIT; + else if (fastcmp(param, "specialstagepit") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_SPECIALSTAGEPIT; + else if (fastcmp(param, "returnflag") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_RETURNFLAG; + else if (fastcmp(param, "redteambase") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_REDTEAMBASE; + else if (fastcmp(param, "blueteambase") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_BLUETEAMBASE; + else if (fastcmp(param, "fan") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_FAN; + else if (fastcmp(param, "supertransform") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_SUPERTRANSFORM; + else if (fastcmp(param, "forcespin") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_FORCESPIN; + else if (fastcmp(param, "zoomtubestart") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_ZOOMTUBESTART; + else if (fastcmp(param, "zoomtubeend") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_ZOOMTUBEEND; + else if (fastcmp(param, "finishline") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_FINISHLINE; + else if (fastcmp(param, "ropehang") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_ROPEHANG; + else if (fastcmp(param, "friction")) + sectors[i].friction = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "gravity")) + sectors[i].gravity = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "damagetype")) + { + if (fastcmp(val, "Generic")) + sectors[i].damagetype = SD_GENERIC; + if (fastcmp(val, "Water")) + sectors[i].damagetype = SD_WATER; + if (fastcmp(val, "Fire")) + sectors[i].damagetype = SD_FIRE; + if (fastcmp(val, "Lava")) + sectors[i].damagetype = SD_LAVA; + if (fastcmp(val, "Electric")) + sectors[i].damagetype = SD_ELECTRIC; + if (fastcmp(val, "Spike")) + sectors[i].damagetype = SD_SPIKE; + if (fastcmp(val, "DeathPitTilt")) + sectors[i].damagetype = SD_DEATHPITTILT; + if (fastcmp(val, "DeathPitNoTilt")) + sectors[i].damagetype = SD_DEATHPITNOTILT; + if (fastcmp(val, "Instakill")) + sectors[i].damagetype = SD_INSTAKILL; + if (fastcmp(val, "SpecialStage")) + sectors[i].damagetype = SD_SPECIALSTAGE; + } + else if (fastcmp(param, "triggertag")) + sectors[i].triggertag = atol(val); + else if (fastcmp(param, "triggerer")) + sectors[i].triggerer = atol(val); } -static void ParseTextmapSidedefParameter(UINT32 i, char *param, char *val) +static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val) { if (fastcmp(param, "offsetx")) sides[i].textureoffset = atol(val)< 9) { - size_t argnum = param[3] - '0'; + size_t argnum = atol(param + 9); if (argnum >= NUMLINESTRINGARGS) return; lines[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL); @@ -1642,6 +1817,21 @@ static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val) lines[i].sidenum[1] = atol(val); else if (fastcmp(param, "alpha")) lines[i].alpha = FLOAT_TO_FIXED(atof(val)); + else if (fastcmp(param, "blendmode") || fastcmp(param, "renderstyle")) + { + if (fastcmp(val, "translucent")) + lines[i].blendmode = AST_COPY; + else if (fastcmp(val, "add")) + lines[i].blendmode = AST_ADD; + else if (fastcmp(val, "subtract")) + lines[i].blendmode = AST_SUBTRACT; + else if (fastcmp(val, "reversesubtract")) + lines[i].blendmode = AST_REVERSESUBTRACT; + else if (fastcmp(val, "modulate")) + lines[i].blendmode = AST_MODULATE; + if (fastcmp(val, "fog")) + lines[i].blendmode = AST_FOG; + } else if (fastcmp(param, "executordelay")) lines[i].executordelay = atol(val); @@ -1657,19 +1847,19 @@ static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val) else if (fastcmp(param, "dontpegbottom") && fastcmp("true", val)) lines[i].flags |= ML_DONTPEGBOTTOM; else if (fastcmp(param, "skewtd") && fastcmp("true", val)) - lines[i].flags |= ML_EFFECT1; + lines[i].flags |= ML_SKEWTD; else if (fastcmp(param, "noclimb") && fastcmp("true", val)) lines[i].flags |= ML_NOCLIMB; else if (fastcmp(param, "noskew") && fastcmp("true", val)) - lines[i].flags |= ML_EFFECT2; + lines[i].flags |= ML_NOSKEW; else if (fastcmp(param, "midpeg") && fastcmp("true", val)) - lines[i].flags |= ML_EFFECT3; + lines[i].flags |= ML_MIDPEG; else if (fastcmp(param, "midsolid") && fastcmp("true", val)) - lines[i].flags |= ML_EFFECT4; + lines[i].flags |= ML_MIDSOLID; else if (fastcmp(param, "wrapmidtex") && fastcmp("true", val)) - lines[i].flags |= ML_EFFECT5; - else if (fastcmp(param, "effect6") && fastcmp("true", val)) - lines[i].flags |= ML_EFFECT6; + lines[i].flags |= ML_WRAPMIDTEX; + /*else if (fastcmp(param, "effect6") && fastcmp("true", val)) + lines[i].flags |= ML_EFFECT6;*/ else if (fastcmp(param, "nonet") && fastcmp("true", val)) lines[i].flags |= ML_NONET; else if (fastcmp(param, "netonly") && fastcmp("true", val)) @@ -1680,13 +1870,13 @@ static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val) lines[i].flags |= ML_TFERLINE; } -static void ParseTextmapThingParameter(UINT32 i, char *param, char *val) +static void ParseTextmapThingParameter(UINT32 i, const char *param, const char *val) { if (fastcmp(param, "id")) Tag_FSet(&mapthings[i].tags, atol(val)); else if (fastcmp(param, "moreids")) { - char* id = val; + const char* id = val; while (id) { Tag_Add(&mapthings[i].tags, atol(id)); @@ -1711,18 +1901,12 @@ static void ParseTextmapThingParameter(UINT32 i, char *param, char *val) else if (fastcmp(param, "scale") || fastcmp(param, "scalex") || fastcmp(param, "scaley")) mapthings[i].scale = FLOAT_TO_FIXED(atof(val)); // Flags - else if (fastcmp(param, "extra") && fastcmp("true", val)) - mapthings[i].options |= MTF_EXTRA; else if (fastcmp(param, "flip") && fastcmp("true", val)) mapthings[i].options |= MTF_OBJECTFLIP; - else if (fastcmp(param, "objectspecial") && fastcmp("true", val)) - mapthings[i].options |= MTF_OBJECTSPECIAL; - else if (fastcmp(param, "ambush") && fastcmp("true", val)) - mapthings[i].options |= MTF_AMBUSH; - else if (strlen(param) == 7 && fastncmp(param, "arg", 3) && fastncmp(param + 4, "str", 3)) + else if (fastncmp(param, "stringarg", 9) && strlen(param) > 9) { - size_t argnum = param[3] - '0'; + size_t argnum = atol(param + 9); if (argnum >= NUMMAPTHINGSTRINGARGS) return; mapthings[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL); @@ -1743,32 +1927,25 @@ static void ParseTextmapThingParameter(UINT32 i, char *param, char *val) * \param Structure number (mapthings, sectors, ...). * \param Parser function pointer. */ -static void TextmapParse(UINT32 dataPos, size_t num, void (*parser)(UINT32, char *, char *)) +static void TextmapParse(UINT32 dataPos, size_t num, void (*parser)(UINT32, const char *, const char *)) { - char *param, *val; + const char *param, *val; - M_SetTokenPos(dataPos); - param = M_GetToken(NULL); + M_TokenizerSetEndPos(dataPos); + param = M_TokenizerRead(0); if (!fastcmp(param, "{")) { - Z_Free(param); CONS_Alert(CONS_WARNING, "Invalid UDMF data capsule!\n"); return; } - Z_Free(param); while (true) { - param = M_GetToken(NULL); + param = M_TokenizerRead(0); if (fastcmp(param, "}")) - { - Z_Free(param); break; - } - val = M_GetToken(NULL); + val = M_TokenizerRead(1); parser(num, param, val); - Z_Free(param); - Z_Free(val); } } @@ -1797,6 +1974,29 @@ static void TextmapFixFlatOffsets(sector_t *sec) } } +static void TextmapUnfixFlatOffsets(sector_t *sec) +{ + if (sec->floorpic_angle) + { + fixed_t pc = FINECOSINE(sec->floorpic_angle >> ANGLETOFINESHIFT); + fixed_t ps = FINESINE(sec->floorpic_angle >> ANGLETOFINESHIFT); + fixed_t xoffs = sec->floor_xoffs; + fixed_t yoffs = sec->floor_yoffs; + sec->floor_xoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + sec->floor_yoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + } + + if (sec->ceilingpic_angle) + { + fixed_t pc = FINECOSINE(sec->ceilingpic_angle >> ANGLETOFINESHIFT); + fixed_t ps = FINESINE(sec->ceilingpic_angle >> ANGLETOFINESHIFT); + fixed_t xoffs = sec->ceiling_xoffs; + fixed_t yoffs = sec->ceiling_yoffs; + sec->ceiling_xoffs = (FixedMul(xoffs, ps) % MAXFLATSIZE) + (FixedMul(yoffs, pc) % MAXFLATSIZE); + sec->ceiling_yoffs = (FixedMul(xoffs, pc) % MAXFLATSIZE) - (FixedMul(yoffs, ps) % MAXFLATSIZE); + } +} + static INT32 P_ColorToRGBA(INT32 color, UINT8 alpha) { UINT8 r = (color >> 16) & 0xFF; @@ -1805,6 +2005,651 @@ static INT32 P_ColorToRGBA(INT32 color, UINT8 alpha) return R_PutRgbaRGBA(r, g, b, alpha); } +static INT32 P_RGBAToColor(INT32 rgba) +{ + UINT8 r = R_GetRgbaR(rgba); + UINT8 g = R_GetRgbaG(rgba); + UINT8 b = R_GetRgbaB(rgba); + return (r << 16) | (g << 8) | b; +} + +typedef struct +{ + mapthing_t *teleport; + mapthing_t *altview; + mapthing_t *angleanchor; +} sectorspecialthings_t; + +static void P_WriteTextmap(void) +{ + size_t i, j; + FILE *f; + char *filepath = va(pandf, srb2home, "TEXTMAP"); + mtag_t firsttag; + mapthing_t *wmapthings; + vertex_t *wvertexes; + sector_t *wsectors; + line_t *wlines; + side_t *wsides; + mtag_t freetag; + sectorspecialthings_t *specialthings; + + f = fopen(filepath, "w"); + if (!f) + { + CONS_Alert(CONS_ERROR, M_GetText("Couldn't save map file %s\n"), filepath); + return; + } + + wmapthings = Z_Calloc(nummapthings * sizeof(*mapthings), PU_LEVEL, NULL); + wvertexes = Z_Calloc(numvertexes * sizeof(*vertexes), PU_LEVEL, NULL); + wsectors = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL); + wlines = Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL); + wsides = Z_Calloc(numsides * sizeof(*sides), PU_LEVEL, NULL); + specialthings = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL); + + memcpy(wmapthings, mapthings, nummapthings * sizeof(*mapthings)); + memcpy(wvertexes, vertexes, numvertexes * sizeof(*vertexes)); + memcpy(wsectors, sectors, numsectors * sizeof(*sectors)); + memcpy(wlines, lines, numlines * sizeof(*lines)); + memcpy(wsides, sides, numsides * sizeof(*sides)); + + for (i = 0; i < nummapthings; i++) + if (mapthings[i].tags.count) + wmapthings[i].tags.tags = memcpy(Z_Malloc(mapthings[i].tags.count * sizeof(mtag_t), PU_LEVEL, NULL), mapthings[i].tags.tags, mapthings[i].tags.count * sizeof(mtag_t)); + + for (i = 0; i < numsectors; i++) + if (sectors[i].tags.count) + wsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); + + for (i = 0; i < numlines; i++) + if (lines[i].tags.count) + wlines[i].tags.tags = memcpy(Z_Malloc(lines[i].tags.count * sizeof(mtag_t), PU_LEVEL, NULL), lines[i].tags.tags, lines[i].tags.count * sizeof(mtag_t)); + + freetag = Tag_NextUnused(0); + + for (i = 0; i < nummapthings; i++) + { + subsector_t *ss; + INT32 s; + + if (wmapthings[i].type != 751 && wmapthings[i].type != 752 && wmapthings[i].type != 758) + continue; + + ss = R_PointInSubsector(wmapthings[i].x << FRACBITS, wmapthings[i].y << FRACBITS); + + if (!ss) + continue; + + s = ss->sector - sectors; + + switch (wmapthings[i].type) + { + case 751: + if (!specialthings[s].teleport) + specialthings[s].teleport = &wmapthings[i]; + break; + case 752: + if (!specialthings[s].altview) + specialthings[s].altview = &wmapthings[i]; + break; + case 758: + if (!specialthings[s].angleanchor) + specialthings[s].angleanchor = &wmapthings[i]; + break; + default: + break; + } + } + + for (i = 0; i < numlines; i++) + { + INT32 s; + + switch (wlines[i].special) + { + case 1: + TAG_ITER_SECTORS(Tag_FGet(&wlines[i].tags), s) + { + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s applies custom gravity to sector %d. Changes to this gravity at runtime will not be reflected in the converted map. Use linedef type 469 for this.\n"), sizeu1(i), s); + wsectors[s].gravity = FixedDiv(lines[i].frontsector->floorheight >> FRACBITS, 1000); + } + break; + case 2: + CONS_Alert(CONS_WARNING, M_GetText("Custom exit linedef %s detected. Changes to the next map at runtime will not be reflected in the converted map. Use linedef type 468 for this.\n"), sizeu1(i)); + wlines[i].args[0] = lines[i].frontsector->floorheight >> FRACBITS; + wlines[i].args[2] = lines[i].frontsector->ceilingheight >> FRACBITS; + break; + case 5: + case 50: + case 51: + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s has type %d, which is not supported in UDMF.\n"), sizeu1(i), wlines[i].special); + break; + case 61: + if (wlines[i].flags & ML_MIDSOLID) + continue; + if (!wlines[i].args[1]) + continue; + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s with crusher type 61 rises twice as fast on spawn. This behavior is not supported in UDMF.\n"), sizeu1(i)); + break; + case 76: + if (freetag == (mtag_t)MAXTAGS) + { + CONS_Alert(CONS_WARNING, M_GetText("No unused tag found. Linedef %s with type 76 cannot be converted.\n"), sizeu1(i)); + break; + } + TAG_ITER_SECTORS(wlines[i].args[0], s) + for (j = 0; (unsigned)j < wsectors[s].linecount; j++) + { + line_t *line = wsectors[s].lines[j] - lines + wlines; + if (line->special < 100 || line->special >= 300) + continue; + Tag_Add(&line->tags, freetag); + } + wlines[i].args[0] = freetag; + freetag = Tag_NextUnused(freetag); + break; + case 259: + if (wlines[i].args[3] & FF_QUICKSAND) + CONS_Alert(CONS_WARNING, M_GetText("Quicksand properties of custom FOF on linedef %s cannot be converted. Use linedef type 75 instead.\n"), sizeu1(i)); + if (wlines[i].args[3] & FF_BUSTUP) + CONS_Alert(CONS_WARNING, M_GetText("Bustable properties of custom FOF on linedef %s cannot be converted. Use linedef type 74 instead.\n"), sizeu1(i)); + break; + case 412: + if ((s = Tag_Iterate_Sectors(wlines[i].args[0], 0)) < 0) + break; + if (!specialthings[s].teleport) + break; + if (freetag == (mtag_t)MAXTAGS) + { + CONS_Alert(CONS_WARNING, M_GetText("No unused tag found. Linedef %s with type 412 cannot be converted.\n"), sizeu1(i)); + break; + } + Tag_Add(&specialthings[s].teleport->tags, freetag); + wlines[i].args[0] = freetag; + freetag = Tag_NextUnused(freetag); + break; + case 422: + if ((s = Tag_Iterate_Sectors(wlines[i].args[0], 0)) < 0) + break; + if (!specialthings[s].altview) + break; + if (freetag == (mtag_t)MAXTAGS) + { + CONS_Alert(CONS_WARNING, M_GetText("No unused tag found. Linedef %s with type 422 cannot be converted.\n"), sizeu1(i)); + break; + } + Tag_Add(&specialthings[s].altview->tags, freetag); + wlines[i].args[0] = freetag; + specialthings[s].altview->pitch = wlines[i].args[2]; + freetag = Tag_NextUnused(freetag); + break; + case 447: + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s has change colormap action, which cannot be converted automatically. Tag arg0 to a sector with the desired colormap.\n"), sizeu1(i)); + if (wlines[i].flags & ML_TFERLINE) + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s mixes front and back colormaps, which is not supported in UDMF. Copy one colormap to the target sector first, then mix in the second one.\n"), sizeu1(i)); + break; + case 455: + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s has fade colormap action, which cannot be converted automatically. Tag arg0 to a sector with the desired colormap.\n"), sizeu1(i)); + if (wlines[i].flags & ML_TFERLINE) + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s specifies starting colormap for the fade, which is not supported in UDMF. Change the colormap with linedef type 447 instead.\n"), sizeu1(i)); + break; + case 457: + if ((s = Tag_Iterate_Sectors(wlines[i].args[0], 0)) < 0) + break; + if (!specialthings[s].angleanchor) + break; + if (freetag == (mtag_t)MAXTAGS) + { + CONS_Alert(CONS_WARNING, M_GetText("No unused tag found. Linedef %s with type 457 cannot be converted.\n"), sizeu1(i)); + break; + } + Tag_Add(&specialthings[s].angleanchor->tags, freetag); + wlines[i].args[0] = freetag; + freetag = Tag_NextUnused(freetag); + break; + case 606: + if (wlines[i].args[0] == MTAG_GLOBAL) + { + sector_t *sec = wlines[i].frontsector - sectors + wsectors; + sec->extra_colormap = wsides[wlines[i].sidenum[0]].colormap_data; + } + else + { + TAG_ITER_SECTORS(wlines[i].args[0], s) + { + if (wsectors[s].colormap_protected) + continue; + + wsectors[s].extra_colormap = wsides[wlines[i].sidenum[0]].colormap_data; + if (freetag == (mtag_t)MAXTAGS) + { + CONS_Alert(CONS_WARNING, M_GetText("No unused tag found. Linedef %s with type 606 cannot be converted.\n"), sizeu1(i)); + break; + } + Tag_Add(&wsectors[s].tags, freetag); + wlines[i].args[1] = freetag; + freetag = Tag_NextUnused(freetag); + break; + } + } + break; + default: + break; + } + + if (wlines[i].special >= 300 && wlines[i].special < 400 && wlines[i].flags & ML_WRAPMIDTEX) + CONS_Alert(CONS_WARNING, M_GetText("Linedef executor trigger linedef %s has disregard order flag, which is not supported in UDMF.\n"), sizeu1(i)); + } + + for (i = 0; i < numsectors; i++) + { + if (Tag_Find(&wsectors[i].tags, LE_CAPSULE0)) + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has reserved tag %d, which is not supported in UDMF. Use arg3 of the boss mapthing instead.\n"), sizeu1(i), LE_CAPSULE0); + if (Tag_Find(&wsectors[i].tags, LE_CAPSULE1)) + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has reserved tag %d, which is not supported in UDMF. Use arg3 of the boss mapthing instead.\n"), sizeu1(i), LE_CAPSULE1); + if (Tag_Find(&wsectors[i].tags, LE_CAPSULE2)) + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has reserved tag %d, which is not supported in UDMF. Use arg3 of the boss mapthing instead.\n"), sizeu1(i), LE_CAPSULE2); + + switch (GETSECSPECIAL(wsectors[i].special, 1)) + { + case 9: + case 10: + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has ring drainer effect, which is not supported in UDMF. Use linedef type 462 instead.\n"), sizeu1(i)); + break; + default: + break; + } + + switch (GETSECSPECIAL(wsectors[i].special, 2)) + { + case 6: + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has emerald check trigger type, which is not supported in UDMF. Use linedef types 337-339 instead.\n"), sizeu1(i)); + break; + case 7: + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has NiGHTS mare trigger type, which is not supported in UDMF. Use linedef types 340-342 instead.\n"), sizeu1(i)); + break; + case 9: + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has Egg Capsule type, which is not supported in UDMF. Use linedef type 464 instead.\n"), sizeu1(i)); + break; + default: + break; + } + } + + fprintf(f, "namespace = \"srb2\";\n"); + for (i = 0; i < nummapthings; i++) + { + fprintf(f, "thing // %s\n", sizeu1(i)); + fprintf(f, "{\n"); + firsttag = Tag_FGet(&wmapthings[i].tags); + if (firsttag != 0) + fprintf(f, "id = %d;\n", firsttag); + if (wmapthings[i].tags.count > 1) + { + fprintf(f, "moreids = \""); + for (j = 1; j < wmapthings[i].tags.count; j++) + { + if (j > 1) + fprintf(f, " "); + fprintf(f, "%d", wmapthings[i].tags.tags[j]); + } + fprintf(f, "\";\n"); + } + fprintf(f, "x = %d;\n", wmapthings[i].x); + fprintf(f, "y = %d;\n", wmapthings[i].y); + if (wmapthings[i].z != 0) + fprintf(f, "height = %d;\n", wmapthings[i].z); + fprintf(f, "angle = %d;\n", wmapthings[i].angle); + if (wmapthings[i].pitch != 0) + fprintf(f, "pitch = %d;\n", wmapthings[i].pitch); + if (wmapthings[i].roll != 0) + fprintf(f, "roll = %d;\n", wmapthings[i].roll); + if (wmapthings[i].type != 0) + fprintf(f, "type = %d;\n", wmapthings[i].type); + if (wmapthings[i].scale != FRACUNIT) + fprintf(f, "scale = %f;\n", FIXED_TO_FLOAT(wmapthings[i].scale)); + if (wmapthings[i].options & MTF_OBJECTFLIP) + fprintf(f, "flip = true;\n"); + for (j = 0; j < NUMMAPTHINGARGS; j++) + if (wmapthings[i].args[j] != 0) + fprintf(f, "arg%s = %d;\n", sizeu1(j), wmapthings[i].args[j]); + for (j = 0; j < NUMMAPTHINGSTRINGARGS; j++) + if (mapthings[i].stringargs[j]) + fprintf(f, "stringarg%s = \"%s\";\n", sizeu1(j), mapthings[i].stringargs[j]); + fprintf(f, "}\n"); + fprintf(f, "\n"); + } + + for (i = 0; i < numvertexes; i++) + { + fprintf(f, "vertex // %s\n", sizeu1(i)); + fprintf(f, "{\n"); + fprintf(f, "x = %f;\n", FIXED_TO_FLOAT(wvertexes[i].x)); + fprintf(f, "y = %f;\n", FIXED_TO_FLOAT(wvertexes[i].y)); + if (wvertexes[i].floorzset) + fprintf(f, "zfloor = %f;\n", FIXED_TO_FLOAT(wvertexes[i].floorz)); + if (wvertexes[i].ceilingzset) + fprintf(f, "zceiling = %f;\n", FIXED_TO_FLOAT(wvertexes[i].ceilingz)); + fprintf(f, "}\n"); + fprintf(f, "\n"); + } + + for (i = 0; i < numlines; i++) + { + fprintf(f, "linedef // %s\n", sizeu1(i)); + fprintf(f, "{\n"); + fprintf(f, "v1 = %s;\n", sizeu1(wlines[i].v1 - vertexes)); + fprintf(f, "v2 = %s;\n", sizeu1(wlines[i].v2 - vertexes)); + fprintf(f, "sidefront = %d;\n", wlines[i].sidenum[0]); + if (wlines[i].sidenum[1] != 0xffff) + fprintf(f, "sideback = %d;\n", wlines[i].sidenum[1]); + firsttag = Tag_FGet(&wlines[i].tags); + if (firsttag != 0) + fprintf(f, "id = %d;\n", firsttag); + if (wlines[i].tags.count > 1) + { + fprintf(f, "moreids = \""); + for (j = 1; j < wlines[i].tags.count; j++) + { + if (j > 1) + fprintf(f, " "); + fprintf(f, "%d", wlines[i].tags.tags[j]); + } + fprintf(f, "\";\n"); + } + if (wlines[i].special != 0) + fprintf(f, "special = %d;\n", wlines[i].special); + for (j = 0; j < NUMLINEARGS; j++) + if (wlines[i].args[j] != 0) + fprintf(f, "arg%s = %d;\n", sizeu1(j), wlines[i].args[j]); + for (j = 0; j < NUMLINESTRINGARGS; j++) + if (lines[i].stringargs[j]) + fprintf(f, "stringarg%s = \"%s\";\n", sizeu1(j), lines[i].stringargs[j]); + if (wlines[i].alpha != FRACUNIT) + fprintf(f, "alpha = %f;\n", FIXED_TO_FLOAT(wlines[i].alpha)); + if (wlines[i].blendmode != AST_COPY) + { + switch (wlines[i].blendmode) + { + case AST_ADD: + fprintf(f, "renderstyle = \"add\";\n"); + break; + case AST_SUBTRACT: + fprintf(f, "renderstyle = \"subtract\";\n"); + break; + case AST_REVERSESUBTRACT: + fprintf(f, "renderstyle = \"reversesubtract\";\n"); + break; + case AST_MODULATE: + fprintf(f, "renderstyle = \"modulate\";\n"); + break; + case AST_FOG: + fprintf(f, "renderstyle = \"fog\";\n"); + break; + default: + break; + } + } + if (wlines[i].executordelay != 0 && wlines[i].backsector) + { + CONS_Alert(CONS_WARNING, M_GetText("Linedef %s has an executor delay. Changes to the delay at runtime will not be reflected in the converted map. Use linedef type 465 for this.\n"), sizeu1(i)); + fprintf(f, "executordelay = %d;\n", (wlines[i].backsector->ceilingheight >> FRACBITS) + (wlines[i].backsector->floorheight >> FRACBITS)); + } + if (wlines[i].flags & ML_IMPASSIBLE) + fprintf(f, "blocking = true;\n"); + if (wlines[i].flags & ML_BLOCKMONSTERS) + fprintf(f, "blockmonsters = true;\n"); + if (wlines[i].flags & ML_TWOSIDED) + fprintf(f, "twosided = true;\n"); + if (wlines[i].flags & ML_DONTPEGTOP) + fprintf(f, "dontpegtop = true;\n"); + if (wlines[i].flags & ML_DONTPEGBOTTOM) + fprintf(f, "dontpegbottom = true;\n"); + if (wlines[i].flags & ML_SKEWTD) + fprintf(f, "skewtd = true;\n"); + if (wlines[i].flags & ML_NOCLIMB) + fprintf(f, "noclimb = true;\n"); + if (wlines[i].flags & ML_NOSKEW) + fprintf(f, "noskew = true;\n"); + if (wlines[i].flags & ML_MIDPEG) + fprintf(f, "midpeg = true;\n"); + if (wlines[i].flags & ML_MIDSOLID) + fprintf(f, "midsolid = true;\n"); + if (wlines[i].flags & ML_WRAPMIDTEX) + fprintf(f, "wrapmidtex = true;\n"); + if (wlines[i].flags & ML_NONET) + fprintf(f, "nonet = true;\n"); + if (wlines[i].flags & ML_NETONLY) + fprintf(f, "netonly = true;\n"); + if (wlines[i].flags & ML_BOUNCY) + fprintf(f, "bouncy = true;\n"); + if (wlines[i].flags & ML_TFERLINE) + fprintf(f, "transfer = true;\n"); + fprintf(f, "}\n"); + fprintf(f, "\n"); + } + + for (i = 0; i < numsides; i++) + { + fprintf(f, "sidedef // %s\n", sizeu1(i)); + fprintf(f, "{\n"); + fprintf(f, "sector = %s;\n", sizeu1(wsides[i].sector - sectors)); + if (wsides[i].textureoffset != 0) + fprintf(f, "offsetx = %d;\n", wsides[i].textureoffset >> FRACBITS); + if (wsides[i].rowoffset != 0) + fprintf(f, "offsety = %d;\n", wsides[i].rowoffset >> FRACBITS); + if (wsides[i].toptexture > 0 && wsides[i].toptexture < numtextures) + fprintf(f, "texturetop = \"%.*s\";\n", 8, textures[wsides[i].toptexture]->name); + if (wsides[i].bottomtexture > 0 && wsides[i].bottomtexture < numtextures) + fprintf(f, "texturebottom = \"%.*s\";\n", 8, textures[wsides[i].bottomtexture]->name); + if (wsides[i].midtexture > 0 && wsides[i].midtexture < numtextures) + fprintf(f, "texturemiddle = \"%.*s\";\n", 8, textures[wsides[i].midtexture]->name); + if (wsides[i].repeatcnt != 0) + fprintf(f, "repeatcnt = %d;\n", wsides[i].repeatcnt); + fprintf(f, "}\n"); + fprintf(f, "\n"); + } + + for (i = 0; i < numsectors; i++) + { + fprintf(f, "sector // %s\n", sizeu1(i)); + fprintf(f, "{\n"); + fprintf(f, "heightfloor = %d;\n", wsectors[i].floorheight >> FRACBITS); + fprintf(f, "heightceiling = %d;\n", wsectors[i].ceilingheight >> FRACBITS); + if (wsectors[i].floorpic != -1) + fprintf(f, "texturefloor = \"%s\";\n", levelflats[wsectors[i].floorpic].name); + if (wsectors[i].ceilingpic != -1) + fprintf(f, "textureceiling = \"%s\";\n", levelflats[wsectors[i].ceilingpic].name); + fprintf(f, "lightlevel = %d;\n", wsectors[i].lightlevel); + if (wsectors[i].floorlightlevel != 0) + fprintf(f, "lightfloor = %d;\n", wsectors[i].floorlightlevel); + if (wsectors[i].floorlightabsolute) + fprintf(f, "lightfloorabsolute = true;\n"); + if (wsectors[i].ceilinglightlevel != 0) + fprintf(f, "lightceiling = %d;\n", wsectors[i].ceilinglightlevel); + if (wsectors[i].ceilinglightabsolute) + fprintf(f, "lightceilingabsolute = true;\n"); + firsttag = Tag_FGet(&wsectors[i].tags); + if (firsttag != 0) + fprintf(f, "id = %d;\n", firsttag); + if (wsectors[i].tags.count > 1) + { + fprintf(f, "moreids = \""); + for (j = 1; j < wsectors[i].tags.count; j++) + { + if (j > 1) + fprintf(f, " "); + fprintf(f, "%d", wsectors[i].tags.tags[j]); + } + fprintf(f, "\";\n"); + } + sector_t tempsec = wsectors[i]; + TextmapUnfixFlatOffsets(&tempsec); + if (tempsec.floor_xoffs != 0) + fprintf(f, "xpanningfloor = %f;\n", FIXED_TO_FLOAT(tempsec.floor_xoffs)); + if (tempsec.floor_yoffs != 0) + fprintf(f, "ypanningfloor = %f;\n", FIXED_TO_FLOAT(tempsec.floor_yoffs)); + if (tempsec.ceiling_xoffs != 0) + fprintf(f, "xpanningceiling = %f;\n", FIXED_TO_FLOAT(tempsec.ceiling_xoffs)); + if (tempsec.ceiling_yoffs != 0) + fprintf(f, "ypanningceiling = %f;\n", FIXED_TO_FLOAT(tempsec.ceiling_yoffs)); + if (wsectors[i].floorpic_angle != 0) + fprintf(f, "rotationfloor = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].floorpic_angle))); + if (wsectors[i].ceilingpic_angle != 0) + fprintf(f, "rotationceiling = %f;\n", FIXED_TO_FLOAT(AngleFixed(wsectors[i].ceilingpic_angle))); + if (wsectors[i].extra_colormap) + { + INT32 lightcolor = P_RGBAToColor(wsectors[i].extra_colormap->rgba); + UINT8 lightalpha = R_GetRgbaA(wsectors[i].extra_colormap->rgba); + INT32 fadecolor = P_RGBAToColor(wsectors[i].extra_colormap->fadergba); + UINT8 fadealpha = R_GetRgbaA(wsectors[i].extra_colormap->fadergba); + + if (lightcolor != 0) + fprintf(f, "lightcolor = %d;\n", lightcolor); + if (lightalpha != 25) + fprintf(f, "lightalpha = %d;\n", lightalpha); + if (fadecolor != 0) + fprintf(f, "fadecolor = %d;\n", fadecolor); + if (fadealpha != 25) + fprintf(f, "fadealpha = %d;\n", fadealpha); + if (wsectors[i].extra_colormap->fadestart != 0) + fprintf(f, "fadestart = %d;\n", wsectors[i].extra_colormap->fadestart); + if (wsectors[i].extra_colormap->fadeend != 31) + fprintf(f, "fadeend = %d;\n", wsectors[i].extra_colormap->fadeend); + if (wsectors[i].extra_colormap->flags & CMF_FOG) + fprintf(f, "colormapfog = true;\n"); + if (wsectors[i].extra_colormap->flags & CMF_FADEFULLBRIGHTSPRITES) + fprintf(f, "colormapfadesprites = true;\n"); + } + if (wsectors[i].colormap_protected) + fprintf(f, "colormapprotected = true;\n"); + if (!(wsectors[i].flags & MSF_FLIPSPECIAL_FLOOR)) + fprintf(f, "flipspecial_nofloor = true;\n"); + if (wsectors[i].flags & MSF_FLIPSPECIAL_CEILING) + fprintf(f, "flipspecial_ceiling = true;\n"); + if (wsectors[i].flags & MSF_TRIGGERSPECIAL_TOUCH) + fprintf(f, "triggerspecial_touch = true;\n"); + if (wsectors[i].flags & MSF_TRIGGERSPECIAL_HEADBUMP) + fprintf(f, "triggerspecial_headbump = true;\n"); + if (wsectors[i].flags & MSF_TRIGGERLINE_PLANE) + fprintf(f, "triggerline_plane = true;\n"); + if (wsectors[i].flags & MSF_TRIGGERLINE_MOBJ) + fprintf(f, "triggerline_mobj = true;\n"); + if (wsectors[i].flags & MSF_INVERTPRECIP) + fprintf(f, "invertprecip = true;\n"); + if (wsectors[i].flags & MSF_GRAVITYFLIP) + fprintf(f, "gravityflip = true;\n"); + if (wsectors[i].flags & MSF_HEATWAVE) + fprintf(f, "heatwave = true;\n"); + if (wsectors[i].flags & MSF_NOCLIPCAMERA) + fprintf(f, "noclipcamera = true;\n"); + if (wsectors[i].specialflags & SSF_OUTERSPACE) + fprintf(f, "outerspace = true;\n"); + if (wsectors[i].specialflags & SSF_DOUBLESTEPUP) + fprintf(f, "doublestepup = true;\n"); + if (wsectors[i].specialflags & SSF_NOSTEPDOWN) + fprintf(f, "nostepdown = true;\n"); + if (wsectors[i].specialflags & SSF_SPEEDPAD) + fprintf(f, "speedpad = true;\n"); + if (wsectors[i].specialflags & SSF_STARPOSTACTIVATOR) + fprintf(f, "starpostactivator = true;\n"); + if (wsectors[i].specialflags & SSF_EXIT) + fprintf(f, "exit = true;\n"); + if (wsectors[i].specialflags & SSF_SPECIALSTAGEPIT) + fprintf(f, "specialstagepit = true;\n"); + if (wsectors[i].specialflags & SSF_RETURNFLAG) + fprintf(f, "returnflag = true;\n"); + if (wsectors[i].specialflags & SSF_REDTEAMBASE) + fprintf(f, "redteambase = true;\n"); + if (wsectors[i].specialflags & SSF_BLUETEAMBASE) + fprintf(f, "blueteambase = true;\n"); + if (wsectors[i].specialflags & SSF_FAN) + fprintf(f, "fan = true;\n"); + if (wsectors[i].specialflags & SSF_SUPERTRANSFORM) + fprintf(f, "supertransform = true;\n"); + if (wsectors[i].specialflags & SSF_FORCESPIN) + fprintf(f, "forcespin = true;\n"); + if (wsectors[i].specialflags & SSF_ZOOMTUBESTART) + fprintf(f, "zoomtubestart = true;\n"); + if (wsectors[i].specialflags & SSF_ZOOMTUBEEND) + fprintf(f, "zoomtubeend = true;\n"); + if (wsectors[i].specialflags & SSF_FINISHLINE) + fprintf(f, "finishline = true;\n"); + if (wsectors[i].specialflags & SSF_ROPEHANG) + fprintf(f, "ropehang = true;\n"); + if (wsectors[i].friction != ORIG_FRICTION) + fprintf(f, "friction = %f;\n", FIXED_TO_FLOAT(wsectors[i].friction)); + if (wsectors[i].gravity != FRACUNIT) + fprintf(f, "gravity = %f;\n", FIXED_TO_FLOAT(wsectors[i].gravity)); + if (wsectors[i].damagetype != SD_NONE) + { + switch (wsectors[i].damagetype) + { + case SD_GENERIC: + fprintf(f, "damagetype = \"Generic\";\n"); + break; + case SD_WATER: + fprintf(f, "damagetype = \"Water\";\n"); + break; + case SD_FIRE: + fprintf(f, "damagetype = \"Fire\";\n"); + break; + case SD_LAVA: + fprintf(f, "damagetype = \"Lava\";\n"); + break; + case SD_ELECTRIC: + fprintf(f, "damagetype = \"Electric\";\n"); + break; + case SD_SPIKE: + fprintf(f, "damagetype = \"Spike\";\n"); + break; + case SD_DEATHPITTILT: + fprintf(f, "damagetype = \"DeathPitTilt\";\n"); + break; + case SD_DEATHPITNOTILT: + fprintf(f, "damagetype = \"DeathPitNoTilt\";\n"); + break; + case SD_INSTAKILL: + fprintf(f, "damagetype = \"Instakill\";\n"); + break; + case SD_SPECIALSTAGE: + fprintf(f, "damagetype = \"SpecialStage\";\n"); + break; + default: + break; + } + } + if (wsectors[i].triggertag != 0) + fprintf(f, "triggertag = %d;\n", wsectors[i].triggertag); + if (wsectors[i].triggerer != 0) + fprintf(f, "triggerer = %d;\n", wsectors[i].triggerer); + fprintf(f, "}\n"); + fprintf(f, "\n"); + } + + fclose(f); + + for (i = 0; i < nummapthings; i++) + if (wmapthings[i].tags.count) + Z_Free(wmapthings[i].tags.tags); + + for (i = 0; i < numsectors; i++) + if (wsectors[i].tags.count) + Z_Free(wsectors[i].tags.tags); + + for (i = 0; i < numlines; i++) + if (wlines[i].tags.count) + Z_Free(wlines[i].tags.tags); + + Z_Free(wmapthings); + Z_Free(wvertexes); + Z_Free(wsectors); + Z_Free(wlines); + Z_Free(wsides); + Z_Free(specialthings); +} + /** Loads the textmap data, after obtaining the elements count and allocating their respective space. */ static void P_LoadTextmap(void) @@ -1858,8 +2703,21 @@ static void P_LoadTextmap(void) sc->floorpic_angle = sc->ceilingpic_angle = 0; + sc->floorlightlevel = sc->ceilinglightlevel = 0; + sc->floorlightabsolute = sc->ceilinglightabsolute = false; + sc->colormap_protected = false; + sc->gravity = FRACUNIT; + + sc->flags = MSF_FLIPSPECIAL_FLOOR; + sc->specialflags = 0; + sc->damagetype = SD_NONE; + sc->triggertag = 0; + sc->triggerer = TO_PLAYER; + + sc->friction = ORIG_FRICTION; + textmap_colormap.used = false; textmap_colormap.lightcolor = 0; textmap_colormap.lightalpha = 25; @@ -1868,6 +2726,10 @@ static void P_LoadTextmap(void) textmap_colormap.fadestart = 0; textmap_colormap.fadeend = 31; textmap_colormap.flags = 0; + + textmap_planefloor.defined = 0; + textmap_planeceiling.defined = 0; + TextmapParse(sectorsPos[i], i, ParseTextmapSectorParameter); P_InitializeSector(sc); @@ -1877,6 +2739,19 @@ static void P_LoadTextmap(void) INT32 fadergba = P_ColorToRGBA(textmap_colormap.fadecolor, textmap_colormap.fadealpha); sc->extra_colormap = sc->spawn_extra_colormap = R_CreateColormap(rgba, fadergba, textmap_colormap.fadestart, textmap_colormap.fadeend, textmap_colormap.flags); } + + if (textmap_planefloor.defined == (PD_A|PD_B|PD_C|PD_D)) + { + sc->f_slope = MakeViaEquationConstants(textmap_planefloor.a, textmap_planefloor.b, textmap_planefloor.c, textmap_planefloor.d); + sc->hasslope = true; + } + + if (textmap_planeceiling.defined == (PD_A|PD_B|PD_C|PD_D)) + { + sc->c_slope = MakeViaEquationConstants(textmap_planeceiling.a, textmap_planeceiling.b, textmap_planeceiling.c, textmap_planeceiling.d); + sc->hasslope = true; + } + TextmapFixFlatOffsets(sc); } @@ -1954,6 +2829,9 @@ static void P_ProcessLinedefsAfterSidedefs(void) ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be -1 here ld->backsector = ld->sidenum[1] != 0xffff ? sides[ld->sidenum[1]].sector : 0; + if (udmf) + continue; + switch (ld->special) { // Compile linedef 'text' from both sidedefs 'text' for appropriate specials. @@ -1974,8 +2852,6 @@ static void P_ProcessLinedefsAfterSidedefs(void) break; case 447: // Change colormap case 455: // Fade colormap - if (udmf) - break; if (ld->flags & ML_DONTPEGBOTTOM) // alternate alpha (by texture offsets) { extracolormap_t *exc = R_CopyColormap(sides[ld->sidenum[0]].colormap_data, false); @@ -2019,8 +2895,12 @@ static boolean P_LoadMapData(const virtres_t *virt) if (udmf) // Count how many entries for each type we got in textmap. { virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); - if (!TextmapCount(textmap->data, textmap->size)) + M_TokenizerOpen((char *)textmap->data); + if (!TextmapCount(textmap->size)) + { + M_TokenizerClose(); return false; + } } else { @@ -2074,7 +2954,10 @@ static boolean P_LoadMapData(const virtres_t *virt) // Load map data. if (udmf) + { P_LoadTextmap(); + M_TokenizerClose(); + } else { P_LoadVertices(virtvertexes->data); @@ -2380,11 +3263,17 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype linenum = (nodetype == NT_XGL3) ? READUINT32((*data)) : READUINT16((*data)); if (linenum != 0xFFFF && linenum >= numlines) - I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid linedef %d!\n", sizeu1(k), m, linenum); + I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %s has invalid linedef %d!\n", sizeu1(k), sizeu2(i), linenum); segs[k].glseg = (linenum == 0xFFFF); segs[k].linedef = (linenum == 0xFFFF) ? NULL : &lines[linenum]; segs[k].side = READUINT8((*data)); } + while (segs[subsectors[i].firstline].glseg) + { + subsectors[i].firstline++; + if (subsectors[i].firstline == k) + I_Error("P_LoadExtendedSubsectorsAndSegs: Subsector %s does not have any valid segs!", sizeu1(i)); + } break; case NT_XNOD: @@ -2421,7 +3310,10 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype P_InitializeSeg(seg); seg->angle = R_PointToAngle2(v1->x, v1->y, v2->x, v2->y); if (seg->linedef) - segs[i].offset = FixedHypot(v1->x - seg->linedef->v1->x, v1->y - seg->linedef->v1->y); + { + vertex_t *v = (seg->side == 1) ? seg->linedef->v2 : seg->linedef->v1; + segs[i].offset = FixedHypot(v1->x - v->x, v1->y - v->y); + } seg->length = P_SegLength(seg); #ifdef HWRENDER seg->flength = (rendermode == render_opengl) ? P_SegLengthFloat(seg) : 0; @@ -2486,7 +3378,7 @@ static void P_LoadMapBSP(const virtres_t *virt) if (numsubsectors <= 0) I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)"); if (numnodes <= 0) - I_Error("Level has no nodes"); + I_Error("Level has no nodes (does your map have at least 2 sectors?)"); if (numsegs <= 0) I_Error("Level has no segs"); @@ -2950,8 +3842,154 @@ static void P_LinkMapData(void) } } -//For maps in binary format, converts setup of specials to UDMF format. -static void P_ConvertBinaryMap(void) +// For maps in binary format, add multi-tags from linedef specials. This must be done +// before any linedef specials have been processed. +static void P_AddBinaryMapTagsFromLine(sector_t *sector, line_t *line) +{ + Tag_Add(§or->tags, Tag_FGet(&line->tags)); + if (line->flags & ML_EFFECT6) { + if (sides[line->sidenum[0]].textureoffset) + Tag_Add(§or->tags, (INT32)sides[line->sidenum[0]].textureoffset / FRACUNIT); + if (sides[line->sidenum[0]].rowoffset) + Tag_Add(§or->tags, (INT32)sides[line->sidenum[0]].rowoffset / FRACUNIT); + } + if (line->flags & ML_TFERLINE) { + if (sides[line->sidenum[1]].textureoffset) + Tag_Add(§or->tags, (INT32)sides[line->sidenum[1]].textureoffset / FRACUNIT); + if (sides[line->sidenum[1]].rowoffset) + Tag_Add(§or->tags, (INT32)sides[line->sidenum[1]].rowoffset / FRACUNIT); + } +} + +static void P_AddBinaryMapTags(void) +{ + size_t i; + + for (i = 0; i < numlines; i++) { + // 97: Apply Tag to Front Sector + // 98: Apply Tag to Back Sector + // 99: Apply Tag to Front and Back Sectors + if (lines[i].special == 97 || lines[i].special == 99) + P_AddBinaryMapTagsFromLine(lines[i].frontsector, &lines[i]); + if (lines[i].special == 98 || lines[i].special == 99) + P_AddBinaryMapTagsFromLine(lines[i].backsector, &lines[i]); + } + + // Run this loop after the 97-99 loop to ensure that 96 can search through all of the + // 97-99-applied tags. + for (i = 0; i < numlines; i++) { + size_t j; + mtag_t tag, target_tag; + mtag_t offset_tags[4]; + + // 96: Apply Tag to Tagged Sectors + if (lines[i].special != 96) + continue; + + tag = Tag_FGet(&lines[i].frontsector->tags); + target_tag = Tag_FGet(&lines[i].tags); + memset(offset_tags, 0, sizeof(mtag_t)*4); + if (lines[i].flags & ML_EFFECT6) { + offset_tags[0] = (INT32)sides[lines[i].sidenum[0]].textureoffset / FRACUNIT; + offset_tags[1] = (INT32)sides[lines[i].sidenum[0]].rowoffset / FRACUNIT; + } + if (lines[i].flags & ML_TFERLINE) { + offset_tags[2] = (INT32)sides[lines[i].sidenum[1]].textureoffset / FRACUNIT; + offset_tags[3] = (INT32)sides[lines[i].sidenum[1]].rowoffset / FRACUNIT; + } + + for (j = 0; j < numsectors; j++) { + boolean matches_target_tag = target_tag && Tag_Find(§ors[j].tags, target_tag); + size_t k; + for (k = 0; k < 4; k++) { + if (lines[i].flags & ML_WRAPMIDTEX) { + if (matches_target_tag || (offset_tags[k] && Tag_Find(§ors[j].tags, offset_tags[k]))) { + Tag_Add(§ors[j].tags, tag); + break; + } + } else if (matches_target_tag) { + if (k == 0) + Tag_Add(§ors[j].tags, tag); + if (offset_tags[k]) + Tag_Add(§ors[j].tags, offset_tags[k]); + } + } + } + } + + for (i = 0; i < nummapthings; i++) + { + switch (mapthings[i].type) + { + case 291: + case 322: + case 750: + case 760: + case 761: + case 762: + Tag_FSet(&mapthings[i].tags, mapthings[i].angle); + break; + case 290: + case 292: + case 294: + case 780: + Tag_FSet(&mapthings[i].tags, mapthings[i].extrainfo); + break; + default: + break; + } + } +} + +static void P_WriteConstant(INT32 constant, char **target) +{ + char buffer[12]; + sprintf(buffer, "%d", constant); + *target = Z_Malloc(strlen(buffer) + 1, PU_LEVEL, NULL); + M_Memcpy(*target, buffer, strlen(buffer) + 1); +} + +static line_t *P_FindPointPushLine(taglist_t *list) +{ + INT32 i, l; + + for (i = 0; i < list->count; i++) + { + mtag_t tag = list->tags[i]; + TAG_ITER_LINES(tag, l) + { + if (Tag_FGet(&lines[l].tags) != tag) + continue; + + if (lines[l].special != 547) + continue; + + return &lines[l]; + } + } + + return NULL; +} + +static void P_SetBinaryFOFAlpha(line_t *line) +{ + if (sides[line->sidenum[0]].toptexture > 0) + { + line->args[1] = sides[line->sidenum[0]].toptexture; + if (sides[line->sidenum[0]].toptexture >= 1001) + { + line->args[2] = (sides[line->sidenum[0]].toptexture/1000); + line->args[1] %= 1000; + } + } + else + { + line->args[1] = 128; + line->args[2] = TMB_TRANSLUCENT; + } +} + +static void P_ConvertBinaryLinedefTypes(void) { size_t i; @@ -2961,14 +3999,120 @@ static void P_ConvertBinaryMap(void) switch (lines[i].special) { + case 2: //Custom exit + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[1] |= TMEF_SKIPTALLY; + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[1] |= TMEF_EMERALDCHECK; + break; + case 3: //Zoom tube parameters + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = !!(lines[i].flags & ML_MIDSOLID); + break; + case 4: //Speed pad parameters + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[1] |= TMSP_NOTELEPORT; + if (lines[i].flags & ML_WRAPMIDTEX) + lines[i].args[1] |= TMSP_FORCESPIN; + P_WriteConstant(sides[lines[i].sidenum[0]].toptexture ? sides[lines[i].sidenum[0]].toptexture : sfx_spdpad, &lines[i].stringargs[0]); + break; + case 7: //Sector flat alignment + lines[i].args[0] = tag; + if ((lines[i].flags & (ML_NETONLY|ML_NONET)) == (ML_NETONLY|ML_NONET)) + { + CONS_Alert(CONS_WARNING, M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), tag); + lines[i].special = 0; + } + else if (lines[i].flags & ML_NETONLY) + lines[i].args[1] = TMP_CEILING; + else if (lines[i].flags & ML_NONET) + lines[i].args[1] = TMP_FLOOR; + else + lines[i].args[1] = TMP_BOTH; + lines[i].flags &= ~(ML_NETONLY|ML_NONET); + + if (lines[i].flags & ML_EFFECT6) // Set offset through x and y texture offsets + { + angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)); + fixed_t xoffs = sides[lines[i].sidenum[0]].textureoffset; + fixed_t yoffs = sides[lines[i].sidenum[0]].rowoffset; + + //If no tag is given, apply to front sector + if (lines[i].args[0] == 0) + P_ApplyFlatAlignment(lines[i].frontsector, flatangle, xoffs, yoffs, lines[i].args[1] != TMP_CEILING, lines[i].args[1] != TMP_FLOOR); + else + { + INT32 s; + TAG_ITER_SECTORS(lines[i].args[0], s) + P_ApplyFlatAlignment(sectors + s, flatangle, xoffs, yoffs, lines[i].args[1] != TMP_CEILING, lines[i].args[1] != TMP_FLOOR); + } + lines[i].special = 0; + } + break; + case 8: //Special sector properties + { + INT32 s; + + lines[i].args[0] = tag; + TAG_ITER_SECTORS(tag, s) + { + if (lines[i].flags & ML_NOCLIMB) + { + sectors[s].flags &= ~MSF_FLIPSPECIAL_FLOOR; + sectors[s].flags |= MSF_FLIPSPECIAL_CEILING; + } + else if (lines[i].flags & ML_MIDSOLID) + sectors[s].flags |= MSF_FLIPSPECIAL_BOTH; + + if (lines[i].flags & ML_MIDPEG) + sectors[s].flags |= MSF_TRIGGERSPECIAL_TOUCH; + if (lines[i].flags & ML_NOSKEW) + sectors[s].flags |= MSF_TRIGGERSPECIAL_HEADBUMP; + + if (lines[i].flags & ML_SKEWTD) + sectors[s].flags |= MSF_INVERTPRECIP; + } + + if (GETSECSPECIAL(lines[i].frontsector->special, 4) != 12) + lines[i].special = 0; + + break; + } + case 10: //Culling plane + lines[i].args[0] = tag; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 11: //Rope hang parameters + lines[i].args[0] = (lines[i].flags & ML_NOCLIMB) ? 0 : sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = !!(lines[i].flags & ML_SKEWTD); + break; + case 13: //Heat wave effect + { + INT32 s; + + TAG_ITER_SECTORS(tag, s) + sectors[s].flags |= MSF_HEATWAVE; + + break; + } + case 14: //Bustable block parameters + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = !!(lines[i].flags & ML_SKEWTD); + P_WriteConstant(sides[lines[i].sidenum[0]].toptexture, &lines[i].stringargs[0]); + break; + case 16: //Minecart parameters + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + break; case 20: //PolyObject first line { INT32 check = -1; INT32 paramline = -1; - TAG_ITER_DECLARECOUNTER(0); - - TAG_ITER_LINES(0, tag, check) + TAG_ITER_LINES(tag, check) { if (lines[check].special == 22) { @@ -2997,15 +4141,15 @@ static void P_ConvertBinaryMap(void) : ((lines[paramline].frontsector->floorheight >> FRACBITS) / 100); //Flags - if (lines[paramline].flags & ML_EFFECT1) + if (lines[paramline].flags & ML_SKEWTD) lines[i].args[3] |= TMPF_NOINSIDES; - if (lines[paramline].flags & ML_EFFECT2) + if (lines[paramline].flags & ML_NOSKEW) lines[i].args[3] |= TMPF_INTANGIBLE; - if (lines[paramline].flags & ML_EFFECT3) + if (lines[paramline].flags & ML_MIDPEG) lines[i].args[3] |= TMPF_PUSHABLESTOP; - if (lines[paramline].flags & ML_EFFECT4) + if (lines[paramline].flags & ML_MIDSOLID) lines[i].args[3] &= ~TMPF_INVISIBLEPLANES; - /*if (lines[paramline].flags & ML_EFFECT5) + /*if (lines[paramline].flags & ML_WRAPMIDTEX) lines[i].args[3] |= TMPF_DONTCLIPPLANES;*/ if (lines[paramline].flags & ML_EFFECT6) lines[i].args[3] |= TMPF_SPLAT; @@ -3014,6 +4158,1069 @@ static void P_ConvertBinaryMap(void) break; } + case 30: //Polyobject - waving flag + lines[i].args[0] = tag; + lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + break; + case 31: //Polyobject - displacement by front sector + lines[i].args[0] = tag; + lines[i].args[1] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; + break; + case 32: //Polyobject - angular displacement by front sector + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset ? sides[lines[i].sidenum[0]].textureoffset >> FRACBITS : 128; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset ? sides[lines[i].sidenum[0]].rowoffset >> FRACBITS : 90; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] |= TMPR_DONTROTATEOTHERS; + else if (lines[i].flags & ML_MIDSOLID) + lines[i].args[3] |= TMPR_ROTATEPLAYERS; + break; + case 50: //Instantly lower floor on level load + case 51: //Instantly raise ceiling on level load + lines[i].args[0] = tag; + break; + case 52: //Continuously falling sector + lines[i].args[0] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 53: //Continuous floor/ceiling mover + case 54: //Continuous floor mover + case 55: //Continuous ceiling mover + lines[i].args[0] = tag; + lines[i].args[1] = (lines[i].special == 53) ? TMP_BOTH : lines[i].special - 54; + lines[i].args[2] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[3] = lines[i].args[2]; + lines[i].args[4] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[5] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].special = 53; + break; + case 56: //Continuous two-speed floor/ceiling mover + case 57: //Continuous two-speed floor mover + case 58: //Continuous two-speed ceiling mover + lines[i].args[0] = tag; + lines[i].args[1] = (lines[i].special == 56) ? TMP_BOTH : lines[i].special - 57; + lines[i].args[2] = abs(lines[i].dx) >> FRACBITS; + lines[i].args[3] = abs(lines[i].dy) >> FRACBITS; + lines[i].args[4] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[5] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].special = 56; + break; + case 59: //Activate moving platform + case 60: //Activate moving platform (adjustable speed) + lines[i].args[0] = tag; + lines[i].args[1] = (lines[i].special == 60) ? P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS : 8; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[3] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[4] = (lines[i].flags & ML_NOCLIMB) ? 1 : 0; + lines[i].special = 60; + break; + case 61: //Crusher (Ceiling to floor) + case 62: //Crusher (Floor to ceiling) + lines[i].args[0] = tag; + lines[i].args[1] = lines[i].special - 61; + if (lines[i].flags & ML_MIDSOLID) + { + lines[i].args[2] = abs(lines[i].dx) >> FRACBITS; + lines[i].args[3] = lines[i].args[2]; + } + else + { + lines[i].args[2] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> (FRACBITS + 1); + lines[i].args[3] = lines[i].args[2] / 4; + } + lines[i].special = 61; + break; + case 63: //Fake floor/ceiling planes + lines[i].args[0] = tag; + break; + case 64: //Appearing/disappearing FOF + lines[i].args[0] = (lines[i].flags & ML_BLOCKMONSTERS) ? 0 : tag; + lines[i].args[1] = (lines[i].flags & ML_BLOCKMONSTERS) ? tag : Tag_FGet(&lines[i].frontsector->tags); + lines[i].args[2] = lines[i].dx >> FRACBITS; + lines[i].args[3] = lines[i].dy >> FRACBITS; + lines[i].args[4] = lines[i].frontsector->floorheight >> FRACBITS; + lines[i].args[5] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 66: //Move floor by displacement + case 67: //Move ceiling by displacement + case 68: //Move floor and ceiling by displacement + lines[i].args[0] = tag; + lines[i].args[1] = lines[i].special - 66; + lines[i].args[2] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] *= -1; + lines[i].special = 66; + break; + case 76: //Make FOF bouncy + lines[i].args[0] = tag; + lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + break; + case 100: //FOF: solid, opaque, shadowcasting + case 101: //FOF: solid, opaque, non-shadowcasting + case 102: //FOF: solid, translucent + case 103: //FOF: solid, sides only + case 104: //FOF: solid, no sides + case 105: //FOF: solid, invisible + lines[i].args[0] = tag; + + //Alpha + if (lines[i].special == 102) + { + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] |= TMFA_INSIDES; + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[3] |= TMFA_SPLAT; + } + else + lines[i].args[1] = 255; + + //Appearance + if (lines[i].special == 105) + lines[i].args[3] |= TMFA_NOPLANES|TMFA_NOSIDES; + else if (lines[i].special == 104) + lines[i].args[3] |= TMFA_NOSIDES; + else if (lines[i].special == 103) + lines[i].args[3] |= TMFA_NOPLANES; + if (lines[i].special != 100 && (lines[i].special != 104 || !(lines[i].flags & ML_NOCLIMB))) + lines[i].args[3] |= TMFA_NOSHADE; + if (lines[i].flags & ML_EFFECT6) + lines[i].args[3] |= TMFA_SPLAT; + + //Tangibility + if (lines[i].flags & ML_SKEWTD) + lines[i].args[4] |= TMFT_DONTBLOCKOTHERS; + if (lines[i].flags & ML_NOSKEW) + lines[i].args[4] |= TMFT_DONTBLOCKPLAYER; + + lines[i].special = 100; + break; + case 120: //FOF: water, opaque + case 121: //FOF: water, translucent + case 122: //FOF: water, opaque, no sides + case 123: //FOF: water, translucent, no sides + case 124: //FOF: goo water, translucent + case 125: //FOF: goo water, translucent, no sides + lines[i].args[0] = tag; + + //Alpha + if (lines[i].special == 120 || lines[i].special == 122) + lines[i].args[1] = 255; + else + { + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[3] |= TMFW_SPLAT; + } + + //No sides? + if (lines[i].special == 122 || lines[i].special == 123 || lines[i].special == 125) + lines[i].args[3] |= TMFW_NOSIDES; + + //Flags + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] |= TMFW_DOUBLESHADOW; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[3] |= TMFW_COLORMAPONLY; + if (!(lines[i].flags & ML_WRAPMIDTEX)) + lines[i].args[3] |= TMFW_NORIPPLE; + + //Goo? + if (lines[i].special >= 124) + lines[i].args[3] |= TMFW_GOOWATER; + + //Splat rendering? + if (lines[i].flags & ML_EFFECT6) + lines[i].args[3] |= TMFW_SPLAT; + + lines[i].special = 120; + break; + case 140: //FOF: intangible from bottom, opaque + case 141: //FOF: intangible from bottom, translucent + case 142: //FOF: intangible from bottom, translucent, no sides + case 143: //FOF: intangible from top, opaque + case 144: //FOF: intangible from top, translucent + case 145: //FOF: intangible from top, translucent, no sides + case 146: //FOF: only tangible from sides + lines[i].args[0] = tag; + + //Alpha + if (lines[i].special == 141 || lines[i].special == 142 || lines[i].special == 144 || lines[i].special == 145) + { + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] |= TMFA_INSIDES; + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[3] |= TMFA_SPLAT; + } + else + lines[i].args[1] = 255; + + //Appearance + if (lines[i].special == 142 || lines[i].special == 145) + lines[i].args[3] |= TMFA_NOSIDES; + else if (lines[i].special == 146) + lines[i].args[3] |= TMFA_NOPLANES; + if (lines[i].special != 146 && (lines[i].flags & ML_NOCLIMB)) + lines[i].args[3] |= TMFA_NOSHADE; + if (lines[i].flags & ML_EFFECT6) + lines[i].args[3] |= TMFA_SPLAT; + + //Tangibility + if (lines[i].special <= 142) + lines[i].args[4] |= TMFT_INTANGIBLEBOTTOM; + else if (lines[i].special <= 145) + lines[i].args[4] |= TMFT_INTANGIBLETOP; + else + lines[i].args[4] |= TMFT_INTANGIBLEBOTTOM|TMFT_INTANGIBLETOP; + + if (lines[i].flags & ML_SKEWTD) + lines[i].args[4] |= TMFT_DONTBLOCKOTHERS; + if (lines[i].flags & ML_NOSKEW) + lines[i].args[4] |= TMFT_DONTBLOCKPLAYER; + + lines[i].special = 100; + break; + case 150: //FOF: Air bobbing + case 151: //FOF: Air bobbing (adjustable) + case 152: //FOF: Reverse air bobbing (adjustable) + case 153: //FOF: Dynamically sinking platform + lines[i].args[0] = tag; + lines[i].args[1] = (lines[i].special == 150) ? 16 : (P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS); + + //Flags + if (lines[i].special == 152) + lines[i].args[2] |= TMFB_REVERSE; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] |= TMFB_SPINDASH; + if (lines[i].special == 153) + lines[i].args[2] |= TMFB_DYNAMIC; + + lines[i].special = 150; + break; + case 160: //FOF: Water bobbing + lines[i].args[0] = tag; + break; + case 170: //FOF: Crumbling, respawn + case 171: //FOF: Crumbling, no respawn + case 172: //FOF: Crumbling, respawn, intangible from bottom + case 173: //FOF: Crumbling, no respawn, intangible from bottom + case 174: //FOF: Crumbling, respawn, intangible from bottom, translucent + case 175: //FOF: Crumbling, no respawn, intangible from bottom, translucent + case 176: //FOF: Crumbling, respawn, floating, bobbing + case 177: //FOF: Crumbling, no respawn, floating, bobbing + case 178: //FOF: Crumbling, respawn, floating + case 179: //FOF: Crumbling, no respawn, floating + case 180: //FOF: Crumbling, respawn, air bobbing + lines[i].args[0] = tag; + + //Alpha + if (lines[i].special >= 174 && lines[i].special <= 175) + { + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[4] |= TMFC_SPLAT; + } + else + lines[i].args[1] = 255; + + if (lines[i].special >= 172 && lines[i].special <= 175) + { + lines[i].args[3] |= TMFT_INTANGIBLEBOTTOM; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[4] |= TMFC_NOSHADE; + } + + if (lines[i].special % 2 == 1) + lines[i].args[4] |= TMFC_NORETURN; + if (lines[i].special == 176 || lines[i].special == 177 || lines[i].special == 180) + lines[i].args[4] |= TMFC_AIRBOB; + if (lines[i].special >= 176 && lines[i].special <= 179) + lines[i].args[4] |= TMFC_FLOATBOB; + if (lines[i].flags & ML_EFFECT6) + lines[i].args[4] |= TMFC_SPLAT; + + if (lines[i].flags & ML_SKEWTD) + lines[i].args[3] |= TMFT_DONTBLOCKOTHERS; + if (lines[i].flags & ML_NOSKEW) + lines[i].args[3] |= TMFT_DONTBLOCKPLAYER; + + lines[i].special = 170; + break; + case 190: // FOF: Rising, solid, opaque, shadowcasting + case 191: // FOF: Rising, solid, opaque, non-shadowcasting + case 192: // FOF: Rising, solid, translucent + case 193: // FOF: Rising, solid, invisible + case 194: // FOF: Rising, intangible from bottom, opaque + case 195: // FOF: Rising, intangible from bottom, translucent + lines[i].args[0] = tag; + + //Translucency + if (lines[i].special == 192 || lines[i].special == 195) + { + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[3] |= TMFA_SPLAT; + } + else + lines[i].args[1] = 255; + + //Appearance + if (lines[i].special == 193) + lines[i].args[3] |= TMFA_NOPLANES|TMFA_NOSIDES; + if (lines[i].special >= 194) + lines[i].args[3] |= TMFA_INSIDES; + if (lines[i].special != 190 && (lines[i].special <= 193 || lines[i].flags & ML_NOCLIMB)) + lines[i].args[3] |= TMFA_NOSHADE; + if (lines[i].flags & ML_EFFECT6) + lines[i].args[3] |= TMFA_SPLAT; + + //Tangibility + if (lines[i].flags & ML_SKEWTD) + lines[i].args[4] |= TMFT_DONTBLOCKOTHERS; + if (lines[i].flags & ML_NOSKEW) + lines[i].args[4] |= TMFT_DONTBLOCKPLAYER; + if (lines[i].special >= 194) + lines[i].args[4] |= TMFT_INTANGIBLEBOTTOM; + + //Speed + lines[i].args[5] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + + //Flags + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[6] |= TMFR_REVERSE; + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[6] |= TMFR_SPINDASH; + + lines[i].special = 190; + break; + case 200: //FOF: Light block + case 201: //FOF: Half light block + lines[i].args[0] = tag; + if (lines[i].special == 201) + lines[i].args[1] = 1; + lines[i].special = 200; + break; + case 202: //FOF: Fog block + case 223: //FOF: Intangible, invisible + lines[i].args[0] = tag; + break; + case 220: //FOF: Intangible, opaque + case 221: //FOF: Intangible, translucent + case 222: //FOF: Intangible, sides only + lines[i].args[0] = tag; + + //Alpha + if (lines[i].special == 221) + { + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[3] |= TMFA_SPLAT; + } + else + lines[i].args[1] = 255; + + //Appearance + if (lines[i].special == 222) + lines[i].args[3] |= TMFA_NOPLANES; + if (lines[i].special == 221) + lines[i].args[3] |= TMFA_INSIDES; + if (lines[i].special != 220 && !(lines[i].flags & ML_NOCLIMB)) + lines[i].args[3] |= TMFA_NOSHADE; + if (lines[i].flags & ML_EFFECT6) + lines[i].args[3] |= TMFA_SPLAT; + + lines[i].special = 220; + break; + case 250: //FOF: Mario block + lines[i].args[0] = tag; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[1] |= TMFM_BRICK; + if (lines[i].flags & ML_SKEWTD) + lines[i].args[1] |= TMFM_INVISIBLE; + break; + case 251: //FOF: Thwomp block + lines[i].args[0] = tag; + if (lines[i].flags & ML_WRAPMIDTEX) //Custom speeds + { + lines[i].args[1] = lines[i].dy >> FRACBITS; + lines[i].args[2] = lines[i].dx >> FRACBITS; + } + else + { + lines[i].args[1] = 80; + lines[i].args[2] = 16; + } + if (lines[i].flags & ML_MIDSOLID) + P_WriteConstant(sides[lines[i].sidenum[0]].textureoffset >> FRACBITS, &lines[i].stringargs[0]); + break; + case 252: //FOF: Shatter block + case 253: //FOF: Shatter block, translucent + case 254: //FOF: Bustable block + case 255: //FOF: Spin-bustable block + case 256: //FOF: Spin-bustable block, translucent + lines[i].args[0] = tag; + + //Alpha + if (lines[i].special == 253 || lines[i].special == 256) + { + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[4] |= TMFB_SPLAT; + } + else + lines[i].args[1] = 255; + + //Bustable type + if (lines[i].special <= 253) + lines[i].args[3] = TMFB_TOUCH; + else if (lines[i].special >= 255) + lines[i].args[3] = TMFB_SPIN; + else if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] = TMFB_STRONG; + else + lines[i].args[3] = TMFB_REGULAR; + + //Flags + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[4] |= TMFB_PUSHABLES; + if (lines[i].flags & ML_WRAPMIDTEX) + { + lines[i].args[4] |= TMFB_EXECUTOR; + lines[i].args[5] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + } + if (lines[i].special == 252 && lines[i].flags & ML_NOCLIMB) + lines[i].args[4] |= TMFB_ONLYBOTTOM; + if (lines[i].flags & ML_EFFECT6) + lines[i].args[4] |= TMFB_SPLAT; + + lines[i].special = 254; + break; + case 257: //FOF: Quicksand + lines[i].args[0] = tag; + if (!(lines[i].flags & ML_WRAPMIDTEX)) + lines[i].args[1] = 1; //No ripple effect + lines[i].args[2] = lines[i].dx >> FRACBITS; //Sinking speed + lines[i].args[3] = lines[i].dy >> FRACBITS; //Friction + break; + case 258: //FOF: Laser + lines[i].args[0] = tag; + + //Alpha + P_SetBinaryFOFAlpha(&lines[i]); + + //Flags + if (lines[i].flags & ML_SKEWTD) + lines[i].args[3] |= TMFL_NOBOSSES; + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].flags & ML_EFFECT6 || lines[i].args[1] == 256) + lines[i].args[3] |= TMFL_SPLAT; + + break; + case 259: //Custom FOF + if (lines[i].sidenum[1] == 0xffff) + I_Error("Custom FOF (tag %d) found without a linedef back side!", tag); + + lines[i].args[0] = tag; + lines[i].args[3] = sides[lines[i].sidenum[1]].toptexture; + if (lines[i].flags & ML_EFFECT6) + lines[i].args[3] |= FF_SPLAT; + lines[i].args[4] = sides[lines[i].sidenum[1]].midtexture; + if (lines[i].args[3] & FF_TRANSLUCENT) + { + P_SetBinaryFOFAlpha(&lines[i]); + + //Replicate old hack: Translucent FOFs set to full opacity cut cyan pixels + if (lines[i].args[1] == 256) + lines[i].args[3] |= FF_SPLAT; + } + else + lines[i].args[1] = 255; + break; + case 300: //Trigger linedef executor - Continuous + case 301: //Trigger linedef executor - Each time + case 302: //Trigger linedef executor - Once + if (lines[i].special == 302) + lines[i].args[0] = TMT_ONCE; + else if (lines[i].special == 301) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; + else + lines[i].args[0] = TMT_CONTINUOUS; + lines[i].special = 300; + break; + case 303: //Ring count - Continuous + case 304: //Ring count - Once + lines[i].args[0] = (lines[i].special == 304) ? TMT_ONCE : TMT_CONTINUOUS; + lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] = TMC_LTE; + else if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[2] = TMC_GTE; + else + lines[i].args[2] = TMC_EQUAL; + lines[i].args[3] = !!(lines[i].flags & ML_MIDSOLID); + lines[i].special = 303; + break; + case 305: //Character ability - Continuous + case 306: //Character ability - Each time + case 307: //Character ability - Once + if (lines[i].special == 307) + lines[i].args[0] = TMT_ONCE; + else if (lines[i].special == 306) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; + else + lines[i].args[0] = TMT_CONTINUOUS; + lines[i].args[1] = (P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS) / 10; + lines[i].special = 305; + break; + case 308: //Race only - once + lines[i].args[0] = TMT_ONCE; + lines[i].args[1] = GTR_RACE; + lines[i].args[2] = TMF_HASANY; + break; + case 309: //CTF red team - continuous + case 310: //CTF red team - each time + case 311: //CTF blue team - continuous + case 312: //CTF blue team - each time + if (lines[i].special % 2 == 0) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; + else + lines[i].args[0] = TMT_CONTINUOUS; + lines[i].args[1] = (lines[i].special > 310) ? TMT_BLUE : TMT_RED; + lines[i].special = 309; + break; + case 313: //No more enemies - once + lines[i].args[0] = tag; + break; + case 314: //Number of pushables - Continuous + case 315: //Number of pushables - Once + lines[i].args[0] = (lines[i].special == 315) ? TMT_ONCE : TMT_CONTINUOUS; + lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] = TMC_GTE; + else if (lines[i].flags & ML_MIDSOLID) + lines[i].args[2] = TMC_LTE; + else + lines[i].args[2] = TMC_EQUAL; + lines[i].special = 314; + break; + case 317: //Condition set trigger - Continuous + case 318: //Condition set trigger - Once + lines[i].args[0] = (lines[i].special == 318) ? TMT_ONCE : TMT_CONTINUOUS; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].special = 317; + break; + case 319: //Unlockable trigger - Continuous + case 320: //Unlockable trigger - Once + lines[i].args[0] = (lines[i].special == 320) ? TMT_ONCE : TMT_CONTINUOUS; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].special = 319; + break; + case 321: //Trigger after X calls - Continuous + case 322: //Trigger after X calls - Each time + if (lines[i].special % 2 == 0) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMXT_EACHTIMEENTERANDEXIT : TMXT_EACHTIMEENTER; + else + lines[i].args[0] = TMXT_CONTINUOUS; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + { + lines[i].args[2] = 1; + lines[i].args[3] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + } + else + lines[i].args[2] = lines[i].args[3] = 0; + lines[i].special = 321; + break; + case 323: //NiGHTSerize - Each time + case 324: //NiGHTSerize - Once + case 325: //DeNiGHTSerize - Each time + case 326: //DeNiGHTSerize - Once + case 327: //NiGHTS lap - Each time + case 328: //NiGHTS lap - Once + case 329: //Ideya capture touch - Each time + case 330: //Ideya capture touch - Once + lines[i].args[0] = (lines[i].special + 1) % 2; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] = TMC_LTE; + else if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[3] = TMC_GTE; + else + lines[i].args[3] = TMC_EQUAL; + if (lines[i].flags & ML_SKEWTD) + lines[i].args[4] = TMC_LTE; + else if (lines[i].flags & ML_NOSKEW) + lines[i].args[4] = TMC_GTE; + else + lines[i].args[4] = TMC_EQUAL; + if (lines[i].flags & ML_DONTPEGBOTTOM) + lines[i].args[5] = TMNP_SLOWEST; + else if (lines[i].flags & ML_MIDSOLID) + lines[i].args[5] = TMNP_TRIGGERER; + else + lines[i].args[5] = TMNP_FASTEST; + if (lines[i].special % 2 == 0) + lines[i].special--; + if (lines[i].special == 323) + { + if (lines[i].flags & ML_TFERLINE) + lines[i].args[6] = TMN_FROMNONIGHTS; + else if (lines[i].flags & ML_DONTPEGTOP) + lines[i].args[6] = TMN_FROMNIGHTS; + else + lines[i].args[6] = TMN_ALWAYS; + + if (lines[i].flags & ML_MIDPEG) + lines[i].args[7] |= TMN_BONUSLAPS; + if (lines[i].flags & ML_BOUNCY) + lines[i].args[7] |= TMN_LEVELCOMPLETION; + } + else if (lines[i].special == 325) + { + if (lines[i].flags & ML_TFERLINE) + lines[i].args[6] = TMD_NOBODYNIGHTS; + else if (lines[i].flags & ML_DONTPEGTOP) + lines[i].args[6] = TMD_SOMEBODYNIGHTS; + else + lines[i].args[6] = TMD_ALWAYS; + + lines[i].args[7] = !!(lines[i].flags & ML_MIDPEG); + } + else if (lines[i].special == 327) + lines[i].args[6] = !!(lines[i].flags & ML_MIDPEG); + else + { + if (lines[i].flags & ML_DONTPEGTOP) + lines[i].args[6] = TMS_ALWAYS; + else if (lines[i].flags & ML_BOUNCY) + lines[i].args[6] = TMS_IFNOTENOUGH; + else + lines[i].args[6] = TMS_IFENOUGH; + + if (lines[i].flags & ML_MIDPEG) + lines[i].args[7] |= TMI_BONUSLAPS; + if (lines[i].flags & ML_TFERLINE) + lines[i].args[7] |= TMI_ENTER; + } + break; + case 331: // Player skin - continuous + case 332: // Player skin - each time + case 333: // Player skin - once + if (lines[i].special == 303) + lines[i].args[0] = TMT_ONCE; + else if (lines[i].special == 302) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; + else + lines[i].args[0] = TMT_CONTINUOUS; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + if (lines[i].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(lines[i].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], lines[i].text, strlen(lines[i].text) + 1); + } + lines[i].special = 331; + break; + case 334: // Object dye - continuous + case 335: // Object dye - each time + case 336: // Object dye - once + if (lines[i].special == 336) + lines[i].args[0] = TMT_ONCE; + else if (lines[i].special == 335) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; + else + lines[i].args[0] = TMT_CONTINUOUS; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + lines[i].special = 334; + break; + case 337: //Emerald check - continuous + case 338: //Emerald check - each time + case 339: //Emerald check - once + if (lines[i].special == 339) + lines[i].args[0] = TMT_ONCE; + else if (lines[i].special == 338) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; + else + lines[i].args[0] = TMT_CONTINUOUS; + lines[i].args[1] = EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7; + lines[i].args[2] = TMF_HASALL; + lines[i].special = 337; + break; + case 340: //NiGHTS mare - continuous + case 341: //NiGHTS mare - each time + case 342: //NiGHTS mare - once + if (lines[i].special == 342) + lines[i].args[0] = TMT_ONCE; + else if (lines[i].special == 341) + lines[i].args[0] = (lines[i].flags & ML_BOUNCY) ? TMT_EACHTIMEENTERANDEXIT : TMT_EACHTIMEENTER; + else + lines[i].args[0] = TMT_CONTINUOUS; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] = TMC_LTE; + else if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[2] = TMC_GTE; + else + lines[i].args[2] = TMC_EQUAL; + lines[i].special = 340; + break; + case 400: //Set tagged sector's floor height/texture + case 401: //Set tagged sector's ceiling height/texture + lines[i].args[0] = tag; + lines[i].args[1] = lines[i].special - 400; + lines[i].args[2] = !(lines[i].flags & ML_NOCLIMB); + lines[i].special = 400; + break; + case 402: //Copy light level + lines[i].args[0] = tag; + lines[i].args[1] = 0; + break; + case 403: //Move tagged sector's floor + case 404: //Move tagged sector's ceiling + lines[i].args[0] = tag; + lines[i].args[1] = lines[i].special - 403; + lines[i].args[2] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[3] = (lines[i].flags & ML_BLOCKMONSTERS) ? sides[lines[i].sidenum[0]].textureoffset >> FRACBITS : 0; + lines[i].args[4] = !!(lines[i].flags & ML_NOCLIMB); + lines[i].special = 403; + break; + case 405: //Move floor according to front texture offsets + case 407: //Move ceiling according to front texture offsets + lines[i].args[0] = tag; + lines[i].args[1] = (lines[i].special == 405) ? TMP_FLOOR : TMP_CEILING; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[3] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[4] = !!(lines[i].flags & ML_NOCLIMB); + lines[i].special = 405; + break; + case 408: //Set flats + lines[i].args[0] = tag; + if ((lines[i].flags & (ML_NOCLIMB|ML_MIDSOLID)) == (ML_NOCLIMB|ML_MIDSOLID)) + { + CONS_Alert(CONS_WARNING, M_GetText("Set flats linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), tag); + lines[i].special = 0; + } + else if (lines[i].flags & ML_NOCLIMB) + lines[i].args[1] = TMP_CEILING; + else if (lines[i].flags & ML_MIDSOLID) + lines[i].args[1] = TMP_FLOOR; + else + lines[i].args[1] = TMP_BOTH; + break; + case 409: //Change tagged sector's tag + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] = TMT_ADD; + else if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[2] = TMT_REMOVE; + else + lines[i].args[2] = TMT_REPLACEFIRST; + break; + case 410: //Change front sector's tag + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[1] = TMT_ADD; + else if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[1] = TMT_REMOVE; + else + lines[i].args[1] = TMT_REPLACEFIRST; + break; + case 411: //Stop plane movement + lines[i].args[0] = tag; + break; + case 412: //Teleporter + lines[i].args[0] = tag; + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[1] |= TMT_SILENT; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[1] |= TMT_KEEPANGLE; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[1] |= TMT_KEEPMOMENTUM; + if (lines[i].flags & ML_MIDPEG) + lines[i].args[1] |= TMT_RELATIVE; + lines[i].args[2] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[3] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[4] = lines[i].frontsector->ceilingheight >> FRACBITS; + break; + case 413: //Change music + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[0] |= TMM_ALLPLAYERS; + if (lines[i].flags & ML_SKEWTD) + lines[i].args[0] |= TMM_OFFSET; + if (lines[i].flags & ML_NOSKEW) + lines[i].args[0] |= TMM_FADE; + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[0] |= TMM_NORELOAD; + if (lines[i].flags & ML_BOUNCY) + lines[i].args[0] |= TMM_FORCERESET; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[0] |= TMM_NOLOOP; + lines[i].args[1] = sides[lines[i].sidenum[0]].midtexture; + lines[i].args[2] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[3] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[4] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : 0; + lines[i].args[5] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].rowoffset >> FRACBITS : -1; + lines[i].args[6] = sides[lines[i].sidenum[0]].bottomtexture; + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + break; + case 414: //Play sound effect + lines[i].args[2] = tag; + if (tag != 0) + { + if (lines[i].flags & ML_WRAPMIDTEX) + { + lines[i].args[0] = TMSS_TAGGEDSECTOR; + lines[i].args[1] = TMSL_EVERYONE; + } + else + { + lines[i].args[0] = TMSS_NOWHERE; + lines[i].args[1] = TMSL_TAGGEDSECTOR; + } + } + else + { + if (lines[i].flags & ML_NOCLIMB) + { + lines[i].args[0] = TMSS_NOWHERE; + lines[i].args[1] = TMSL_TRIGGERER; + } + else if (lines[i].flags & ML_MIDSOLID) + { + lines[i].args[0] = TMSS_NOWHERE; + lines[i].args[1] = TMSL_EVERYONE; + } + else if (lines[i].flags & ML_BLOCKMONSTERS) + { + lines[i].args[0] = TMSS_TRIGGERSECTOR; + lines[i].args[1] = TMSL_EVERYONE; + } + else + { + lines[i].args[0] = TMSS_TRIGGERMOBJ; + lines[i].args[1] = TMSL_EVERYONE; + } + } + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + break; + case 415: //Run script + { + INT32 scrnum; + + lines[i].stringargs[0] = Z_Malloc(9, PU_LEVEL, NULL); + strcpy(lines[i].stringargs[0], G_BuildMapName(gamemap)); + lines[i].stringargs[0][0] = 'S'; + lines[i].stringargs[0][1] = 'C'; + lines[i].stringargs[0][2] = 'R'; + + scrnum = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + if (scrnum < 0 || scrnum > 999) + { + scrnum = 0; + lines[i].stringargs[0][5] = lines[i].stringargs[0][6] = lines[i].stringargs[0][7] = '0'; + } + else + { + lines[i].stringargs[0][5] = (char)('0' + (char)((scrnum / 100))); + lines[i].stringargs[0][6] = (char)('0' + (char)((scrnum % 100) / 10)); + lines[i].stringargs[0][7] = (char)('0' + (char)(scrnum % 10)); + } + lines[i].stringargs[0][8] = '\0'; + break; + } + case 416: //Start adjustable flickering light + case 417: //Start adjustable pulsating light + case 602: //Adjustable pulsating light + case 603: //Adjustable flickering light + lines[i].args[0] = tag; + lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[2] = lines[i].frontsector->lightlevel; + if ((lines[i].flags & ML_NOCLIMB) && lines[i].backsector) + lines[i].args[4] = lines[i].backsector->lightlevel; + else + lines[i].args[3] = 1; + break; + case 418: //Start adjustable blinking light (unsynchronized) + case 419: //Start adjustable blinking light (synchronized) + case 604: //Adjustable blinking light (unsynchronized) + case 605: //Adjustable blinking light (synchronized) + lines[i].args[0] = tag; + lines[i].args[1] = abs(lines[i].dx) >> FRACBITS; + lines[i].args[2] = abs(lines[i].dy) >> FRACBITS; + lines[i].args[3] = lines[i].frontsector->lightlevel; + if ((lines[i].flags & ML_NOCLIMB) && lines[i].backsector) + lines[i].args[5] = lines[i].backsector->lightlevel; + else + lines[i].args[4] |= TMB_USETARGET; + if (lines[i].special % 2 == 1) + { + lines[i].args[4] |= TMB_SYNC; + lines[i].special--; + } + break; + case 420: //Fade light level + lines[i].args[0] = tag; + if (lines[i].flags & ML_DONTPEGBOTTOM) + { + lines[i].args[1] = max(sides[lines[i].sidenum[0]].textureoffset >> FRACBITS, 0); + // failsafe: if user specifies Back Y Offset and NOT Front Y Offset, use the Back Offset + // to be consistent with other light and fade specials + lines[i].args[2] = ((lines[i].sidenum[1] != 0xFFFF && !(sides[lines[i].sidenum[0]].rowoffset >> FRACBITS)) ? + max(min(sides[lines[i].sidenum[1]].rowoffset >> FRACBITS, 255), 0) + : max(min(sides[lines[i].sidenum[0]].rowoffset >> FRACBITS, 255), 0)); + } + else + { + lines[i].args[1] = lines[i].frontsector->lightlevel; + lines[i].args[2] = abs(P_AproxDistance(lines[i].dx, lines[i].dy)) >> FRACBITS; + } + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[3] |= TMF_TICBASED; + if (lines[i].flags & ML_WRAPMIDTEX) + lines[i].args[3] |= TMF_OVERRIDE; + break; + case 421: //Stop lighting effect + lines[i].args[0] = tag; + break; + case 422: //Switch to cut-away view + lines[i].args[0] = tag; + lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[2] = (lines[i].flags & ML_NOCLIMB) ? sides[lines[i].sidenum[0]].textureoffset >> FRACBITS : 0; + break; + case 423: //Change sky + case 424: //Change weather + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 425: //Change object state + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + break; + case 426: //Stop object + lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 427: //Award score + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + break; + case 428: //Start platform movement + lines[i].args[0] = tag; + lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[3] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[4] = (lines[i].flags & ML_NOCLIMB) ? 1 : 0; + break; + case 429: //Crush ceiling once + case 430: //Crush floor once + case 431: //Crush floor and ceiling once + lines[i].args[0] = tag; + lines[i].args[1] = (lines[i].special == 429) ? TMP_CEILING : ((lines[i].special == 430) ? TMP_FLOOR : TMP_BOTH); + if (lines[i].special == 430 || lines[i].flags & ML_MIDSOLID) + { + lines[i].args[2] = abs(lines[i].dx) >> FRACBITS; + lines[i].args[3] = lines[i].args[2]; + } + else + { + lines[i].args[2] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> (FRACBITS + 1); + lines[i].args[3] = lines[i].args[2] / 4; + } + lines[i].special = 429; + break; + case 432: //Enable/disable 2D mode + lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 433: //Enable/disable gravity flip + lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 434: //Award power-up + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + if (lines[i].sidenum[1] != 0xffff && lines[i].flags & ML_BLOCKMONSTERS) // read power from back sidedef + { + lines[i].stringargs[1] = Z_Malloc(strlen(sides[lines[i].sidenum[1]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[1], sides[lines[i].sidenum[1]].text, strlen(sides[lines[i].sidenum[1]].text) + 1); + } + else + P_WriteConstant((lines[i].flags & ML_NOCLIMB) ? -1 : (sides[lines[i].sidenum[0]].textureoffset >> FRACBITS), &lines[i].stringargs[1]); + break; + case 435: //Change plane scroller direction + lines[i].args[0] = tag; + lines[i].args[1] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; + break; + case 436: //Shatter FOF + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + break; + case 437: //Disable player control + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 438: //Change object size + lines[i].args[0] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + break; + case 439: //Change tagged linedef's textures + lines[i].args[0] = tag; + lines[i].args[1] = TMSD_FRONTBACK; + lines[i].args[2] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 441: //Condition set trigger + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + break; + case 442: //Change object type state + lines[i].args[0] = tag; + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + if (lines[i].sidenum[1] == 0xffff) + lines[i].args[1] = 1; + else + { + lines[i].args[1] = 0; + if (sides[lines[i].sidenum[1]].text) + { + lines[i].stringargs[1] = Z_Malloc(strlen(sides[lines[i].sidenum[1]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[1], sides[lines[i].sidenum[1]].text, strlen(sides[lines[i].sidenum[1]].text) + 1); + } + } + break; case 443: //Call Lua function if (lines[i].text) { @@ -3023,47 +5230,444 @@ static void P_ConvertBinaryMap(void) else CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(i)); break; + case 444: //Earthquake + lines[i].args[0] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + break; + case 445: //Make FOF disappear/reappear + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 446: //Make FOF crumble + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] |= TMFR_NORETURN; + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[2] |= TMFR_CHECKFLAG; + break; case 447: //Change colormap - lines[i].args[0] = Tag_FGet(&lines[i].tags); - if (lines[i].flags & ML_EFFECT3) + lines[i].args[0] = tag; + if (lines[i].flags & ML_MIDPEG) lines[i].args[2] |= TMCF_RELATIVE; - if (lines[i].flags & ML_EFFECT1) + if (lines[i].flags & ML_SKEWTD) lines[i].args[2] |= TMCF_SUBLIGHTR|TMCF_SUBFADER; if (lines[i].flags & ML_NOCLIMB) lines[i].args[2] |= TMCF_SUBLIGHTG|TMCF_SUBFADEG; - if (lines[i].flags & ML_EFFECT2) + if (lines[i].flags & ML_NOSKEW) lines[i].args[2] |= TMCF_SUBLIGHTB|TMCF_SUBFADEB; break; + case 448: //Change skybox + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if ((lines[i].flags & (ML_MIDSOLID|ML_BLOCKMONSTERS)) == ML_MIDSOLID) // Solid Midtexture is on but Block Enemies is off? + { + CONS_Alert(CONS_WARNING, + M_GetText("Skybox switch linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), + tag); + lines[i].special = 0; + break; + } + else if ((lines[i].flags & (ML_MIDSOLID|ML_BLOCKMONSTERS)) == (ML_MIDSOLID|ML_BLOCKMONSTERS)) + lines[i].args[2] = TMS_CENTERPOINT; + else if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[2] = TMS_BOTH; + else + lines[i].args[2] = TMS_VIEWPOINT; + lines[i].args[3] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 449: //Enable bosses with parameters + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 450: //Execute linedef executor (specific tag) + lines[i].args[0] = tag; + break; + case 451: //Execute linedef executor (random tag in range) + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + break; + case 452: //Set FOF translucency + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = lines[i].sidenum[1] != 0xffff ? (sides[lines[i].sidenum[1]].textureoffset >> FRACBITS) : (P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS); + if (lines[i].flags & ML_MIDPEG) + lines[i].args[3] |= TMST_RELATIVE; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] |= TMST_DONTDOTRANSLUCENT; + break; + case 453: //Fade FOF + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = lines[i].sidenum[1] != 0xffff ? (sides[lines[i].sidenum[1]].textureoffset >> FRACBITS) : (lines[i].dx >> FRACBITS); + lines[i].args[3] = lines[i].sidenum[1] != 0xffff ? (sides[lines[i].sidenum[1]].rowoffset >> FRACBITS) : (abs(lines[i].dy) >> FRACBITS); + if (lines[i].flags & ML_MIDPEG) + lines[i].args[4] |= TMFT_RELATIVE; + if (lines[i].flags & ML_WRAPMIDTEX) + lines[i].args[4] |= TMFT_OVERRIDE; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[4] |= TMFT_TICBASED; + if (lines[i].flags & ML_BOUNCY) + lines[i].args[4] |= TMFT_IGNORECOLLISION; + if (lines[i].flags & ML_SKEWTD) + lines[i].args[4] |= TMFT_GHOSTFADE; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[4] |= TMFT_DONTDOTRANSLUCENT; + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[4] |= TMFT_DONTDOEXISTS; + if (lines[i].flags & ML_NOSKEW) + lines[i].args[4] |= (TMFT_DONTDOLIGHTING|TMFT_DONTDOCOLORMAP); + if (lines[i].flags & ML_TFERLINE) + lines[i].args[4] |= TMFT_USEEXACTALPHA; + break; + case 454: //Stop fading FOF + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = !!(lines[i].flags & ML_BLOCKMONSTERS); + break; case 455: //Fade colormap { INT32 speed = (INT32)((((lines[i].flags & ML_DONTPEGBOTTOM) || !sides[lines[i].sidenum[0]].rowoffset) && lines[i].sidenum[1] != 0xFFFF) ? abs(sides[lines[i].sidenum[1]].rowoffset >> FRACBITS) : abs(sides[lines[i].sidenum[0]].rowoffset >> FRACBITS)); - lines[i].args[0] = Tag_FGet(&lines[i].tags); - if (lines[i].flags & ML_EFFECT4) + lines[i].args[0] = tag; + if (lines[i].flags & ML_MIDSOLID) lines[i].args[2] = speed; else lines[i].args[2] = (256 + speed - 1)/speed; - if (lines[i].flags & ML_EFFECT3) + if (lines[i].flags & ML_MIDPEG) lines[i].args[3] |= TMCF_RELATIVE; - if (lines[i].flags & ML_EFFECT1) + if (lines[i].flags & ML_SKEWTD) lines[i].args[3] |= TMCF_SUBLIGHTR|TMCF_SUBFADER; if (lines[i].flags & ML_NOCLIMB) lines[i].args[3] |= TMCF_SUBLIGHTG|TMCF_SUBFADEG; - if (lines[i].flags & ML_EFFECT2) + if (lines[i].flags & ML_NOSKEW) lines[i].args[3] |= TMCF_SUBLIGHTB|TMCF_SUBFADEB; if (lines[i].flags & ML_BOUNCY) lines[i].args[3] |= TMCF_FROMBLACK; - if (lines[i].flags & ML_EFFECT5) + if (lines[i].flags & ML_WRAPMIDTEX) lines[i].args[3] |= TMCF_OVERRIDE; break; } case 456: //Stop fading colormap - lines[i].args[0] = Tag_FGet(&lines[i].tags); + lines[i].args[0] = tag; + break; + case 457: //Track object's angle + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[3] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].rowoffset >> FRACBITS : 0; + lines[i].args[4] = !!(lines[i].flags & ML_NOSKEW); + break; + case 459: //Control text prompt + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if (lines[i].flags & ML_BLOCKMONSTERS) + lines[i].args[2] |= TMP_CLOSE; + if (lines[i].flags & ML_SKEWTD) + lines[i].args[2] |= TMP_RUNPOSTEXEC; + if (lines[i].flags & ML_TFERLINE) + lines[i].args[2] |= TMP_CALLBYNAME; + if (lines[i].flags & ML_NOSKEW) + lines[i].args[2] |= TMP_KEEPCONTROLS; + if (lines[i].flags & ML_MIDPEG) + lines[i].args[2] |= TMP_KEEPREALTIME; + /*if (lines[i].flags & ML_NOCLIMB) + lines[i].args[2] |= TMP_ALLPLAYERS; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[2] |= TMP_FREEZETHINKERS;*/ + lines[i].args[3] = (lines[i].sidenum[1] != 0xFFFF) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : tag; + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + break; + case 460: //Award rings + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + break; + case 461: //Spawn object + lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[2] = lines[i].frontsector->floorheight >> FRACBITS; + lines[i].args[3] = (lines[i].flags & ML_SKEWTD) ? AngleFixed(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)) >> FRACBITS : 0; + if (lines[i].flags & ML_NOCLIMB) + { + if (lines[i].sidenum[1] != 0xffff) // Make sure the linedef has a back side + { + lines[i].args[4] = 1; + lines[i].args[5] = sides[lines[i].sidenum[1]].textureoffset >> FRACBITS; + lines[i].args[6] = sides[lines[i].sidenum[1]].rowoffset >> FRACBITS; + lines[i].args[7] = lines[i].frontsector->ceilingheight >> FRACBITS; + } + else + { + CONS_Alert(CONS_WARNING, "Linedef Type %d - Spawn Object: Linedef is set for random range but has no back side.\n", lines[i].special); + lines[i].args[4] = 0; + } + } + else + lines[i].args[4] = 0; + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + break; + case 463: //Dye object + if (sides[lines[i].sidenum[0]].text) + { + lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); + M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); + } + break; + case 464: //Trigger egg capsule + lines[i].args[0] = tag; + lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 466: //Set level failure state + lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 467: //Set light level + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = TML_SECTOR; + lines[i].args[3] = !!(lines[i].flags & ML_MIDPEG); + break; + case 480: //Polyobject - door slide + case 481: //Polyobject - door move + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if (lines[i].sidenum[1] != 0xffff) + lines[i].args[3] = sides[lines[i].sidenum[1]].textureoffset >> FRACBITS; + break; + case 482: //Polyobject - move + case 483: //Polyobject - move, override + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + lines[i].args[3] = lines[i].special == 483; + lines[i].special = 482; + break; + case 484: //Polyobject - rotate right + case 485: //Polyobject - rotate right, override + case 486: //Polyobject - rotate left + case 487: //Polyobject - rotate left, override + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if (lines[i].args[2] == 360) + lines[i].args[3] |= TMPR_CONTINUOUS; + else if (lines[i].args[2] == 0) + lines[i].args[2] = 360; + if (lines[i].special < 486) + lines[i].args[2] *= -1; + if (lines[i].flags & ML_NOCLIMB) + lines[i].args[3] |= TMPR_DONTROTATEOTHERS; + else if (lines[i].flags & ML_MIDSOLID) + lines[i].args[3] |= TMPR_ROTATEPLAYERS; + if (lines[i].special % 2 == 1) + lines[i].args[3] |= TMPR_OVERRIDE; + lines[i].special = 484; + break; + case 488: //Polyobject - move by waypoints + lines[i].args[0] = tag; + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + if (lines[i].flags & ML_MIDPEG) + lines[i].args[3] = PWR_WRAP; + else if (lines[i].flags & ML_NOSKEW) + lines[i].args[3] = PWR_COMEBACK; + else + lines[i].args[3] = PWR_STOP; + if (lines[i].flags & ML_SKEWTD) + lines[i].args[4] |= PWF_REVERSE; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[4] |= PWF_LOOP; + break; + case 489: //Polyobject - turn invisible, intangible + case 490: //Polyobject - turn visible, tangible + lines[i].args[0] = tag; + lines[i].args[1] = 491 - lines[i].special; + if (!(lines[i].flags & ML_NOCLIMB)) + lines[i].args[2] = lines[i].args[1]; + lines[i].special = 489; + break; + case 491: //Polyobject - set translucency + lines[i].args[0] = tag; + // If Front X Offset is specified, use that. Else, use floorheight. + lines[i].args[1] = (sides[lines[i].sidenum[0]].textureoffset ? sides[lines[i].sidenum[0]].textureoffset : lines[i].frontsector->floorheight) >> FRACBITS; + // If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000. + if (!(lines[i].flags & ML_DONTPEGBOTTOM)) + lines[i].args[1] /= 100; + lines[i].args[2] = !!(lines[i].flags & ML_MIDPEG); + break; + case 492: //Polyobject - fade translucency + lines[i].args[0] = tag; + // If Front X Offset is specified, use that. Else, use floorheight. + lines[i].args[1] = (sides[lines[i].sidenum[0]].textureoffset ? sides[lines[i].sidenum[0]].textureoffset : lines[i].frontsector->floorheight) >> FRACBITS; + // If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000. + if (!(lines[i].flags & ML_DONTPEGBOTTOM)) + lines[i].args[1] /= 100; + // allow Back Y Offset to be consistent with other fade specials + lines[i].args[2] = (lines[i].sidenum[1] != 0xffff && !sides[lines[i].sidenum[0]].rowoffset) ? + abs(sides[lines[i].sidenum[1]].rowoffset >> FRACBITS) + : abs(sides[lines[i].sidenum[0]].rowoffset >> FRACBITS); + if (lines[i].flags & ML_MIDPEG) + lines[i].args[3] |= TMPF_RELATIVE; + if (lines[i].flags & ML_WRAPMIDTEX) + lines[i].args[3] |= TMPF_OVERRIDE; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[3] |= TMPF_TICBASED; + if (lines[i].flags & ML_BOUNCY) + lines[i].args[3] |= TMPF_IGNORECOLLISION; + if (lines[i].flags & ML_SKEWTD) + lines[i].args[3] |= TMPF_GHOSTFADE; + break; + case 500: //Scroll front wall left + case 501: //Scroll front wall right + lines[i].args[0] = 0; + lines[i].args[1] = (lines[i].special == 500) ? -1 : 1; + lines[i].args[2] = 0; + lines[i].special = 500; + break; + case 502: //Scroll tagged wall + case 503: //Scroll tagged wall (accelerative) + case 504: //Scroll tagged wall (displacement) + lines[i].args[0] = tag; + if (lines[i].flags & ML_MIDPEG) + { + if (lines[i].sidenum[1] == 0xffff) + { + CONS_Debug(DBG_GAMELOGIC, "Line special %d (line #%s) missing back side!\n", lines[i].special, sizeu1(i)); + lines[i].special = 0; + break; + } + lines[i].args[1] = 1; + } + else + lines[i].args[1] = 0; + if (lines[i].flags & ML_NOSKEW) + { + lines[i].args[2] = sides[lines[i].sidenum[0]].textureoffset >> (FRACBITS - SCROLL_SHIFT); + lines[i].args[3] = sides[lines[i].sidenum[0]].rowoffset >> (FRACBITS - SCROLL_SHIFT); + } + else + { + lines[i].args[2] = lines[i].dx >> FRACBITS; + lines[i].args[3] = lines[i].dy >> FRACBITS; + } + lines[i].args[4] = lines[i].special - 502; + lines[i].special = 502; + break; + case 505: //Scroll front wall by front side offsets + case 506: //Scroll front wall by back side offsets + case 507: //Scroll back wall by front side offsets + case 508: //Scroll back wall by back side offsets + lines[i].args[0] = lines[i].special >= 507; + if (lines[i].special % 2 == 0) + { + if (lines[i].sidenum[1] == 0xffff) + { + CONS_Debug(DBG_GAMELOGIC, "Line special %d (line #%s) missing back side!\n", lines[i].special, sizeu1(i)); + lines[i].special = 0; + break; + } + lines[i].args[1] = sides[lines[i].sidenum[1]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[1]].rowoffset >> FRACBITS; + } + else + { + lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + lines[i].args[2] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; + } + lines[i].special = 500; + break; + case 510: //Scroll floor texture + case 511: //Scroll floor texture (accelerative) + case 512: //Scroll floor texture (displacement) + case 513: //Scroll ceiling texture + case 514: //Scroll ceiling texture (accelerative) + case 515: //Scroll ceiling texture (displacement) + case 520: //Carry objects on floor + case 521: //Carry objects on floor (accelerative) + case 522: //Carry objects on floor (displacement) + case 523: //Carry objects on ceiling + case 524: //Carry objects on ceiling (accelerative) + case 525: //Carry objects on ceiling (displacement) + case 530: //Scroll floor texture and carry objects + case 531: //Scroll floor texture and carry objects (accelerative) + case 532: //Scroll floor texture and carry objects (displacement) + case 533: //Scroll ceiling texture and carry objects + case 534: //Scroll ceiling texture and carry objects (accelerative) + case 535: //Scroll ceiling texture and carry objects (displacement) + lines[i].args[0] = tag; + lines[i].args[1] = ((lines[i].special % 10) < 3) ? TMP_FLOOR : TMP_CEILING; + lines[i].args[2] = ((lines[i].special - 510)/10 + 1) % 3; + lines[i].args[3] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; + lines[i].args[4] = (lines[i].special % 10) % 3; + if (lines[i].args[2] != TMS_SCROLLONLY && !(lines[i].flags & ML_NOCLIMB)) + lines[i].args[4] |= TMST_NONEXCLUSIVE; + lines[i].special = 510; + break; + case 540: //Floor friction + { + INT32 s; + fixed_t strength; // friction value of sector + fixed_t friction; // friction value to be applied during movement + + strength = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; + if (strength > 0) // sludge + strength = strength*2; // otherwise, the maximum sludginess value is +967... + + // The following might seem odd. At the time of movement, + // the move distance is multiplied by 'friction/0x10000', so a + // higher friction value actually means 'less friction'. + friction = ORIG_FRICTION - (0x1EB8*strength)/0x80; // ORIG_FRICTION is 0xE800 + + TAG_ITER_SECTORS(tag, s) + sectors[s].friction = friction; + break; + } + case 541: //Wind + case 542: //Upwards wind + case 543: //Downwards wind + case 544: //Current + case 545: //Upwards current + case 546: //Downwards current + lines[i].args[0] = tag; + switch ((lines[i].special - 541) % 3) + { + case 0: + lines[i].args[1] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; + break; + case 1: + lines[i].args[2] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; + break; + case 2: + lines[i].args[2] = -R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; + break; + } + lines[i].args[3] = (lines[i].special >= 544) ? p_current : p_wind; + if (lines[i].flags & ML_MIDSOLID) + lines[i].args[4] |= TMPF_SLIDE; + if (!(lines[i].flags & ML_NOCLIMB)) + lines[i].args[4] |= TMPF_NONEXCLUSIVE; + lines[i].special = 541; + break; + case 600: //Floor lighting + case 601: //Ceiling lighting + lines[i].args[0] = tag; + lines[i].args[1] = (lines[i].special == 601) ? TMP_CEILING : TMP_FLOOR; + lines[i].special = 600; break; case 606: //Colormap - lines[i].args[0] = Tag_FGet(&lines[i].tags); + lines[i].args[0] = tag; break; case 700: //Slope front sector floor case 701: //Slope front sector ceiling @@ -3086,6 +5690,8 @@ static void P_ConvertBinaryMap(void) lines[i].args[2] |= TMSL_NOPHYSICS; if (lines[i].flags & ML_NONET) lines[i].args[2] |= TMSL_DYNAMIC; + if (lines[i].flags & ML_TFERLINE) + lines[i].args[2] |= TMSL_COPY; lines[i].special = 700; break; @@ -3141,21 +5747,63 @@ static void P_ConvertBinaryMap(void) lines[i].args[1] = tag; lines[i].special = 720; break; - case 900: //Translucent wall (10%) - case 901: //Translucent wall (20%) - case 902: //Translucent wall (30%) - case 903: //Translucent wall (40%) - case 904: //Translucent wall (50%) - case 905: //Translucent wall (60%) - case 906: //Translucent wall (70%) - case 907: //Translucent wall (80%) - case 908: //Translucent wall (90%) - lines[i].alpha = ((909 - lines[i].special) << FRACBITS)/10; + case 723: //Copy back side floor slope + case 724: //Copy back side ceiling slope + case 725: //Copy back side floor and ceiling slope + if (lines[i].special != 724) + lines[i].args[2] = tag; + if (lines[i].special != 723) + lines[i].args[3] = tag; + lines[i].special = 720; + break; + case 730: //Copy front side floor slope to back side + case 731: //Copy front side ceiling slope to back side + case 732: //Copy front side floor and ceiling slope to back side + if (lines[i].special != 731) + lines[i].args[4] |= TMSC_FRONTTOBACKFLOOR; + if (lines[i].special != 730) + lines[i].args[4] |= TMSC_FRONTTOBACKCEILING; + lines[i].special = 720; + break; + case 733: //Copy back side floor slope to front side + case 734: //Copy back side ceiling slope to front side + case 735: //Copy back side floor and ceiling slope to front side + if (lines[i].special != 734) + lines[i].args[4] |= TMSC_BACKTOFRONTFLOOR; + if (lines[i].special != 733) + lines[i].args[4] |= TMSC_BACKTOFRONTCEILING; + lines[i].special = 720; + break; + case 799: //Set dynamic slope vertex to front sector height + lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); + break; + case 909: //Fog wall + lines[i].blendmode = AST_FOG; break; default: break; } + // Set alpha for translucent walls + if (lines[i].special >= 900 && lines[i].special < 909) + lines[i].alpha = ((909 - lines[i].special) << FRACBITS)/10; + + // Set alpha for additive/subtractive/reverse subtractive walls + if (lines[i].special >= 910 && lines[i].special <= 939) + lines[i].alpha = ((10 - lines[i].special % 10) << FRACBITS)/10; + + if (lines[i].special >= 910 && lines[i].special <= 919) // additive + lines[i].blendmode = AST_ADD; + + if (lines[i].special >= 920 && lines[i].special <= 929) // subtractive + lines[i].blendmode = AST_SUBTRACT; + + if (lines[i].special >= 930 && lines[i].special <= 939) // reverse subtractive + lines[i].blendmode = AST_REVERSESUBTRACT; + + if (lines[i].special == 940) // modulate + lines[i].blendmode = AST_MODULATE; + //Linedef executor delay if (lines[i].special >= 400 && lines[i].special < 500) { @@ -3165,29 +5813,531 @@ static void P_ConvertBinaryMap(void) lines[i].executordelay = 1; } } +} + +static void P_ConvertBinarySectorTypes(void) +{ + size_t i; + + for (i = 0; i < numsectors; i++) + { + mtag_t tag = Tag_FGet(§ors[i].tags); + + switch(GETSECSPECIAL(sectors[i].special, 1)) + { + case 1: //Damage + sectors[i].damagetype = SD_GENERIC; + break; + case 2: //Damage (Water) + sectors[i].damagetype = SD_WATER; + break; + case 3: //Damage (Fire) + { + size_t j; + boolean isLava = false; + + for (j = 0; j < sectors[i].linecount; j++) + { + line_t *line = sectors[i].lines[j]; + + if (line->frontsector != §ors[i]) + continue; + + if (line->flags & ML_BLOCKMONSTERS) + continue; + + if (line->special == 120 || (line->special == 259 && (line->args[2] & FF_SWIMMABLE))) + { + isLava = true; + break; + } + } + sectors[i].damagetype = isLava ? SD_LAVA : SD_FIRE; + break; + } + case 4: //Damage (Electric) + sectors[i].damagetype = SD_ELECTRIC; + break; + case 5: //Spikes + sectors[i].damagetype = SD_SPIKE; + break; + case 6: //Death pit (camera tilt) + sectors[i].damagetype = SD_DEATHPITTILT; + break; + case 7: //Death pit (no camera tilt) + sectors[i].damagetype = SD_DEATHPITNOTILT; + break; + case 8: //Instakill + sectors[i].damagetype = SD_INSTAKILL; + break; + case 11: //Special stage damage + sectors[i].damagetype = SD_SPECIALSTAGE; + break; + case 12: //Space countdown + sectors[i].specialflags |= SSF_OUTERSPACE; + break; + case 13: //Ramp sector + sectors[i].specialflags |= SSF_DOUBLESTEPUP; + break; + case 14: //Non-ramp sector + sectors[i].specialflags |= SSF_NOSTEPDOWN; + break; + default: + break; + } + + switch(GETSECSPECIAL(sectors[i].special, 2)) + { + case 1: //Trigger linedef executor (pushable objects) + sectors[i].triggertag = tag; + sectors[i].flags |= MSF_TRIGGERLINE_PLANE; + sectors[i].triggerer = TO_MOBJ; + break; + case 2: //Trigger linedef executor (Anywhere in sector, all players) + sectors[i].triggertag = tag; + sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE; + sectors[i].triggerer = TO_ALLPLAYERS; + break; + case 3: //Trigger linedef executor (Floor touch, all players) + sectors[i].triggertag = tag; + sectors[i].flags |= MSF_TRIGGERLINE_PLANE; + sectors[i].triggerer = TO_ALLPLAYERS; + break; + case 4: //Trigger linedef executor (Anywhere in sector) + sectors[i].triggertag = tag; + sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE; + sectors[i].triggerer = TO_PLAYER; + break; + case 5: //Trigger linedef executor (Floor touch) + sectors[i].triggertag = tag; + sectors[i].flags |= MSF_TRIGGERLINE_PLANE; + sectors[i].triggerer = TO_PLAYER; + break; + case 6: //Trigger linedef executor (Emerald check) + sectors[i].triggertag = tag; + sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE; + sectors[i].triggerer = TO_PLAYEREMERALDS; + break; + case 7: //Trigger linedef executor (NiGHTS mare) + sectors[i].triggertag = tag; + sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE; + sectors[i].triggerer = TO_PLAYERNIGHTS; + break; + case 8: //Check for linedef executor on FOFs + sectors[i].flags |= MSF_TRIGGERLINE_MOBJ; + break; + default: + break; + } + + switch(GETSECSPECIAL(sectors[i].special, 3)) + { + case 5: //Speed pad + sectors[i].specialflags |= SSF_SPEEDPAD; + break; + default: + break; + } + + switch(GETSECSPECIAL(sectors[i].special, 4)) + { + case 1: //Star post activator + sectors[i].specialflags |= SSF_STARPOSTACTIVATOR; + break; + case 2: //Exit/Special Stage pit/Return flag + sectors[i].specialflags |= SSF_EXIT|SSF_SPECIALSTAGEPIT|SSF_RETURNFLAG; + break; + case 3: //Red team base + sectors[i].specialflags |= SSF_REDTEAMBASE; + break; + case 4: //Blue team base + sectors[i].specialflags |= SSF_BLUETEAMBASE; + break; + case 5: //Fan sector + sectors[i].specialflags |= SSF_FAN; + break; + case 6: //Super Sonic transform + sectors[i].specialflags |= SSF_SUPERTRANSFORM; + break; + case 7: //Force spin + sectors[i].specialflags |= SSF_FORCESPIN; + break; + case 8: //Zoom tube start + sectors[i].specialflags |= SSF_ZOOMTUBESTART; + break; + case 9: //Zoom tube end + sectors[i].specialflags |= SSF_ZOOMTUBEEND; + break; + case 10: //Circuit finish line + sectors[i].specialflags |= SSF_FINISHLINE; + break; + case 11: //Rope hang + sectors[i].specialflags |= SSF_ROPEHANG; + break; + case 12: //Intangible to the camera + sectors[i].flags |= MSF_NOCLIPCAMERA; + break; + default: + break; + } + } +} + +static void P_ConvertBinaryThingTypes(void) +{ + size_t i; + mobjtype_t mobjtypeofthing[4096] = {0}; + mobjtype_t mobjtype; + + for (i = 0; i < NUMMOBJTYPES; i++) + { + if (mobjinfo[i].doomednum < 0 || mobjinfo[i].doomednum >= 4096) + continue; + + mobjtypeofthing[mobjinfo[i].doomednum] = (mobjtype_t)i; + } for (i = 0; i < nummapthings; i++) { + mobjtype = mobjtypeofthing[mapthings[i].type]; + if (mobjtype) + { + if (mobjinfo[mobjtype].flags & MF_BOSS) + { + INT32 paramoffset = mapthings[i].extrainfo*LE_PARAMWIDTH; + mapthings[i].args[0] = mapthings[i].extrainfo; + mapthings[i].args[1] = !!(mapthings[i].options & MTF_OBJECTSPECIAL); + mapthings[i].args[2] = LE_BOSSDEAD + paramoffset; + mapthings[i].args[3] = LE_ALLBOSSESDEAD + paramoffset; + mapthings[i].args[4] = LE_PINCHPHASE + paramoffset; + } + if (mobjinfo[mobjtype].flags & MF_NIGHTSITEM) + { + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[0] |= TMNI_BONUSONLY; + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[0] |= TMNI_REVEAL; + } + if (mobjinfo[mobjtype].flags & MF_PUSHABLE) + { + if ((mapthings[i].options & (MTF_OBJECTSPECIAL|MTF_AMBUSH)) == (MTF_OBJECTSPECIAL|MTF_AMBUSH)) + mapthings[i].args[0] = TMP_CLASSIC; + else if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[0] = TMP_SLIDE; + else if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[0] = TMP_IMMOVABLE; + else + mapthings[i].args[0] = TMP_NORMAL; + } + if ((mobjinfo[mobjtype].flags & MF_SPRING) && mobjinfo[mobjtype].painchance == 3) + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + if (mobjinfo[mobjtype].flags & MF_MONITOR) + { + if ((mapthings[i].options & MTF_EXTRA) && mapthings[i].angle & 16384) + mapthings[i].args[0] = mapthings[i].angle & 16383; + + if (mobjinfo[mobjtype].speed != 0) + { + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[1] = TMMR_STRONG; + else if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[1] = TMMR_WEAK; + else + mapthings[i].args[1] = TMMR_SAME; + } + } + } + + if (mapthings[i].type >= 1 && mapthings[i].type <= 35) //Player starts + { + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + continue; + } + else if (mapthings[i].type >= 2200 && mapthings[i].type <= 2217) //Flickies + { + mapthings[i].args[0] = mapthings[i].angle; + if (mapthings[i].options & MTF_EXTRA) + mapthings[i].args[1] |= TMFF_AIMLESS; + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[1] |= TMFF_STATIONARY; + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[1] |= TMFF_HOP; + if (mapthings[i].type == 2207) + mapthings[i].args[2] = mapthings[i].extrainfo; + continue; + } + switch (mapthings[i].type) { - case 750: - Tag_Add(&mapthings[i].tags, mapthings[i].angle); + case 102: //SDURF + case 1805: //Puma + mapthings[i].args[0] = mapthings[i].angle; break; - case 760: - case 761: - Tag_FSet(&mapthings[i].tags, mapthings[i].angle); + case 110: //THZ Turret + mapthings[i].args[0] = LE_TURRET; break; - case 762: + case 111: //Pop-up Turret + mapthings[i].args[0] = mapthings[i].angle; + break; + case 103: //Buzz (Gold) + case 104: //Buzz (Red) + case 105: //Jetty-syn Bomber + case 106: //Jetty-syn Gunner + case 117: //Robo-Hood + case 126: //Crushstacean + case 128: //Bumblebore + case 132: //Cacolantern + case 138: //Banpyura + case 1602: //Pian + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 119: //Egg Guard + if ((mapthings[i].options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_OBJECTSPECIAL) + mapthings[i].args[0] = TMGD_LEFT; + else if ((mapthings[i].options & (MTF_EXTRA|MTF_OBJECTSPECIAL)) == MTF_EXTRA) + mapthings[i].args[0] = TMGD_RIGHT; + else + mapthings[i].args[0] = TMGD_BACK; + mapthings[i].args[1] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 127: //Hive Elemental + mapthings[i].args[0] = mapthings[i].extrainfo; + break; + case 135: //Pterabyte Spawner + mapthings[i].args[0] = mapthings[i].extrainfo + 1; + break; + case 136: //Pyre Fly + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 201: //Egg Slimer + mapthings[i].args[5] = !(mapthings[i].options & MTF_AMBUSH); + break; + case 203: //Egg Colosseum + mapthings[i].args[5] = LE_BOSS4DROP + mapthings[i].extrainfo * LE_PARAMWIDTH; + break; + case 204: //Fang + mapthings[i].args[4] = LE_BOSS4DROP + mapthings[i].extrainfo*LE_PARAMWIDTH; + if (mapthings[i].options & MTF_EXTRA) + mapthings[i].args[5] |= TMF_GRAYSCALE; + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[5] |= TMF_SKIPINTRO; + break; + case 206: //Brak Eggman (Old) + mapthings[i].args[5] = LE_BRAKPLATFORM + mapthings[i].extrainfo*LE_PARAMWIDTH; + break; + case 207: //Metal Sonic (Race) + case 2104: //Amy Cameo + mapthings[i].args[0] = !!(mapthings[i].options & MTF_EXTRA); + break; + case 208: //Metal Sonic (Battle) + mapthings[i].args[5] = !!(mapthings[i].options & MTF_EXTRA); + break; + case 209: //Brak Eggman + mapthings[i].args[5] = LE_BRAKVILEATACK + mapthings[i].extrainfo*LE_PARAMWIDTH; + if (mapthings[i].options & MTF_EXTRA) + mapthings[i].args[6] |= TMB_NODEATHFLING; + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[6] |= TMB_BARRIER; + break; + case 292: //Boss waypoint + mapthings[i].args[0] = mapthings[i].angle; + mapthings[i].args[1] = mapthings[i].options & 7; + break; + case 294: //Fang waypoint + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 300: //Ring + case 301: //Bounce ring + case 302: //Rail ring + case 303: //Infinity ring + case 304: //Automatic ring + case 305: //Explosion ring + case 306: //Scatter ring + case 307: //Grenade ring + case 308: //Red team ring + case 309: //Blue team ring + case 312: //Emerald token + case 320: //Emerald hunt location + case 321: //Match chaos emerald spawn + case 322: //Emblem + case 330: //Bounce ring panel + case 331: //Rail ring panel + case 332: //Automatic ring panel + case 333: //Explosion ring panel + case 334: //Scatter ring panel + case 335: //Grenade ring panel + case 520: //Bomb sphere + case 521: //Spikeball + case 1706: //Blue sphere + case 1800: //Coin + mapthings[i].args[0] = !(mapthings[i].options & MTF_AMBUSH); + break; + case 409: //Extra life monitor + mapthings[i].args[2] = !(mapthings[i].options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)); + break; + case 500: //Air bubble patch + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 502: //Star post + if (mapthings[i].extrainfo) + // Allow thing Parameter to define star post num too! + // For starposts above param 15 (the 16th), add 360 to the angle like before and start parameter from 1 (NOT 0)! + // So the 16th starpost is angle=0 param=15, the 17th would be angle=360 param=1. + // This seems more intuitive for mappers to use, since most SP maps won't have over 16 consecutive star posts. + mapthings[i].args[0] = mapthings[i].extrainfo + (mapthings[i].angle/360) * 15; + else + // Old behavior if Parameter is 0; add 360 to the angle for each consecutive star post. + mapthings[i].args[0] = (mapthings[i].angle/360); + mapthings[i].args[1] = !!(mapthings[i].options & MTF_OBJECTSPECIAL); + break; + case 522: //Wall spike + if (mapthings[i].options & MTF_OBJECTSPECIAL) + { + mapthings[i].args[0] = mobjinfo[MT_WALLSPIKE].speed + mapthings[i].angle/360; + mapthings[i].args[1] = (16 - mapthings[i].extrainfo) * mapthings[i].args[0]/16; + if (mapthings[i].options & MTF_EXTRA) + mapthings[i].args[2] |= TMSF_RETRACTED; + } + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[2] |= TMSF_INTANGIBLE; + break; + case 523: //Spike + if (mapthings[i].options & MTF_OBJECTSPECIAL) + { + mapthings[i].args[0] = mobjinfo[MT_SPIKE].speed + mapthings[i].angle; + mapthings[i].args[1] = (16 - mapthings[i].extrainfo) * mapthings[i].args[0]/16; + if (mapthings[i].options & MTF_EXTRA) + mapthings[i].args[2] |= TMSF_RETRACTED; + } + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[2] |= TMSF_INTANGIBLE; + break; + case 540: //Fan + mapthings[i].args[0] = mapthings[i].angle; + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[1] |= TMF_INVISIBLE; + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[1] |= TMF_NODISTANCECHECK; + break; + case 541: //Gas jet + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 543: //Balloon + if (mapthings[i].angle > 0) + P_WriteConstant(((mapthings[i].angle - 1) % (numskincolors - 1)) + 1, &mapthings[i].stringargs[0]); + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 555: //Diagonal yellow spring + case 556: //Diagonal red spring + case 557: //Diagonal blue spring + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[0] |= TMDS_NOGRAVITY; + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[0] |= TMDS_ROTATEEXTRA; + break; + case 558: //Horizontal yellow spring + case 559: //Horizontal red spring + case 560: //Horizontal blue spring + mapthings[i].args[0] = !(mapthings[i].options & MTF_AMBUSH); + break; + case 700: //Water ambience A + case 701: //Water ambience B + case 702: //Water ambience C + case 703: //Water ambience D + case 704: //Water ambience E + case 705: //Water ambience F + case 706: //Water ambience G + case 707: //Water ambience H + mapthings[i].args[0] = 35; + P_WriteConstant(sfx_amwtr1 + mapthings[i].type - 700, &mapthings[i].stringargs[0]); + mapthings[i].type = 700; + break; + case 708: //Disco ambience + mapthings[i].args[0] = 512; + P_WriteConstant(sfx_ambint, &mapthings[i].stringargs[0]); + mapthings[i].type = 700; + break; + case 709: //Volcano ambience + mapthings[i].args[0] = 220; + P_WriteConstant(sfx_ambin2, &mapthings[i].stringargs[0]); + mapthings[i].type = 700; + break; + case 710: //Machine ambience + mapthings[i].args[0] = 24; + P_WriteConstant(sfx_ambmac, &mapthings[i].stringargs[0]); + mapthings[i].type = 700; + break; + case 750: //Slope vertex + mapthings[i].args[0] = mapthings[i].extrainfo; + break; + case 753: //Zoom tube waypoint + mapthings[i].args[0] = mapthings[i].angle >> 8; + mapthings[i].args[1] = mapthings[i].angle & 255; + break; + case 754: //Push point + case 755: //Pull point + { + subsector_t *ss = R_PointInSubsector(mapthings[i].x << FRACBITS, mapthings[i].y << FRACBITS); + sector_t *s; + line_t *line; + + if (!ss) + { + CONS_Debug(DBG_GAMELOGIC, "Push/pull point: Placed outside of map bounds!\n"); + break; + } + + s = ss->sector; + line = P_FindPointPushLine(&s->tags); + + if (!line) + { + CONS_Debug(DBG_GAMELOGIC, "Push/pull point: Unable to find line of type 547 tagged to sector %s!\n", sizeu1((size_t)(s - sectors))); + break; + } + + mapthings[i].args[0] = mapthings[i].angle; + mapthings[i].args[1] = P_AproxDistance(line->dx >> FRACBITS, line->dy >> FRACBITS); + if (mapthings[i].type == 755) + mapthings[i].args[1] *= -1; + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[2] |= TMPP_NOZFADE; + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[2] |= TMPP_PUSHZ; + if (!(line->flags & ML_NOCLIMB)) + mapthings[i].args[2] |= TMPP_NONEXCLUSIVE; + mapthings[i].type = 754; + break; + } + case 756: //Blast linedef executor + mapthings[i].args[0] = mapthings[i].angle; + break; + case 757: //Fan particle generator + { + INT32 j = Tag_FindLineSpecial(15, mapthings[i].angle); + + if (j == -1) + { + CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs to be tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(i), mapthings[i].angle); + break; + } + mapthings[i].args[0] = mapthings[i].z; + mapthings[i].args[1] = R_PointToDist2(lines[j].v1->x, lines[j].v1->y, lines[j].v2->x, lines[j].v2->y) >> FRACBITS; + mapthings[i].args[2] = sides[lines[j].sidenum[0]].textureoffset >> FRACBITS; + mapthings[i].args[3] = sides[lines[j].sidenum[0]].rowoffset >> FRACBITS; + mapthings[i].args[4] = lines[j].backsector ? sides[lines[j].sidenum[1]].textureoffset >> FRACBITS : 0; + mapthings[i].args[6] = mapthings[i].angle; + if (sides[lines[j].sidenum[0]].toptexture) + P_WriteConstant(sides[lines[j].sidenum[0]].toptexture, &mapthings[i].stringargs[0]); + break; + } + case 762: //PolyObject spawn point (crush) { INT32 check = -1; INT32 firstline = -1; - mtag_t tag = mapthings[i].angle; + mtag_t tag = Tag_FGet(&mapthings[i].tags); - TAG_ITER_DECLARECOUNTER(0); - - Tag_FSet(&mapthings[i].tags, tag); - - TAG_ITER_LINES(0, tag, check) + TAG_ITER_LINES(tag, check) { if (lines[check].special == 20) { @@ -3202,8 +6352,201 @@ static void P_ConvertBinaryMap(void) mapthings[i].type = 761; break; } - case 780: - Tag_FSet(&mapthings[i].tags, mapthings[i].extrainfo); + case 780: //Skybox + mapthings[i].args[0] = !!(mapthings[i].options & MTF_OBJECTSPECIAL); + break; + case 799: //Tutorial plant + mapthings[i].args[0] = mapthings[i].extrainfo; + break; + case 1002: //Dripping water + mapthings[i].args[0] = mapthings[i].angle; + break; + case 1007: //Kelp + case 1008: //Stalagmite (DSZ1) + case 1011: //Stalagmite (DSZ2) + mapthings[i].args[0] = !!(mapthings[i].options & MTF_OBJECTSPECIAL); + break; + case 1102: //Eggman Statue + mapthings[i].args[1] = !!(mapthings[i].options & MTF_EXTRA); + break; + case 1104: //Mace spawnpoint + case 1105: //Chain with maces spawnpoint + case 1106: //Chained spring spawnpoint + case 1107: //Chain spawnpoint + case 1109: //Firebar spawnpoint + case 1110: //Custom mace spawnpoint + { + mtag_t tag = (mtag_t)mapthings[i].angle; + INT32 j = Tag_FindLineSpecial(9, tag); + + if (j == -1) + { + CONS_Debug(DBG_GAMELOGIC, "Chain/mace setup: Unable to find parameter line 9 (tag %d)!\n", tag); + break; + } + + mapthings[i].angle = lines[j].frontsector->ceilingheight >> FRACBITS; + mapthings[i].pitch = lines[j].frontsector->floorheight >> FRACBITS; + mapthings[i].args[0] = lines[j].dx >> FRACBITS; + mapthings[i].args[1] = mapthings[i].extrainfo; + mapthings[i].args[3] = lines[j].dy >> FRACBITS; + mapthings[i].args[4] = sides[lines[j].sidenum[0]].textureoffset >> FRACBITS; + mapthings[i].args[7] = -sides[lines[j].sidenum[0]].rowoffset >> FRACBITS; + if (lines[j].backsector) + { + mapthings[i].roll = lines[j].backsector->ceilingheight >> FRACBITS; + mapthings[i].args[2] = sides[lines[j].sidenum[1]].rowoffset >> FRACBITS; + mapthings[i].args[5] = lines[j].backsector->floorheight >> FRACBITS; + mapthings[i].args[6] = sides[lines[j].sidenum[1]].textureoffset >> FRACBITS; + } + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[8] |= TMM_DOUBLESIZE; + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[8] |= TMM_SILENT; + if (lines[j].flags & ML_NOCLIMB) + mapthings[i].args[8] |= TMM_ALLOWYAWCONTROL; + if (lines[j].flags & ML_SKEWTD) + mapthings[i].args[8] |= TMM_SWING; + if (lines[j].flags & ML_NOSKEW) + mapthings[i].args[8] |= TMM_MACELINKS; + if (lines[j].flags & ML_MIDPEG) + mapthings[i].args[8] |= TMM_CENTERLINK; + if (lines[j].flags & ML_MIDSOLID) + mapthings[i].args[8] |= TMM_CLIP; + if (lines[j].flags & ML_WRAPMIDTEX) + mapthings[i].args[8] |= TMM_ALWAYSTHINK; + if (mapthings[i].type == 1110) + { + P_WriteConstant(sides[lines[j].sidenum[0]].toptexture, &mapthings[i].stringargs[0]); + P_WriteConstant(lines[j].backsector ? sides[lines[j].sidenum[1]].toptexture : MT_NULL, &mapthings[i].stringargs[1]); + } + break; + } + case 1101: //Torch + case 1119: //Candle + case 1120: //Candle pricket + mapthings[i].args[0] = !!(mapthings[i].options & MTF_EXTRA); + break; + case 1121: //Flame holder + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[0] |= TMFH_NOFLAME; + if (mapthings[i].options & MTF_EXTRA) + mapthings[i].args[0] |= TMFH_CORONA; + break; + case 1127: //Spectator EggRobo + if (mapthings[i].options & MTF_AMBUSH) + mapthings[i].args[0] = TMED_LEFT; + else if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[0] = TMED_RIGHT; + else + mapthings[i].args[0] = TMED_NONE; + break; + case 1200: //Tumbleweed (Big) + case 1201: //Tumbleweed (Small) + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 1202: //Rock spawner + { + mtag_t tag = (mtag_t)mapthings[i].angle; + INT32 j = Tag_FindLineSpecial(12, tag); + + if (j == -1) + { + CONS_Debug(DBG_GAMELOGIC, "Rock spawner: Unable to find parameter line 12 (tag %d)!\n", tag); + break; + } + mapthings[i].angle = AngleFixed(R_PointToAngle2(lines[j].v2->x, lines[j].v2->y, lines[j].v1->x, lines[j].v1->y)) >> FRACBITS; + mapthings[i].args[0] = P_AproxDistance(lines[j].dx, lines[j].dy) >> FRACBITS; + mapthings[i].args[1] = sides[lines[j].sidenum[0]].textureoffset >> FRACBITS; + mapthings[i].args[2] = !!(lines[j].flags & ML_NOCLIMB); + P_WriteConstant(MT_ROCKCRUMBLE1 + (sides[lines[j].sidenum[0]].rowoffset >> FRACBITS), &mapthings[i].stringargs[0]); + break; + } + case 1221: //Minecart saloon door + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 1229: //Minecart switch point + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 1300: //Flame jet (horizontal) + case 1301: //Flame jet (vertical) + mapthings[i].args[0] = (mapthings[i].angle >> 13)*TICRATE/2; + mapthings[i].args[1] = ((mapthings[i].angle >> 10) & 7)*TICRATE/2; + mapthings[i].args[2] = 80 - 5*mapthings[i].extrainfo; + mapthings[i].args[3] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 1304: //Lavafall + mapthings[i].args[0] = mapthings[i].angle; + mapthings[i].args[1] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 1305: //Rollout Rock + mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 1500: //Glaregoyle + case 1501: //Glaregoyle (Up) + case 1502: //Glaregoyle (Down) + case 1503: //Glaregoyle (Long) + if (mapthings[i].angle >= 360) + mapthings[i].args[1] = 7*(mapthings[i].angle/360) + 1; + break; + case 1700: //Axis + mapthings[i].args[2] = mapthings[i].angle & 16383; + mapthings[i].args[3] = !!(mapthings[i].angle & 16384); + /* FALLTHRU */ + case 1701: //Axis transfer + case 1702: //Axis transfer line + mapthings[i].args[0] = mapthings[i].extrainfo; + mapthings[i].args[1] = mapthings[i].options; + break; + case 1703: //Ideya drone + mapthings[i].args[0] = mapthings[i].angle & 0xFFF; + mapthings[i].args[1] = mapthings[i].extrainfo*32; + mapthings[i].args[2] = ((mapthings[i].angle & 0xF000) >> 12)*32; + if ((mapthings[i].options & (MTF_OBJECTSPECIAL|MTF_EXTRA)) == (MTF_OBJECTSPECIAL|MTF_EXTRA)) + mapthings[i].args[3] = TMDA_BOTTOM; + else if ((mapthings[i].options & (MTF_OBJECTSPECIAL|MTF_EXTRA)) == MTF_OBJECTSPECIAL) + mapthings[i].args[3] = TMDA_TOP; + else if ((mapthings[i].options & (MTF_OBJECTSPECIAL|MTF_EXTRA)) == MTF_EXTRA) + mapthings[i].args[3] = TMDA_MIDDLE; + else + mapthings[i].args[3] = TMDA_BOTTOMOFFSET; + mapthings[i].args[4] = !!(mapthings[i].options & MTF_AMBUSH); + break; + case 1704: //NiGHTS bumper + mapthings[i].pitch = 30 * (((mapthings[i].options & 15) + 9) % 12); + mapthings[i].options &= ~0xF; + break; + case 1705: //Hoop + case 1713: //Hoop (Customizable) + { + UINT16 oldangle = mapthings[i].angle; + mapthings[i].angle = ((oldangle >> 8)*360)/256; + mapthings[i].pitch = ((oldangle & 255)*360)/256; + mapthings[i].args[0] = (mapthings[i].type == 1705) ? 96 : (mapthings[i].options & 0xF)*16 + 32; + mapthings[i].options &= ~0xF; + mapthings[i].type = 1713; + break; + } + case 1710: //Ideya capture + mapthings[i].args[0] = mapthings[i].extrainfo; + mapthings[i].args[1] = mapthings[i].angle; + break; + case 1714: //Ideya anchor point + mapthings[i].args[0] = mapthings[i].extrainfo; + break; + case 1806: //King Bowser + mapthings[i].args[0] = LE_KOOPA; + break; + case 1807: //Axe + mapthings[i].args[0] = LE_AXE; + break; + case 2000: //Smashing spikeball + mapthings[i].args[0] = mapthings[i].angle; + break; + case 2006: //Jack-o'-lantern 1 + case 2007: //Jack-o'-lantern 2 + case 2008: //Jack-o'-lantern 3 + mapthings[i].args[0] = !!(mapthings[i].options & MTF_EXTRA); break; default: break; @@ -3211,6 +6554,52 @@ static void P_ConvertBinaryMap(void) } } +static void P_ConvertBinaryLinedefFlags(void) +{ + size_t i; + + for (i = 0; i < numlines; i++) + { + if (!!(lines[i].flags & ML_DONTPEGBOTTOM) ^ !!(lines[i].flags & ML_MIDPEG)) + lines[i].flags |= ML_MIDPEG; + else + lines[i].flags &= ~ML_MIDPEG; + + if (lines[i].special >= 100 && lines[i].special < 300) + { + if (lines[i].flags & ML_DONTPEGTOP) + lines[i].flags |= ML_SKEWTD; + else + lines[i].flags &= ~ML_SKEWTD; + + if ((lines[i].flags & ML_TFERLINE) && lines[i].frontsector) + { + size_t j; + + for (j = 0; j < lines[i].frontsector->linecount; j++) + { + if (lines[i].frontsector->lines[j]->flags & ML_DONTPEGTOP) + lines[i].frontsector->lines[j]->flags |= ML_SKEWTD; + else + lines[i].frontsector->lines[j]->flags &= ~ML_SKEWTD; + } + } + } + + } +} + +//For maps in binary format, converts setup of specials to UDMF format. +static void P_ConvertBinaryMap(void) +{ + P_ConvertBinaryLinedefTypes(); + P_ConvertBinarySectorTypes(); + P_ConvertBinaryThingTypes(); + P_ConvertBinaryLinedefFlags(); + if (M_CheckParm("-writetextmap")) + P_WriteTextmap(); +} + /** Compute MD5 message digest for bytes read from memory source * * The resulting message digest number will be written into the 16 bytes @@ -3287,6 +6676,9 @@ static boolean P_LoadMapFromFile(void) P_LinkMapData(); + if (!udmf) + P_AddBinaryMapTags(); + Taglist_InitGlobalTables(); if (!udmf) @@ -3394,8 +6786,10 @@ static void P_InitLevelSettings(void) numstarposts = 0; ssspheres = timeinmap = 0; - // special stage - stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial + // Assume Special Stages were failed in unless proven otherwise - via P_GiveEmerald or emerald touchspecial + // Normal stages will default to be OK, until a Lua script / linedef executor says otherwise. + stagefailed = G_IsSpecialStage(gamemap); + // Reset temporary record data memset(&ntemprecords, 0, sizeof(nightsdata_t)); @@ -4135,7 +7529,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) #ifdef HWRENDER // Free GPU textures before freeing patches. - if (vid.glstate == VID_GL_LIBRARY_LOADED) + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) HWR_ClearAllTextures(); #endif @@ -4160,7 +7554,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // internal game map maplumpname = G_BuildMapName(gamemap); - lastloadedmaplumpnum = W_CheckNumForName(maplumpname); + lastloadedmaplumpnum = W_CheckNumForMap(maplumpname); if (lastloadedmaplumpnum == LUMPERROR) I_Error("Map %s not found.\n", maplumpname); @@ -4174,7 +7568,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_ResetWaypoints(); - P_MapStart(); + P_MapStart(); // tmthing can be used starting from this point + + P_InitSlopes(); if (!P_LoadMapFromFile()) return false; @@ -4227,8 +7623,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // clear special respawning que iquehead = iquetail = 0; - P_MapEnd(); - // Remove the loading shit from the screen if (rendermode != render_none && !(titlemapinaction || reloadinggamestate)) F_WipeColorFill(levelfadecol); @@ -4248,6 +7642,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_RunCachedActions(); + P_MapEnd(); // tmthing is no longer needed from this point onwards + // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... if (!titlemapinaction) { @@ -4271,7 +7667,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); } P_PreTicker(2); - LUAh_MapLoad(); + P_MapStart(); // just in case MapLoad modifies tmthing + LUA_HookInt(gamemap, HOOK(MapLoad)); + P_MapEnd(); // just in case MapLoad modifies tmthing } // No render mode or reloading gamestate, stop here. @@ -4385,10 +7783,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; @@ -4409,18 +7806,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++) @@ -4500,7 +7889,7 @@ boolean P_AddWadFile(const char *wadfilename) #ifdef HWRENDER // Free GPU textures before freeing patches. - if (vid.glstate == VID_GL_LIBRARY_LOADED) + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) HWR_ClearAllTextures(); #endif @@ -4514,7 +7903,7 @@ boolean P_AddWadFile(const char *wadfilename) // Reload it all anyway, just in case they // added some textures but didn't insert a // TEXTURES/etc. list. - R_LoadTextures(); // numtexture changes + R_LoadTexturesPwad(wadnum); // numtexture changes // Reload ANIMDEFS P_InitPicAnims(); @@ -4527,8 +7916,8 @@ boolean P_AddWadFile(const char *wadfilename) // // look for skins // - R_AddSkins(wadnum); // faB: wadfile index in wadfiles[] - R_PatchSkins(wadnum); // toast: PATCH PATCH + R_AddSkins(wadnum, false); // faB: wadfile index in wadfiles[] + R_PatchSkins(wadnum, false); // toast: PATCH PATCH ST_ReloadSkinFaceGraphics(); // @@ -4584,3 +7973,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 34de9c93d..36d19f66d 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -80,6 +80,7 @@ typedef struct UINT8 *picture; #ifdef HWRENDER void *mipmap; + void *mippic; #endif } levelflat_t; @@ -102,10 +103,11 @@ 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); -void P_WriteThings(void); +//void P_WriteThings(void); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); @@ -120,5 +122,6 @@ void P_AddGradesForMare(INT16 i, UINT8 mare, char *gtext); UINT8 P_GetGrade(UINT32 pscore, INT16 map, UINT8 mare); UINT8 P_HasGrades(INT16 map, UINT8 mare); UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade); +UINT32 P_GetScoreForGradeOverall(INT16 map, UINT8 grade); #endif diff --git a/src/p_sight.c b/src/p_sight.c index 2e1e49997..1aa231a6c 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -307,7 +307,7 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) for (rover = front->ffloors; rover; rover = rover->next) { if (!(rover->flags & FF_EXISTS) - || !(rover->flags & FF_RENDERSIDES) || rover->flags & FF_TRANSLUCENT) + || !(rover->flags & FF_RENDERSIDES) || (rover->flags & (FF_TRANSLUCENT|FF_FOG))) { continue; } @@ -323,7 +323,7 @@ static boolean P_CrossSubsector(size_t num, register los_t *los) for (rover = back->ffloors; rover; rover = rover->next) { if (!(rover->flags & FF_EXISTS) - || !(rover->flags & FF_RENDERSIDES) || rover->flags & FF_TRANSLUCENT) + || !(rover->flags & FF_RENDERSIDES) || (rover->flags & (FF_TRANSLUCENT|FF_FOG))) { continue; } @@ -452,7 +452,7 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) /// \todo Improve by checking fog density/translucency /// and setting a sight limit. if (!(rover->flags & FF_EXISTS) - || !(rover->flags & FF_RENDERPLANES) || rover->flags & FF_TRANSLUCENT) + || !(rover->flags & FF_RENDERPLANES) || (rover->flags & (FF_TRANSLUCENT|FF_FOG))) { continue; } diff --git a/src/p_slopes.c b/src/p_slopes.c index aa46a8402..7fa51452e 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2004 by Stephen McGranahan -// Copyright (C) 2015-2020 by Sonic Team Junior. +// Copyright (C) 2015-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -90,8 +90,38 @@ 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) +void T_DynamicSlopeLine (dynlineplanethink_t* th) { pslope_t* slope = th->slope; line_t* srcline = th->sourceline; @@ -131,47 +161,56 @@ void T_DynamicSlopeLine (dynplanethink_t* th) } /// Mapthing-defined -void T_DynamicSlopeVert (dynplanethink_t* th) +void T_DynamicSlopeVert (dynvertexplanethink_t* th) { - pslope_t* slope = th->slope; - size_t i; - INT32 l; - for (i = 0; i < 3; i++) { - l = Tag_FindLineSpecial(799, th->tags[i]); - if (l != -1) { - th->vex[i].z = lines[l].frontsector->floorheight; - } + for (i = 0; i < 3; i++) + { + if (th->relative & (1 << i)) + th->vex[i].z = th->origvecheights[i] + (th->secs[i]->floorheight - th->origsecheights[i]); else - th->vex[i].z = 0; + th->vex[i].z = th->secs[i]->floorheight; } - ReconfigureViaVertexes(slope, th->vex[0], th->vex[1], th->vex[2]); + ReconfigureViaVertexes(th->slope, th->vex[0], th->vex[1], th->vex[2]); } -static inline void P_AddDynSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent, const INT16 tags[3], const vector3_t vx[3]) +static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent) { - dynplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL); - switch (type) - { - case DP_VERTEX: - th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeVert; - memcpy(th->tags, tags, sizeof(th->tags)); - memcpy(th->vex, vx, sizeof(th->vex)); - break; - default: - th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeLine; - th->sourceline = sourceline; - th->extent = extent; - } - + dynlineplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL); + th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeLine; th->slope = slope; th->type = type; - + th->sourceline = sourceline; + th->extent = extent; P_AddThinker(THINK_DYNSLOPE, &th->thinker); } +static inline void P_AddDynVertexSlopeThinker (pslope_t* slope, const INT16 tags[3], const vector3_t vx[3]) +{ + dynvertexplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL); + size_t i; + INT32 l; + th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeVert; + th->slope = slope; + + for (i = 0; i < 3; i++) { + l = Tag_FindLineSpecial(799, tags[i]); + if (l == -1) + { + Z_Free(th); + return; + } + th->secs[i] = lines[l].frontsector; + th->vex[i] = vx[i]; + th->origsecheights[i] = lines[l].frontsector->floorheight; + th->origvecheights[i] = vx[i].z; + if (lines[l].args[0]) + th->relative |= 1<thinker); +} /// Create a new slope and add it to the slope list. static inline pslope_t* Slope_Add (const UINT8 flags) @@ -238,6 +277,27 @@ static fixed_t GetExtent(sector_t *sector, line_t *line) return fardist; } +static boolean P_CopySlope(pslope_t** toslope, pslope_t* fromslope) +{ + if (*toslope || !fromslope) + return true; + + *toslope = fromslope; + return true; +} + +static void P_UpdateHasSlope(sector_t *sec) +{ + size_t i; + + sec->hasslope = true; + + // if this is an FOF control sector, make sure any target sectors also are marked as having slopes + if (sec->numattached) + for (i = 0; i < sec->numattached; i++) + sectors[sec->attached[i]].hasslope = true; +} + /// Creates one or more slopes based on the given line type and front/back sectors. static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) { @@ -328,7 +388,7 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) P_CalculateSlopeNormal(fslope); if (spawnthinker && (flags & SL_DYNAMIC)) - P_AddDynSlopeThinker(fslope, DP_FRONTFLOOR, line, extent, NULL, NULL); + P_AddDynLineSlopeThinker(fslope, DP_FRONTFLOOR, line, extent); } if(frontceil) { @@ -345,7 +405,7 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) P_CalculateSlopeNormal(cslope); if (spawnthinker && (flags & SL_DYNAMIC)) - P_AddDynSlopeThinker(cslope, DP_FRONTCEIL, line, extent, NULL, NULL); + P_AddDynLineSlopeThinker(cslope, DP_FRONTCEIL, line, extent); } } if(backfloor || backceil) @@ -385,7 +445,7 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) P_CalculateSlopeNormal(fslope); if (spawnthinker && (flags & SL_DYNAMIC)) - P_AddDynSlopeThinker(fslope, DP_BACKFLOOR, line, extent, NULL, NULL); + P_AddDynLineSlopeThinker(fslope, DP_BACKFLOOR, line, extent); } if(backceil) { @@ -402,9 +462,26 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) P_CalculateSlopeNormal(cslope); if (spawnthinker && (flags & SL_DYNAMIC)) - P_AddDynSlopeThinker(cslope, DP_BACKCEIL, line, extent, NULL, NULL); + P_AddDynLineSlopeThinker(cslope, DP_BACKCEIL, line, extent); } } + + if (line->args[2] & TMSL_COPY) + { + if (frontfloor) + P_CopySlope(&line->backsector->f_slope, line->frontsector->f_slope); + if (backfloor) + P_CopySlope(&line->frontsector->f_slope, line->backsector->f_slope); + if (frontceil) + P_CopySlope(&line->backsector->c_slope, line->frontsector->c_slope); + if (backceil) + P_CopySlope(&line->frontsector->c_slope, line->backsector->c_slope); + + if (backfloor || backceil) + P_UpdateHasSlope(line->frontsector); + if (frontfloor || frontceil) + P_UpdateHasSlope(line->backsector); + } } /// Creates a new slope from three mapthings with the specified IDs @@ -439,14 +516,14 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag vx[i].x = mt->x << FRACBITS; vx[i].y = mt->y << FRACBITS; vx[i].z = mt->z << FRACBITS; - if (!mt->extrainfo) + if (!mt->args[0]) vx[i].z += R_PointInSubsector(vx[i].x, vx[i].y)->sector->floorheight; } ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]); if (spawnthinker && (flags & SL_DYNAMIC)) - P_AddDynSlopeThinker(ret, DP_VERTEX, NULL, 0, tags, vx); + P_AddDynVertexSlopeThinker(ret, tags, vx); return ret; } @@ -546,11 +623,10 @@ static boolean P_SetSlopeFromTag(sector_t *sec, INT32 tag, boolean ceiling) { INT32 i; pslope_t **secslope = ceiling ? &sec->c_slope : &sec->f_slope; - TAG_ITER_DECLARECOUNTER(0); if (!tag || *secslope) return false; - TAG_ITER_SECTORS(0, tag, i) + TAG_ITER_SECTORS(tag, i) { pslope_t *srcslope = ceiling ? sectors[i].c_slope : sectors[i].f_slope; if (srcslope) @@ -562,27 +638,6 @@ static boolean P_SetSlopeFromTag(sector_t *sec, INT32 tag, boolean ceiling) return false; } -static boolean P_CopySlope(pslope_t **toslope, pslope_t *fromslope) -{ - if (*toslope || !fromslope) - return true; - - *toslope = fromslope; - return true; -} - -static void P_UpdateHasSlope(sector_t *sec) -{ - size_t i; - - sec->hasslope = true; - - // if this is an FOF control sector, make sure any target sectors also are marked as having slopes - if (sec->numattached) - for (i = 0; i < sec->numattached; i++) - sectors[sec->attached[i]].hasslope = true; -} - // // P_CopySectorSlope // @@ -632,13 +687,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(); @@ -672,6 +734,13 @@ void P_SpawnSlopes(const boolean fromsave) { } } +/// Initializes slopes. +void P_InitSlopes(void) +{ + slopelist = NULL; + slopecount = 0; +} + // ============================================================================ // // Various utilities related to slopes @@ -774,13 +843,13 @@ 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; } //CONS_Printf("Launched off of slope.\n"); mo->standingslope = NULL; - - if (mo->player) - mo->player->powers[pw_justlaunched] = 1; } // diff --git a/src/p_slopes.h b/src/p_slopes.h index 46e8dc1e7..f4b0535e7 100644 --- a/src/p_slopes.h +++ b/src/p_slopes.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2004 by Stephen McGranahan -// Copyright (C) 2015-2020 by Sonic Team Junior. +// Copyright (C) 2015-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -44,12 +44,14 @@ typedef enum typedef enum { TMSL_NOPHYSICS = 1, - TMSL_DYNAMIC = 2, + TMSL_DYNAMIC = 1<<1, + TMSL_COPY = 1<<2, } textmapslopeflags_t; void P_LinkSlopeThinkers (void); void P_CalculateSlopeNormal(pslope_t *slope); +void P_InitSlopes(void); void P_SpawnSlopes(const boolean fromsave); // @@ -86,6 +88,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 { @@ -93,26 +96,29 @@ typedef enum { DP_FRONTCEIL, DP_BACKFLOOR, DP_BACKCEIL, - DP_VERTEX } dynplanetype_t; /// Permit slopes to be dynamically altered through a thinker. typedef struct { thinker_t thinker; - - pslope_t* slope; + pslope_t *slope; dynplanetype_t type; - - // Used by line slopes. - line_t* sourceline; + line_t *sourceline; fixed_t extent; +} dynlineplanethink_t; - // Used by mapthing vertex slopes. - INT16 tags[3]; +typedef struct +{ + thinker_t thinker; + pslope_t *slope; + sector_t *secs[3]; vector3_t vex[3]; -} dynplanethink_t; + fixed_t origsecheights[3]; + fixed_t origvecheights[3]; + UINT8 relative; +} dynvertexplanethink_t; -void T_DynamicSlopeLine (dynplanethink_t* th); -void T_DynamicSlopeVert (dynplanethink_t* th); +void T_DynamicSlopeLine (dynlineplanethink_t* th); +void T_DynamicSlopeVert (dynvertexplanethink_t* th); #endif // #ifndef P_SLOPES_H__ diff --git a/src/p_spec.c b/src/p_spec.c index 00fe3ca0e..78878de1d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -15,6 +15,7 @@ /// utility functions, etc. /// Line Tag handling. Line and Sector triggers. +#include "dehacked.h" #include "doomdef.h" #include "g_game.h" #include "p_local.h" @@ -35,7 +36,7 @@ #include "v_video.h" // V_AUTOFADEOUT|V_ALLOWLOWERCASE #include "m_misc.h" #include "m_cond.h" //unlock triggers -#include "lua_hook.h" // LUAh_LinedefExecute +#include "lua_hook.h" // LUA_HookLinedefExecute #include "f_finale.h" // control text prompt #include "r_skins.h" // skins @@ -50,9 +51,6 @@ mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs -// Amount (dx, dy) vector linedef is shifted right to get scroll amount -#define SCROLL_SHIFT 5 - /** Animated texture descriptor * This keeps track of an animated texture or an animated flat. * \sa P_UpdateSpecials, P_InitPicAnims, animdef_t @@ -100,7 +98,7 @@ typedef struct static void P_SpawnScrollers(void); static void P_SpawnFriction(void); static void P_SpawnPushers(void); -static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *source, INT32 affectee, INT32 referrer, INT32 exclusive, INT32 slider); //SoM: 3/9/2000 +static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, fixed_t z_mag, INT32 affectee, INT32 referrer, INT32 exclusive, INT32 slider); //SoM: 3/9/2000 static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t offset, INT32 line, INT32 sourceline); static void P_ResetFakeFloorFader(ffloor_t *rover, fade_t *data, boolean finalize); #define P_RemoveFakeFloorFader(l) P_ResetFakeFloorFader(l, NULL, false); @@ -117,7 +115,7 @@ static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, ext static void P_AddBlockThinker(sector_t *sec, line_t *sourceline); static void P_AddFloatThinker(sector_t *sec, UINT16 tag, line_t *sourceline); //static void P_AddBridgeThinker(line_t *sourceline, sector_t *sec); -static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinkerlist_t *secthinkers); +static void P_AddFakeFloorsByLine(size_t line, INT32 alpha, UINT8 blendmode, ffloortype_e ffloorflags, thinkerlist_t *secthinkers); static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec); static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer); static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee, UINT8 reverse); @@ -993,30 +991,22 @@ static boolean PolyDoor(line_t *line) { polydoordata_t pdd; - pdd.polyObjNum = Tag_FGet(&line->tags); // polyobject id + pdd.polyObjNum = line->args[0]; // polyobject id switch(line->special) { case 480: // Polyobj_DoorSlide pdd.doorType = POLY_DOOR_SLIDE; - pdd.speed = sides[line->sidenum[0]].textureoffset / 8; + pdd.speed = line->args[1] << (FRACBITS - 3); pdd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); // angle of motion - pdd.distance = sides[line->sidenum[0]].rowoffset; - - if (line->sidenum[1] != 0xffff) - pdd.delay = sides[line->sidenum[1]].textureoffset >> FRACBITS; // delay in tics - else - pdd.delay = 0; + pdd.distance = line->args[2] << FRACBITS; + pdd.delay = line->args[3]; // delay in tics break; case 481: // Polyobj_DoorSwing pdd.doorType = POLY_DOOR_SWING; - pdd.speed = sides[line->sidenum[0]].textureoffset >> FRACBITS; // angular speed - pdd.distance = sides[line->sidenum[0]].rowoffset >> FRACBITS; // angular distance - - if (line->sidenum[1] != 0xffff) - pdd.delay = sides[line->sidenum[1]].textureoffset >> FRACBITS; // delay in tics - else - pdd.delay = 0; + pdd.speed = line->args[1]; // angular speed + pdd.distance = line->args[2]; // angular distance + pdd.delay = line->args[3]; // delay in tics break; default: return 0; // ??? @@ -1025,31 +1015,29 @@ static boolean PolyDoor(line_t *line) return EV_DoPolyDoor(&pdd); } -// Parses arguments for parameterized polyobject move specials +// Parses arguments for parameterized polyobject move special static boolean PolyMove(line_t *line) { polymovedata_t pmd; - pmd.polyObjNum = Tag_FGet(&line->tags); - pmd.speed = sides[line->sidenum[0]].textureoffset / 8; + pmd.polyObjNum = line->args[0]; + pmd.speed = line->args[1] << (FRACBITS - 3); pmd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); - pmd.distance = sides[line->sidenum[0]].rowoffset; + pmd.distance = line->args[2] << FRACBITS; - pmd.overRide = (line->special == 483); // Polyobj_OR_Move + pmd.overRide = !!line->args[3]; // Polyobj_OR_Move return EV_DoPolyObjMove(&pmd); } -// Makes a polyobject invisible and intangible -// If NOCLIMB is ticked, the polyobject will still be tangible, just not visible. -static void PolyInvisible(line_t *line) +static void PolySetVisibilityTangibility(line_t *line) { - INT32 polyObjNum = Tag_FGet(&line->tags); - polyobj_t *po; + INT32 polyObjNum = line->args[0]; + polyobj_t* po; if (!(po = Polyobj_GetForNum(polyObjNum))) { - CONS_Debug(DBG_POLYOBJ, "PolyInvisible: bad polyobj %d\n", polyObjNum); + CONS_Debug(DBG_POLYOBJ, "PolySetVisibilityTangibility: bad polyobj %d\n", polyObjNum); return; } @@ -1057,49 +1045,32 @@ static void PolyInvisible(line_t *line) if (po->isBad) return; - if (!(line->flags & ML_NOCLIMB)) - po->flags &= ~POF_SOLID; - - po->flags |= POF_NOSPECIALS; - po->flags &= ~POF_RENDERALL; -} - -// Makes a polyobject visible and tangible -// If NOCLIMB is ticked, the polyobject will not be tangible, just visible. -static void PolyVisible(line_t *line) -{ - INT32 polyObjNum = Tag_FGet(&line->tags); - polyobj_t *po; - - if (!(po = Polyobj_GetForNum(polyObjNum))) + if (line->args[1] == TMPV_VISIBLE) { - CONS_Debug(DBG_POLYOBJ, "PolyVisible: bad polyobj %d\n", polyObjNum); - return; + po->flags &= ~POF_NOSPECIALS; + po->flags |= (po->spawnflags & POF_RENDERALL); + } + else if (line->args[1] == TMPV_INVISIBLE) + { + po->flags |= POF_NOSPECIALS; + po->flags &= ~POF_RENDERALL; } - // don't allow line actions to affect bad polyobjects - if (po->isBad) - return; - - if (!(line->flags & ML_NOCLIMB)) + if (line->args[2] == TMPT_TANGIBLE) po->flags |= POF_SOLID; - - po->flags &= ~POF_NOSPECIALS; - po->flags |= (po->spawnflags & POF_RENDERALL); + else if (line->args[2] == TMPT_INTANGIBLE) + po->flags &= ~POF_SOLID; } - // Sets the translucency of a polyobject -// Frontsector floor / 100 = translevel static void PolyTranslucency(line_t *line) { - INT32 polyObjNum = Tag_FGet(&line->tags); + INT32 polyObjNum = line->args[0]; polyobj_t *po; - INT32 value; if (!(po = Polyobj_GetForNum(polyObjNum))) { - CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjWaypoint: bad polyobj %d\n", polyObjNum); + CONS_Debug(DBG_POLYOBJ, "PolyTranslucency: bad polyobj %d\n", polyObjNum); return; } @@ -1107,17 +1078,10 @@ static void PolyTranslucency(line_t *line) if (po->isBad) return; - // If Front X Offset is specified, use that. Else, use floorheight. - value = (sides[line->sidenum[0]].textureoffset ? sides[line->sidenum[0]].textureoffset : line->frontsector->floorheight) >> FRACBITS; - - // If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000. - if (!(line->flags & ML_DONTPEGBOTTOM)) - value /= 100; - - if (line->flags & ML_EFFECT3) // relative calc - po->translucency += value; + if (lines->args[2]) // relative calc + po->translucency += line->args[1]; else - po->translucency = value; + po->translucency = line->args[1]; po->translucency = max(min(po->translucency, NUMTRANSMAPS), 0); } @@ -1125,10 +1089,9 @@ static void PolyTranslucency(line_t *line) // Makes a polyobject translucency fade and applies tangibility static boolean PolyFade(line_t *line) { - INT32 polyObjNum = Tag_FGet(&line->tags); + INT32 polyObjNum = line->args[0]; polyobj_t *po; polyfadedata_t pfd; - INT32 value; if (!(po = Polyobj_GetForNum(polyObjNum))) { @@ -1141,7 +1104,7 @@ static boolean PolyFade(line_t *line) return 0; // Prevent continuous execs from interfering on an existing fade - if (!(line->flags & ML_EFFECT5) + if (!(line->args[3] & TMPF_OVERRIDE) && po->thinker && po->thinker->function.acp1 == (actionf_p1)T_PolyObjFade) { @@ -1151,17 +1114,10 @@ static boolean PolyFade(line_t *line) pfd.polyObjNum = polyObjNum; - // If Front X Offset is specified, use that. Else, use floorheight. - value = (sides[line->sidenum[0]].textureoffset ? sides[line->sidenum[0]].textureoffset : line->frontsector->floorheight) >> FRACBITS; - - // If DONTPEGBOTTOM, specify raw translucency value. Else, take it out of 1000. - if (!(line->flags & ML_DONTPEGBOTTOM)) - value /= 100; - - if (line->flags & ML_EFFECT3) // relative calc - pfd.destvalue = po->translucency + value; + if (line->args[3] & TMPF_RELATIVE) // relative calc + pfd.destvalue = po->translucency + line->args[1]; else - pfd.destvalue = value; + pfd.destvalue = line->args[1]; pfd.destvalue = max(min(pfd.destvalue, NUMTRANSMAPS), 0); @@ -1169,15 +1125,11 @@ static boolean PolyFade(line_t *line) if (po->translucency == pfd.destvalue) return 1; - pfd.docollision = !(line->flags & ML_BOUNCY); // do not handle collision flags - pfd.doghostfade = (line->flags & ML_EFFECT1); // do ghost fade (no collision flags during fade) - pfd.ticbased = (line->flags & ML_EFFECT4); // Speed = Tic Duration - - // allow Back Y Offset to be consistent with other fade specials - pfd.speed = (line->sidenum[1] != 0xFFFF && !sides[line->sidenum[0]].rowoffset) ? - abs(sides[line->sidenum[1]].rowoffset>>FRACBITS) - : abs(sides[line->sidenum[0]].rowoffset>>FRACBITS); + pfd.docollision = !(line->args[3] & TMPF_IGNORECOLLISION); // do not handle collision flags + pfd.doghostfade = (line->args[3] & TMPF_GHOSTFADE); // do ghost fade (no collision flags during fade) + pfd.ticbased = (line->args[3] & TMPF_TICBASED); // Speed = Tic Duration + pfd.speed = line->args[2]; return EV_DoPolyObjFade(&pfd); } @@ -1187,49 +1139,25 @@ static boolean PolyWaypoint(line_t *line) { polywaypointdata_t pwd; - pwd.polyObjNum = Tag_FGet(&line->tags); - pwd.speed = sides[line->sidenum[0]].textureoffset / 8; - pwd.sequence = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Sequence # - - // Behavior after reaching the last waypoint? - if (line->flags & ML_EFFECT3) - pwd.returnbehavior = PWR_WRAP; // Wrap back to first waypoint - else if (line->flags & ML_EFFECT2) - pwd.returnbehavior = PWR_COMEBACK; // Go through sequence in reverse - else - pwd.returnbehavior = PWR_STOP; // Stop - - // Flags - pwd.flags = 0; - if (line->flags & ML_EFFECT1) - pwd.flags |= PWF_REVERSE; - if (line->flags & ML_EFFECT4) - pwd.flags |= PWF_LOOP; + pwd.polyObjNum = line->args[0]; + pwd.speed = line->args[1] << (FRACBITS - 3); + pwd.sequence = line->args[2]; + pwd.returnbehavior = line->args[3]; + pwd.flags = line->args[4]; return EV_DoPolyObjWaypoint(&pwd); } -// Parses arguments for parameterized polyobject rotate specials +// Parses arguments for parameterized polyobject rotate special static boolean PolyRotate(line_t *line) { polyrotdata_t prd; - prd.polyObjNum = Tag_FGet(&line->tags); - prd.speed = sides[line->sidenum[0]].textureoffset >> FRACBITS; // angular speed - prd.distance = sides[line->sidenum[0]].rowoffset >> FRACBITS; // angular distance - - // Polyobj_(OR_)RotateRight have dir == -1 - prd.direction = (line->special == 484 || line->special == 485) ? -1 : 1; - - // Polyobj_OR types have override set to true - prd.overRide = (line->special == 485 || line->special == 487); - - if (line->flags & ML_NOCLIMB) - prd.turnobjs = 0; - else if (line->flags & ML_EFFECT4) - prd.turnobjs = 2; - else - prd.turnobjs = 1; + prd.polyObjNum = line->args[0]; + prd.speed = line->args[1]; // angular speed + prd.distance = abs(line->args[2]); // angular distance + prd.direction = (line->args[2] < 0) ? -1 : 1; + prd.flags = line->args[3]; return EV_DoPolyObjRotate(&prd); } @@ -1239,10 +1167,10 @@ static boolean PolyFlag(line_t *line) { polyflagdata_t pfd; - pfd.polyObjNum = Tag_FGet(&line->tags); - pfd.speed = P_AproxDistance(line->dx, line->dy) >> FRACBITS; - pfd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y) >> ANGLETOFINESHIFT; - pfd.momx = sides[line->sidenum[0]].textureoffset >> FRACBITS; + pfd.polyObjNum = line->args[0]; + pfd.speed = line->args[1]; + pfd.angle = line->angle >> ANGLETOFINESHIFT; + pfd.momx = line->args[2]; return EV_DoPolyObjFlag(&pfd); } @@ -1251,12 +1179,14 @@ static boolean PolyFlag(line_t *line) static boolean PolyDisplace(line_t *line) { polydisplacedata_t pdd; + fixed_t length = R_PointToDist2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); + fixed_t speed = line->args[1] << FRACBITS; - pdd.polyObjNum = Tag_FGet(&line->tags); + pdd.polyObjNum = line->args[0]; pdd.controlSector = line->frontsector; - pdd.dx = line->dx>>8; - pdd.dy = line->dy>>8; + pdd.dx = FixedMul(FixedDiv(line->dx, length), speed) >> 8; + pdd.dy = FixedMul(FixedDiv(line->dy, length), speed) >> 8; return EV_DoPolyObjDisplace(&pdd); } @@ -1268,22 +1198,16 @@ static boolean PolyRotDisplace(line_t *line) polyrotdisplacedata_t pdd; fixed_t anginter, distinter; - pdd.polyObjNum = Tag_FGet(&line->tags); + pdd.polyObjNum = line->args[0]; pdd.controlSector = line->frontsector; // Rotate 'anginter' interval for each 'distinter' interval from the control sector. - // Use default values if not provided as fallback. - anginter = sides[line->sidenum[0]].rowoffset ? sides[line->sidenum[0]].rowoffset : 90*FRACUNIT; - distinter = sides[line->sidenum[0]].textureoffset ? sides[line->sidenum[0]].textureoffset : 128*FRACUNIT; + anginter = line->args[2] << FRACBITS; + distinter = line->args[1] << FRACBITS; pdd.rotscale = FixedDiv(anginter, distinter); // Same behavior as other rotators when carrying things. - if (line->flags & ML_NOCLIMB) - pdd.turnobjs = 0; - else if (line->flags & ML_EFFECT4) - pdd.turnobjs = 2; - else - pdd.turnobjs = 1; + pdd.turnobjs = line->args[3]; return EV_DoPolyObjRotDisplace(&pdd); } @@ -1298,7 +1222,7 @@ void P_RunNightserizeExecutors(mobj_t *actor) for (i = 0; i < numlines; i++) { - if (lines[i].special == 323 || lines[i].special == 324) + if (lines[i].special == 323) P_RunTriggerLinedef(&lines[i], actor, NULL); } } @@ -1312,7 +1236,7 @@ void P_RunDeNightserizeExecutors(mobj_t *actor) for (i = 0; i < numlines; i++) { - if (lines[i].special == 325 || lines[i].special == 326) + if (lines[i].special == 325) P_RunTriggerLinedef(&lines[i], actor, NULL); } } @@ -1326,7 +1250,7 @@ void P_RunNightsLapExecutors(mobj_t *actor) for (i = 0; i < numlines; i++) { - if (lines[i].special == 327 || lines[i].special == 328) + if (lines[i].special == 327) P_RunTriggerLinedef(&lines[i], actor, NULL); } } @@ -1340,13 +1264,19 @@ void P_RunNightsCapsuleTouchExecutors(mobj_t *actor, boolean entering, boolean e for (i = 0; i < numlines; i++) { - if ((lines[i].special == 329 || lines[i].special == 330) - && ((entering && (lines[i].flags & ML_TFERLINE)) - || (!entering && !(lines[i].flags & ML_TFERLINE))) - && ((lines[i].flags & ML_DONTPEGTOP) - || (enoughspheres && !(lines[i].flags & ML_BOUNCY)) - || (!enoughspheres && (lines[i].flags & ML_BOUNCY)))) - P_RunTriggerLinedef(&lines[i], actor, NULL); + if (lines[i].special != 329) + continue; + + if (!!(lines[i].args[7] & TMI_ENTER) != entering) + continue; + + if (lines[i].args[6] == TMS_IFENOUGH && !enoughspheres) + continue; + + if (lines[i].args[6] == TMS_IFNOTENOUGH && enoughspheres) + continue; + + P_RunTriggerLinedef(&lines[i], actor, NULL); } } @@ -1426,27 +1356,42 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) INT16 specialtype = triggerline->special; size_t i; - UINT8 inputmare = max(0, min(255, sides[triggerline->sidenum[0]].textureoffset>>FRACBITS)); - UINT8 inputlap = max(0, min(255, sides[triggerline->sidenum[0]].rowoffset>>FRACBITS)); + UINT8 inputmare = max(0, min(255, triggerline->args[1])); + UINT8 inputlap = max(0, min(255, triggerline->args[2])); - boolean ltemare = triggerline->flags & ML_NOCLIMB; - boolean gtemare = triggerline->flags & ML_BLOCKMONSTERS; - boolean ltelap = triggerline->flags & ML_EFFECT1; - boolean gtelap = triggerline->flags & ML_EFFECT2; + textmapcomparison_t marecomp = triggerline->args[3]; + textmapcomparison_t lapcomp = triggerline->args[4]; + textmapnightsplayer_t checkplayer = triggerline->args[5]; - boolean lapfrombonustime = triggerline->flags & ML_EFFECT3; - boolean perglobalinverse = triggerline->flags & ML_DONTPEGBOTTOM; - boolean perglobal = !(triggerline->flags & ML_EFFECT4) && !perglobalinverse; + boolean lapfrombonustime; - boolean donomares = triggerline->flags & ML_BOUNCY; // nightserize: run at end of level (no mares) - boolean fromnonights = triggerline->flags & ML_TFERLINE; // nightserize: from non-nights // denightserize: all players no nights - boolean fromnights = triggerline->flags & ML_DONTPEGTOP; // nightserize: from nights // denightserize: >0 players are nights + boolean donomares = (specialtype == 323) && (triggerline->args[7] & TMN_LEVELCOMPLETION); // nightserize: run at end of level (no mares) UINT8 currentmare = UINT8_MAX; UINT8 currentlap = UINT8_MAX; + // Set lapfrombonustime + switch (specialtype) + { + case 323: + lapfrombonustime = !!(triggerline->args[7] & TMN_BONUSLAPS); + break; + case 325: + lapfrombonustime = !!(triggerline->args[7]); + break; + case 327: + lapfrombonustime = !!(triggerline->args[6]); + break; + case 329: + lapfrombonustime = !!(triggerline->args[7] & TMI_BONUSLAPS); + break; + default: + lapfrombonustime = false; + break; + } + // Do early returns for Nightserize - if (specialtype >= 323 && specialtype <= 324) + if (specialtype == 323) { // run only when no mares are found if (donomares && P_FindLowestMare() != UINT8_MAX) @@ -1457,7 +1402,7 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) return false; // run only if player is nightserizing from non-nights - if (fromnonights) + if (triggerline->args[6] == TMN_FROMNONIGHTS) { if (!actor->player) return false; @@ -1465,7 +1410,7 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) return false; } // run only if player is nightserizing from nights - else if (fromnights) + else if (triggerline->args[6] == TMN_FROMNIGHTS) { if (!actor->player) return false; @@ -1475,8 +1420,8 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) } // Get current mare and lap (and check early return for DeNightserize) - if (perglobal || perglobalinverse - || (specialtype >= 325 && specialtype <= 326 && (fromnonights || fromnights))) + if (checkplayer != TMNP_TRIGGERER + || (specialtype == 325 && triggerline->args[6] != TMD_ALWAYS)) { UINT8 playersarenights = 0; @@ -1487,19 +1432,19 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) continue; // denightserize: run only if all players are not nights - if (specialtype >= 325 && specialtype <= 326 && fromnonights + if (specialtype == 325 && triggerline->args[6] == TMD_NOBODYNIGHTS && players[i].powers[pw_carry] == CR_NIGHTSMODE) return false; // count number of nights players for denightserize return - if (specialtype >= 325 && specialtype <= 326 && fromnights + if (specialtype == 325 && triggerline->args[6] == TMD_SOMEBODYNIGHTS && players[i].powers[pw_carry] == CR_NIGHTSMODE) playersarenights++; lap = lapfrombonustime ? players[i].marebonuslap : players[i].marelap; // get highest mare/lap of players - if (perglobal) + if (checkplayer == TMNP_FASTEST) { if (players[i].mare > currentmare || currentmare == UINT8_MAX) { @@ -1511,7 +1456,7 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) currentlap = lap; } // get lowest mare/lap of players - else if (perglobalinverse) + else if (checkplayer == TMNP_SLOWEST) { if (players[i].mare < currentmare || currentmare == UINT8_MAX) { @@ -1525,12 +1470,12 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) } // denightserize: run only if >0 players are nights - if (specialtype >= 325 && specialtype <= 326 && fromnights + if (specialtype == 325 && triggerline->args[6] == TMD_SOMEBODYNIGHTS && playersarenights < 1) return false; } // get current mare/lap from triggering player - else if (!perglobal && !perglobalinverse) + else if (checkplayer == TMNP_TRIGGERER) { if (!actor->player) return false; @@ -1542,280 +1487,170 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor) return false; // special case: player->marebonuslap is 0 until passing through on bonus time. Don't trigger lines looking for inputlap 0. // Compare current mare/lap to input mare/lap based on rules - if (!(specialtype >= 323 && specialtype <= 324 && donomares) // don't return false if donomares and we got this far - && ((ltemare && currentmare > inputmare) - || (gtemare && currentmare < inputmare) - || (!ltemare && !gtemare && currentmare != inputmare) - || (ltelap && currentlap > inputlap) - || (gtelap && currentlap < inputlap) - || (!ltelap && !gtelap && currentlap != inputlap)) + if (!donomares // don't return false if donomares and we got this far + && ((marecomp == TMC_LTE && currentmare > inputmare) + || (marecomp == TMC_GTE && currentmare < inputmare) + || (marecomp == TMC_EQUAL && currentmare != inputmare) + || (lapcomp == TMC_LTE && currentlap > inputlap) + || (lapcomp == TMC_GTE && currentlap < inputlap) + || (lapcomp == TMC_EQUAL && currentlap != inputlap)) ) return false; return true; } -/** Used by P_LinedefExecute to check a trigger linedef's conditions - * The linedef executor specials in the trigger linedef's sector are run if all conditions are met. - * Return false cancels P_LinedefExecute, this happens if a condition is not met. - * - * \param triggerline Trigger linedef to check conditions for; should NEVER be NULL. - * \param actor Object initiating the action; should not be NULL. - * \param caller Sector in which the action was started. May be NULL. - * \sa P_ProcessLineSpecial, P_LinedefExecute - */ -boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller) +static boolean P_CheckPlayerMareOld(line_t *triggerline) { - sector_t *ctlsector; - fixed_t dist = P_AproxDistance(triggerline->dx, triggerline->dy)>>FRACBITS; - size_t i, linecnt, sectori; - INT16 specialtype = triggerline->special; + UINT8 mare; + INT32 targetmare = P_AproxDistance(triggerline->dx, triggerline->dy) >> FRACBITS; - ///////////////////////////////////////////////// - // Distance-checking/sector trigger conditions // - ///////////////////////////////////////////////// + if (!(maptol & TOL_NIGHTS)) + return false; - // Linetypes 303 and 304 require a specific - // number, or minimum or maximum, of rings. - if (specialtype == 303 || specialtype == 304) + mare = P_FindLowestMare(); + + if (triggerline->flags & ML_NOCLIMB) + return mare <= targetmare; + + if (triggerline->flags & ML_BLOCKMONSTERS) + return mare >= targetmare; + + return mare == targetmare; +} + +static boolean P_CheckPlayerMare(line_t *triggerline) +{ + UINT8 mare; + INT32 targetmare = triggerline->args[1]; + + if (!(maptol & TOL_NIGHTS)) + return false; + + mare = P_FindLowestMare(); + + switch (triggerline->args[2]) { - fixed_t rings = 0; - - // With the passuse flag, count all player's - // rings. - if (triggerline->flags & ML_EFFECT4) - { - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i] || players[i].spectator) - continue; - - if (!players[i].mo || ((maptol & TOL_NIGHTS) ? players[i].spheres : players[i].rings) <= 0) - continue; - - rings += (maptol & TOL_NIGHTS) ? players[i].spheres : players[i].rings; - } - } - else - { - if (!(actor && actor->player)) - return false; // no player to count rings from here, sorry - - rings = (maptol & TOL_NIGHTS) ? actor->player->spheres : actor->player->rings; - } - - if (triggerline->flags & ML_NOCLIMB) - { - if (rings > dist) - return false; - } - else if (triggerline->flags & ML_BLOCKMONSTERS) - { - if (rings < dist) - return false; - } - else - { - if (rings != dist) - return false; - } - } - else if (specialtype >= 314 && specialtype <= 315) - { - msecnode_t *node; - mobj_t *mo; - INT32 numpush = 0; - INT32 numneeded = dist; - - if (!caller) - return false; // we need a calling sector to find pushables in, silly! - - // Count the pushables in this sector - node = caller->touching_thinglist; // things touching this sector - while (node) - { - mo = node->m_thing; - if ((mo->flags & MF_PUSHABLE) || ((mo->info->flags & MF_PUSHABLE) && mo->fuse)) - numpush++; - node = node->m_thinglist_next; - } - - if (triggerline->flags & ML_NOCLIMB) // Need at least or more - { - if (numpush < numneeded) - return false; - } - else if (triggerline->flags & ML_EFFECT4) // Need less than - { - if (numpush >= numneeded) - return false; - } - else // Need exact - { - if (numpush != numneeded) - return false; - } - } - else if (caller) - { - if (GETSECSPECIAL(caller->special, 2) == 6) - { - if (!(ALL7EMERALDS(emeralds))) - return false; - } - else if (GETSECSPECIAL(caller->special, 2) == 7) - { - UINT8 mare; - - if (!(maptol & TOL_NIGHTS)) - return false; - - mare = P_FindLowestMare(); - - if (triggerline->flags & ML_NOCLIMB) - { - if (!(mare <= dist)) - return false; - } - else if (triggerline->flags & ML_BLOCKMONSTERS) - { - if (!(mare >= dist)) - return false; - } - else - { - if (!(mare == dist)) - return false; - } - } - // If we were not triggered by a sector type especially for the purpose, - // a Linedef Executor linedef trigger is not handling sector triggers properly, return. - - else if ((!GETSECSPECIAL(caller->special, 2) || GETSECSPECIAL(caller->special, 2) > 7) && (specialtype > 322)) - { - CONS_Alert(CONS_WARNING, - M_GetText("Linedef executor trigger isn't handling sector triggers properly!\nspecialtype = %d, if you are not a dev, report this warning instance\nalong with the wad that caused it!\n"), - specialtype); - return false; - } - } - - ////////////////////////////////////// - // Miscellaneous trigger conditions // - ////////////////////////////////////// - - switch (specialtype) - { - case 305: // continuous - case 306: // each time - case 307: // once - if (!(actor && actor->player && actor->player->charability == dist/10)) - return false; - break; - case 309: // continuous - case 310: // each time - // Only red team members can activate this. - if (!(actor && actor->player && actor->player->ctfteam == 1)) - return false; - break; - case 311: // continuous - case 312: // each time - // Only blue team members can activate this. - if (!(actor && actor->player && actor->player->ctfteam == 2)) - return false; - break; - case 317: // continuous - case 318: // once - { // Unlockable triggers required - INT32 trigid = (INT32)(sides[triggerline->sidenum[0]].textureoffset>>FRACBITS); - - if ((modifiedgame && !savemoddata) || (netgame || multiplayer)) - return false; - else if (trigid < 0 || trigid > 31) // limited by 32 bit variable - { - CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", triggerline->sidenum[0], trigid); - return false; - } - else if (!(unlocktriggers & (1 << trigid))) - return false; - } - break; - case 319: // continuous - case 320: // once - { // An unlockable itself must be unlocked! - INT32 unlockid = (INT32)(sides[triggerline->sidenum[0]].textureoffset>>FRACBITS); - - if ((modifiedgame && !savemoddata) || (netgame || multiplayer)) - return false; - else if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count - { - CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid); - return false; - } - else if (!(unlockables[unlockid-1].unlocked)) - return false; - } - break; - case 321: // continuous - case 322: // each time - // decrement calls left before triggering - if (triggerline->callcount > 0) - { - if (--triggerline->callcount > 0) - return false; - } - break; - case 323: // nightserize - each time - case 324: // nightserize - once - case 325: // denightserize - each time - case 326: // denightserize - once - case 327: // nights lap - each time - case 328: // nights lap - once - case 329: // nights egg capsule touch - each time - case 330: // nights egg capsule touch - once - if (!P_CheckNightsTriggerLine(triggerline, actor)) - return false; - break; - case 331: // continuous - case 332: // each time - case 333: // once - if (!(actor && actor->player && ((stricmp(triggerline->text, skins[actor->player->skin].name) == 0) ^ ((triggerline->flags & ML_NOCLIMB) == ML_NOCLIMB)))) - return false; - break; - case 334: // object dye - continuous - case 335: // object dye - each time - case 336: // object dye - once - { - INT32 triggercolor = (INT32)sides[triggerline->sidenum[0]].toptexture; - UINT16 color = (actor->player ? actor->player->powers[pw_dye] : actor->color); - boolean invert = (triggerline->flags & ML_NOCLIMB ? true : false); - - if (invert ^ (triggercolor != color)) - return false; - } + case TMC_EQUAL: default: - break; + return mare == targetmare; + case TMC_GTE: + return mare >= targetmare; + case TMC_LTE: + return mare <= targetmare; + } +} + +static boolean P_CheckPlayerRings(line_t *triggerline, mobj_t *actor) +{ + INT32 rings = 0; + INT32 targetrings = triggerline->args[1]; + size_t i; + + // Count all players' rings. + if (triggerline->args[3]) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator) + continue; + + if (!players[i].mo || ((maptol & TOL_NIGHTS) ? players[i].spheres : players[i].rings) <= 0) + continue; + + rings += (maptol & TOL_NIGHTS) ? players[i].spheres : players[i].rings; + } + } + else + { + if (!(actor && actor->player)) + return false; // no player to count rings from here, sorry + + rings = (maptol & TOL_NIGHTS) ? actor->player->spheres : actor->player->rings; } - ///////////////////////////////// - // Processing linedef specials // - ///////////////////////////////// + switch (triggerline->args[2]) + { + case TMC_EQUAL: + default: + return rings == targetrings; + case TMC_GTE: + return rings >= targetrings; + case TMC_LTE: + return rings <= targetrings; + } +} - ctlsector = triggerline->frontsector; - sectori = (size_t)(ctlsector - sectors); - linecnt = ctlsector->linecount; +static boolean P_CheckPushables(line_t *triggerline, sector_t *caller) +{ + msecnode_t *node; + mobj_t *mo; + INT32 numpushables = 0; + INT32 targetpushables = triggerline->args[1]; - if (triggerline->flags & ML_EFFECT5) // disregard order for efficiency + if (!caller) + return false; // we need a calling sector to find pushables in, silly! + + // Count the pushables in this sector + for (node = caller->touching_thinglist; node; node = node->m_thinglist_next) + { + mo = node->m_thing; + if ((mo->flags & MF_PUSHABLE) || ((mo->info->flags & MF_PUSHABLE) && mo->fuse)) + numpushables++; + } + + switch (triggerline->args[2]) + { + case TMC_EQUAL: + default: + return numpushables == targetpushables; + case TMC_GTE: + return numpushables >= targetpushables; + case TMC_LTE: + return numpushables <= targetpushables; + } +} + +static boolean P_CheckEmeralds(INT32 checktype, UINT16 target) +{ + switch (checktype) + { + case TMF_HASALL: + default: + return (emeralds & target) == target; + case TMF_HASANY: + return !!(emeralds & target); + case TMF_HASEXACTLY: + return emeralds == target; + case TMF_DOESNTHAVEALL: + return (emeralds & target) != target; + case TMF_DOESNTHAVEANY: + return !(emeralds & target); + } +} + +static void P_ActivateLinedefExecutor(line_t *line, mobj_t *actor, sector_t *caller) +{ + if (line->special < 400 || line->special >= 500) + return; + + if (line->executordelay) + P_AddExecutorDelay(line, actor, caller); + else + P_ProcessLineSpecial(line, actor, caller); +} + +static boolean P_ActivateLinedefExecutorsInSector(line_t *triggerline, mobj_t *actor, sector_t *caller) +{ + sector_t *ctlsector = triggerline->frontsector; + size_t sectori = (size_t)(ctlsector - sectors); + size_t linecnt = ctlsector->linecount; + size_t i; + + if (!udmf && triggerline->flags & ML_WRAPMIDTEX) // disregard order for efficiency { for (i = 0; i < linecnt; i++) - if (ctlsector->lines[i]->special >= 400 - && ctlsector->lines[i]->special < 500) - { - if (ctlsector->lines[i]->executordelay) - P_AddExecutorDelay(ctlsector->lines[i], actor, caller); - else - P_ProcessLineSpecial(ctlsector->lines[i], actor, caller); - } + P_ActivateLinedefExecutor(ctlsector->lines[i], actor, caller); } else // walk around the sector in a defined order { @@ -1896,39 +1731,178 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller if (i == masterlineindex) break; - if (ctlsector->lines[i]->special >= 400 - && ctlsector->lines[i]->special < 500) - { - if (ctlsector->lines[i]->executordelay) - P_AddExecutorDelay(ctlsector->lines[i], actor, caller); - else - P_ProcessLineSpecial(ctlsector->lines[i], actor, caller); - } + P_ActivateLinedefExecutor(ctlsector->lines[i], actor, caller); } } - // "Trigger on X calls" linedefs reset if noclimb is set - if ((specialtype == 321 || specialtype == 322) && triggerline->flags & ML_NOCLIMB) - triggerline->callcount = sides[triggerline->sidenum[0]].textureoffset>>FRACBITS; + return true; +} + +/** Used by P_LinedefExecute to check a trigger linedef's conditions + * The linedef executor specials in the trigger linedef's sector are run if all conditions are met. + * Return false cancels P_LinedefExecute, this happens if a condition is not met. + * + * \param triggerline Trigger linedef to check conditions for; should NEVER be NULL. + * \param actor Object initiating the action; should not be NULL. + * \param caller Sector in which the action was started. May be NULL. + * \sa P_ProcessLineSpecial, P_LinedefExecute + */ +boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller) +{ + INT16 specialtype = triggerline->special; + + //////////////////////// + // Trigger conditions // + //////////////////////// + + if (caller && !udmf) + { + if (caller->triggerer == TO_PLAYEREMERALDS) + { + CONS_Alert(CONS_WARNING, M_GetText("Deprecated emerald check sector type detected. Please use linedef types 337-339 instead.\n")); + if (!(ALL7EMERALDS(emeralds))) + return false; + } + else if (caller->triggerer == TO_PLAYERNIGHTS) + { + CONS_Alert(CONS_WARNING, M_GetText("Deprecated NiGHTS mare sector type detected. Please use linedef types 340-342 instead.\n")); + if (!P_CheckPlayerMareOld(triggerline)) + return false; + } + } + + switch (specialtype) + { + case 303: + if (!P_CheckPlayerRings(triggerline, actor)) + return false; + break; + case 305: + if (!(actor && actor->player && actor->player->charability == triggerline->args[1])) + return false; + break; + case 309: + // Only red/blue team members can activate this. + if (!(actor && actor->player)) + return false; + if (actor->player->ctfteam != ((triggerline->args[1] == TMT_RED) ? 1 : 2)) + return false; + break; + case 314: + if (!P_CheckPushables(triggerline, caller)) + return false; + break; + case 317: + { // Unlockable triggers required + INT32 trigid = triggerline->args[1]; + + if ((modifiedgame && !savemoddata) || (netgame || multiplayer)) + return false; + else if (trigid < 0 || trigid > 31) // limited by 32 bit variable + { + CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", triggerline->sidenum[0], trigid); + return false; + } + else if (!(unlocktriggers & (1 << trigid))) + return false; + } + break; + case 319: + { // An unlockable itself must be unlocked! + INT32 unlockid = triggerline->args[1]; + + if ((modifiedgame && !savemoddata) || (netgame || multiplayer)) + return false; + else if (unlockid < 0 || unlockid >= MAXUNLOCKABLES) // limited by unlockable count + { + CONS_Debug(DBG_GAMELOGIC, "Unlockable check (sidedef %hu): bad unlockable ID %d\n", triggerline->sidenum[0], unlockid); + return false; + } + else if (!(unlockables[unlockid-1].unlocked)) + return false; + } + break; + case 321: + // decrement calls left before triggering + if (triggerline->callcount > 0) + { + if (--triggerline->callcount > 0) + return false; + } + break; + case 323: // nightserize + case 325: // denightserize + case 327: // nights lap + case 329: // nights egg capsule touch + if (!P_CheckNightsTriggerLine(triggerline, actor)) + return false; + break; + case 331: + if (!(actor && actor->player)) + return false; + if (!triggerline->stringargs[0]) + return false; + if (!(stricmp(triggerline->stringargs[0], skins[actor->player->skin].name) == 0) ^ !!(triggerline->args[1])) + return false; + break; + case 334: // object dye + { + INT32 triggercolor = triggerline->stringargs[0] ? get_number(triggerline->stringargs[0]) : SKINCOLOR_NONE; + UINT16 color = (actor->player ? actor->player->powers[pw_dye] : actor->color); + + if (!!(triggerline->args[1]) ^ (triggercolor != color)) + return false; + } + break; + case 337: // emerald check + if (!P_CheckEmeralds(triggerline->args[2], (UINT16)triggerline->args[1])) + return false; + break; + case 340: // NiGHTS mare + if (!P_CheckPlayerMare(triggerline)) + return false; + break; + default: + break; + } + + ///////////////////////////////// + // Processing linedef specials // + ///////////////////////////////// + + if (!P_ActivateLinedefExecutorsInSector(triggerline, actor, caller)) + return false; + + // "Trigger on X calls" linedefs reset if args[2] is set + if (specialtype == 321 && triggerline->args[2]) + triggerline->callcount = triggerline->args[3]; else - // These special types work only once - if (specialtype == 302 // Once - || specialtype == 304 // Ring count - Once - || specialtype == 307 // Character ability - Once - || specialtype == 308 // Race only - Once - || specialtype == 313 // No More Enemies - Once - || specialtype == 315 // No of pushables - Once - || specialtype == 318 // Unlockable trigger - Once - || specialtype == 320 // Unlockable - Once - || specialtype == 321 || specialtype == 322 // Trigger on X calls - Continuous + Each Time - || specialtype == 324 // Nightserize - Once - || specialtype == 326 // DeNightserize - Once - || specialtype == 328 // Nights lap - Once - || specialtype == 330 // Nights Bonus Time - Once - || specialtype == 333 // Skin - Once - || specialtype == 336 // Dye - Once - || specialtype == 399) // Level Load - triggerline->special = 0; // Clear it out + { + // These special types work only once + if (specialtype == 313 // No more enemies + || specialtype == 321 // Trigger on X calls + || specialtype == 399) // Level Load + triggerline->special = 0; + else if ((specialtype == 323 // Nightserize + || specialtype == 325 // DeNightserize + || specialtype == 327 // Nights lap + || specialtype == 329) // Nights bonus time + && triggerline->args[0]) + triggerline->special = 0; + else if ((specialtype == 300 // Basic + || specialtype == 303 // Ring count + || specialtype == 305 // Character ability + || specialtype == 308 // Gametype + || specialtype == 309 // CTF team + || specialtype == 314 // No of pushables + || specialtype == 317 // Unlockable trigger + || specialtype == 319 // Unlockable + || specialtype == 331 // Player skin + || specialtype == 334 // Object dye + || specialtype == 337) // Emerald check + && triggerline->args[0] == TMT_ONCE) + triggerline->special = 0; + } return true; } @@ -1948,39 +1922,160 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller */ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) { - size_t masterline; + INT32 masterline; CONS_Debug(DBG_GAMELOGIC, "P_LinedefExecute: Executing trigger linedefs of tag %d\n", tag); I_Assert(!actor || !P_MobjWasRemoved(actor)); // If actor is there, it must be valid. - for (masterline = 0; masterline < numlines; masterline++) + TAG_ITER_LINES(tag, masterline) { - if (Tag_FGet(&lines[masterline].tags) != tag) - continue; - - // "No More Enemies" and "Level Load" take care of themselves. - if (lines[masterline].special == 313 - || lines[masterline].special == 399 - // Each-time executors handle themselves, too - || lines[masterline].special == 301 // Each time - || lines[masterline].special == 306 // Character ability - Each time - || lines[masterline].special == 310 // CTF Red team - Each time - || lines[masterline].special == 312 // CTF Blue team - Each time - || lines[masterline].special == 322 // Trigger on X calls - Each Time - || lines[masterline].special == 332 // Skin - Each time - || lines[masterline].special == 335)// Dye - Each time - continue; - if (lines[masterline].special < 300 || lines[masterline].special > 399) continue; + // "No More Enemies" and "Level Load" take care of themselves. + if (lines[masterline].special == 313 || lines[masterline].special == 399) + continue; + + // Each-time executors handle themselves, too + if ((lines[masterline].special == 300 // Basic + || lines[masterline].special == 303 // Ring count + || lines[masterline].special == 305 // Character ability + || lines[masterline].special == 308 // Gametype + || lines[masterline].special == 309 // CTF team + || lines[masterline].special == 314 // Number of pushables + || lines[masterline].special == 317 // Condition set trigger + || lines[masterline].special == 319 // Unlockable trigger + || lines[masterline].special == 331 // Player skin + || lines[masterline].special == 334 // Object dye + || lines[masterline].special == 337) // Emerald check + && lines[masterline].args[0] > TMT_EACHTIMEMASK) + continue; + + if (lines[masterline].special == 321 && lines[masterline].args[0] > TMXT_EACHTIMEMASK) // Trigger after X calls + continue; + if (!P_RunTriggerLinedef(&lines[masterline], actor, caller)) return; // cancel P_LinedefExecute if function returns false } } +static void P_PlaySFX(INT32 sfxnum, mobj_t *mo, sector_t *callsec, INT16 tag, textmapsoundsource_t source, textmapsoundlistener_t listener) +{ + if (sfxnum == sfx_None) + return; // Do nothing! + + if (sfxnum < sfx_None || sfxnum >= NUMSFX) + { + CONS_Debug(DBG_GAMELOGIC, "Line type 414 Executor: sfx number %d is invalid!\n", sfxnum); + return; + } + + // Check if you can hear the sound + switch (listener) + { + case TMSL_TRIGGERER: // only play sound if displayplayer + if (!mo) + return; + + if (!mo->player) + return; + + if (mo->player != &players[displayplayer] && mo->player != &players[secondarydisplayplayer]) + return; + + break; + case TMSL_TAGGEDSECTOR: // only play if touching tagged sectors + { + UINT8 i = 0; + mobj_t *camobj = players[displayplayer].mo; + ffloor_t *rover; + boolean foundit = false; + + for (i = 0; i < 2; camobj = players[secondarydisplayplayer].mo, i++) + { + if (!camobj) + continue; + + if (foundit || Tag_Find(&camobj->subsector->sector->tags, tag)) + { + foundit = true; + break; + } + + // Only trigger if mobj is touching the tag + for (rover = camobj->subsector->sector->ffloors; rover; rover = rover->next) + { + if (!Tag_Find(&rover->master->frontsector->tags, tag)) + continue; + + if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) + continue; + + if (camobj->z + camobj->height < P_GetSpecialBottomZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) + continue; + + foundit = true; + break; + } + } + + if (!foundit) + return; + + break; + } + case TMSL_EVERYONE: // no additional check + default: + break; + } + + // Play the sound from the specified source + switch (source) + { + case TMSS_TRIGGERMOBJ: // play the sound from mobj that triggered it + if (mo) + S_StartSound(mo, sfxnum); + break; + case TMSS_TRIGGERSECTOR: // play the sound from calling sector's soundorg + if (callsec) + S_StartSound(&callsec->soundorg, sfxnum); + else if (mo) + S_StartSound(&mo->subsector->sector->soundorg, sfxnum); + break; + case TMSS_NOWHERE: // play the sound from nowhere + S_StartSound(NULL, sfxnum); + break; + case TMSS_TAGGEDSECTOR: // play the sound from tagged sectors' soundorgs + { + INT32 secnum; + + TAG_ITER_SECTORS(tag, secnum) + S_StartSound(§ors[secnum].soundorg, sfxnum); + break; + } + default: + break; + } +} + +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 // @@ -1988,53 +2083,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) { @@ -2051,7 +2107,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; @@ -2063,7 +2119,7 @@ void P_SwitchWeather(INT32 weathernum) continue; // not a precipmobj thinker precipmobj = (precipmobj_t *)think; - if (swap == PRECIP_RAIN) // Snow To Rain + if (weathernum == PRECIP_RAIN || weathernum == PRECIP_STORM || weathernum == PRECIP_STORM_NOSTRIKES) // Snow To Rain { precipmobj->flags = mobjinfo[MT_RAIN].flags; st = &states[mobjinfo[MT_RAIN].spawnstate]; @@ -2078,7 +2134,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; @@ -2103,7 +2159,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; @@ -2117,48 +2173,33 @@ void P_SwitchWeather(INT32 weathernum) case PRECIP_SNOW: // snow curWeather = PRECIP_SNOW; - if (!swap) + if (purge) P_SpawnPrecipitation(); break; case PRECIP_RAIN: // rain { - boolean dontspawn = false; - - if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES) - dontspawn = true; - curWeather = PRECIP_RAIN; - if (!dontspawn && !swap) + if (purge) P_SpawnPrecipitation(); break; } case PRECIP_STORM: // storm { - boolean dontspawn = false; - - if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES) - dontspawn = true; - curWeather = PRECIP_STORM; - if (!dontspawn && !swap) + if (purge) P_SpawnPrecipitation(); break; } case PRECIP_STORM_NOSTRIKES: // storm w/o lightning { - boolean dontspawn = false; - - if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES) - dontspawn = true; - curWeather = PRECIP_STORM_NOSTRIKES; - if (!dontspawn && !swap) + if (purge) P_SpawnPrecipitation(); break; @@ -2166,14 +2207,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; @@ -2204,6 +2242,39 @@ static mobj_t *P_GetObjectTypeInSectorNum(mobjtype_t type, size_t s) return NULL; } +static mobj_t* P_FindObjectTypeFromTag(mobjtype_t type, mtag_t tag) +{ + if (udmf) + { + INT32 mtnum; + mobj_t *mo; + + TAG_ITER_THINGS(tag, mtnum) + { + mo = mapthings[mtnum].mobj; + + if (!mo) + continue; + + if (mo->type != type) + continue; + + return mo; + } + + return NULL; + } + else + { + INT32 secnum; + + if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) + return NULL; + + return P_GetObjectTypeInSectorNum(type, secnum); + } +} + /** Processes the line special triggered by an object. * * \param line Line with the special command on it. @@ -2222,8 +2293,6 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 secnum = -1; mobj_t *bot = NULL; - mtag_t tag = Tag_FGet(&line->tags); - TAG_ITER_DECLARECOUNTER(0); I_Assert(!mo || !P_MobjWasRemoved(mo)); // If mo is there, mo must be valid! @@ -2233,90 +2302,134 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // note: only commands with linedef types >= 400 && < 500 can be used switch (line->special) { - case 400: // Set tagged sector's floor height/pic - EV_DoFloor(line, instantMoveFloorByFrontSector); + case 400: // Set tagged sector's heights/flats + if (line->args[1] != TMP_CEILING) + EV_DoFloor(line->args[0], line, instantMoveFloorByFrontSector); + if (line->args[1] != TMP_FLOOR) + EV_DoCeiling(line->args[0], line, instantMoveCeilingByFrontSector); break; - case 401: // Set tagged sector's ceiling height/pic - EV_DoCeiling(line, instantMoveCeilingByFrontSector); - break; - - case 402: // Set tagged sector's light level + case 402: // Copy light level to tagged sectors { INT16 newlightlevel; + INT16 newfloorlightlevel, newceilinglightlevel; + boolean newfloorlightabsolute, newceilinglightabsolute; INT32 newfloorlightsec, newceilinglightsec; newlightlevel = line->frontsector->lightlevel; + newfloorlightlevel = line->frontsector->floorlightlevel; + newfloorlightabsolute = line->frontsector->floorlightabsolute; + newceilinglightlevel = line->frontsector->ceilinglightlevel; + newceilinglightabsolute = line->frontsector->ceilinglightabsolute; newfloorlightsec = line->frontsector->floorlightsec; newceilinglightsec = line->frontsector->ceilinglightsec; - // act on all sectors with the same tag as the triggering linedef - TAG_ITER_SECTORS(0, tag, secnum) + TAG_ITER_SECTORS(line->args[0], secnum) { if (sectors[secnum].lightingdata) { // Stop the lighting madness going on in this sector! - P_RemoveThinker(&((elevator_t *)sectors[secnum].lightingdata)->thinker); + P_RemoveThinker(&((thinkerdata_t *)sectors[secnum].lightingdata)->thinker); sectors[secnum].lightingdata = NULL; - - // No, it's not an elevator_t, but any struct with a thinker_t named - // 'thinker' at the beginning will do here. (We don't know what it - // actually is: could be lightlevel_t, fireflicker_t, glow_t, etc.) } - sectors[secnum].lightlevel = newlightlevel; - sectors[secnum].floorlightsec = newfloorlightsec; - sectors[secnum].ceilinglightsec = newceilinglightsec; + if (!(line->args[1] & TMLC_NOSECTOR)) + sectors[secnum].lightlevel = newlightlevel; + if (!(line->args[1] & TMLC_NOFLOOR)) + { + sectors[secnum].floorlightlevel = newfloorlightlevel; + sectors[secnum].floorlightabsolute = newfloorlightabsolute; + sectors[secnum].floorlightsec = newfloorlightsec; + } + if (!(line->args[1] & TMLC_NOCEILING)) + { + sectors[secnum].ceilinglightlevel = newceilinglightlevel; + sectors[secnum].ceilinglightabsolute = newceilinglightabsolute; + sectors[secnum].ceilinglightsec = newceilinglightsec; + } } } break; - case 403: // Move floor, linelen = speed, frontsector floor = dest height - EV_DoFloor(line, moveFloorByFrontSector); + case 403: // Move planes by front sector + if (line->args[1] != TMP_CEILING) + EV_DoFloor(line->args[0], line, moveFloorByFrontSector); + if (line->args[1] != TMP_FLOOR) + EV_DoCeiling(line->args[0], line, moveCeilingByFrontSector); break; - case 404: // Move ceiling, linelen = speed, frontsector ceiling = dest height - EV_DoCeiling(line, moveCeilingByFrontSector); + case 405: // Move planes by distance + if (line->args[1] != TMP_CEILING) + EV_DoFloor(line->args[0], line, moveFloorByDistance); + if (line->args[1] != TMP_FLOOR) + EV_DoCeiling(line->args[0], line, moveCeilingByDistance); break; - case 405: // Move floor by front side texture offsets, offset x = speed, offset y = amount to raise/lower - EV_DoFloor(line, moveFloorByFrontTexture); + case 408: // Set flats + { + TAG_ITER_SECTORS(line->args[0], secnum) + { + if (line->args[1] != TMP_CEILING) + sectors[secnum].floorpic = line->frontsector->floorpic; + if (line->args[1] != TMP_FLOOR) + sectors[secnum].ceilingpic = line->frontsector->ceilingpic; + } break; - - case 407: // Move ceiling by front side texture offsets, offset x = speed, offset y = amount to raise/lower - EV_DoCeiling(line, moveCeilingByFrontTexture); - break; - -/* case 405: // Lower floor by line, dx = speed, dy = amount to lower - EV_DoFloor(line, lowerFloorByLine); - break; - - case 406: // Raise floor by line, dx = speed, dy = amount to raise - EV_DoFloor(line, raiseFloorByLine); - break; - - case 407: // Lower ceiling by line, dx = speed, dy = amount to lower - EV_DoCeiling(line, lowerCeilingByLine); - break; - - case 408: // Raise ceiling by line, dx = speed, dy = amount to raise - EV_DoCeiling(line, raiseCeilingByLine); - break;*/ + } case 409: // Change tagged sectors' tag // (formerly "Change calling sectors' tag", but behavior was changed) { - TAG_ITER_SECTORS(0, tag, secnum) - Tag_SectorFSet(secnum,(INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); + mtag_t newtag = line->args[1]; + + TAG_ITER_SECTORS(line->args[0], secnum) + { + switch (line->args[2]) + { + case TMT_ADD: + Tag_SectorAdd(secnum, newtag); + break; + case TMT_REMOVE: + Tag_SectorRemove(secnum, newtag); + break; + case TMT_REPLACEFIRST: + default: + Tag_SectorFSet(secnum, newtag); + break; + case TMT_TRIGGERTAG: + sectors[secnum].triggertag = newtag; + break; + } + } break; } case 410: // Change front sector's tag - Tag_SectorFSet((UINT32)(line->frontsector - sectors), (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); + { + mtag_t newtag = line->args[1]; + secnum = (UINT32)(line->frontsector - sectors); + + switch (line->args[2]) + { + case TMT_ADD: + Tag_SectorAdd(secnum, newtag); + break; + case TMT_REMOVE: + Tag_SectorRemove(secnum, newtag); + break; + case TMT_REPLACEFIRST: + default: + Tag_SectorFSet(secnum, newtag); + break; + case TMT_TRIGGERTAG: + sectors[secnum].triggertag = newtag; + break; + } break; + } case 411: // Stop floor/ceiling movement in tagged sector(s) - TAG_ITER_SECTORS(0, tag, secnum) + TAG_ITER_SECTORS(line->args[0], secnum) { if (sectors[secnum].floordata) { @@ -2350,13 +2463,13 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (!mo) // nothing to teleport return; - if (line->flags & ML_EFFECT3) // Relative silent teleport + if (line->args[1] & TMT_RELATIVE) // Relative silent teleport { fixed_t x, y, z; - x = sides[line->sidenum[0]].textureoffset; - y = sides[line->sidenum[0]].rowoffset; - z = line->frontsector->ceilingheight; + x = line->args[2] << FRACBITS; + y = line->args[3] << FRACBITS; + z = line->args[4] << FRACBITS; P_UnsetThingPosition(mo); mo->x += x; @@ -2386,41 +2499,40 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } else { - if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) - return; + angle_t angle; + boolean silent, keepmomentum; - dest = P_GetObjectTypeInSectorNum(MT_TELEPORTMAN, secnum); + dest = P_FindObjectTypeFromTag(MT_TELEPORTMAN, line->args[0]); if (!dest) return; + angle = (line->args[1] & TMT_KEEPANGLE) ? mo->angle : dest->angle; + silent = !!(line->args[1] & TMT_SILENT); + keepmomentum = !!(line->args[1] & TMT_KEEPMOMENTUM); + if (bot) - P_Teleport(bot, dest->x, dest->y, dest->z, (line->flags & ML_NOCLIMB) ? mo->angle : dest->angle, (line->flags & ML_BLOCKMONSTERS) == 0, (line->flags & ML_EFFECT4) == ML_EFFECT4); - if (line->flags & ML_BLOCKMONSTERS) - P_Teleport(mo, dest->x, dest->y, dest->z, (line->flags & ML_NOCLIMB) ? mo->angle : dest->angle, false, (line->flags & ML_EFFECT4) == ML_EFFECT4); - else - { - P_Teleport(mo, dest->x, dest->y, dest->z, (line->flags & ML_NOCLIMB) ? mo->angle : dest->angle, true, (line->flags & ML_EFFECT4) == ML_EFFECT4); - // Play the 'bowrwoosh!' sound - S_StartSound(dest, sfx_mixup); - } + P_Teleport(bot, dest->x, dest->y, dest->z, angle, !silent, keepmomentum); + P_Teleport(mo, dest->x, dest->y, dest->z, angle, !silent, keepmomentum); + if (!silent) + S_StartSound(dest, sfx_mixup); // Play the 'bowrwoosh!' sound } } break; case 413: // Change music - // console player only unless NOCLIMB is set - if ((line->flags & ML_NOCLIMB) || (mo && mo->player && P_IsLocalPlayer(mo->player)) || titlemapinaction) + // console player only unless TMM_ALLPLAYERS is set + if ((line->args[0] & TMM_ALLPLAYERS) || (mo && mo->player && P_IsLocalPlayer(mo->player)) || titlemapinaction) { - boolean musicsame = (!sides[line->sidenum[0]].text[0] || !strnicmp(sides[line->sidenum[0]].text, S_MusicName(), 7)); - UINT16 tracknum = (UINT16)max(sides[line->sidenum[0]].bottomtexture, 0); - INT32 position = (INT32)max(sides[line->sidenum[0]].midtexture, 0); - UINT32 prefadems = (UINT32)max(sides[line->sidenum[0]].textureoffset >> FRACBITS, 0); - UINT32 postfadems = (UINT32)max(sides[line->sidenum[0]].rowoffset >> FRACBITS, 0); - UINT8 fadetarget = (UINT8)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].textureoffset >> FRACBITS : 0, 0); - INT16 fadesource = (INT16)max((line->sidenum[1] != 0xffff) ? sides[line->sidenum[1]].rowoffset >> FRACBITS : -1, -1); + boolean musicsame = (!line->stringargs[0] || !line->stringargs[0][0] || !strnicmp(line->stringargs[0], S_MusicName(), 7)); + UINT16 tracknum = (UINT16)max(line->args[6], 0); + INT32 position = (INT32)max(line->args[1], 0); + UINT32 prefadems = (UINT32)max(line->args[2], 0); + UINT32 postfadems = (UINT32)max(line->args[3], 0); + UINT8 fadetarget = (UINT8)max(line->args[4], 0); + INT16 fadesource = (INT16)max(line->args[5], -1); // Seek offset from current song position - if (line->flags & ML_EFFECT1) + if (line->args[0] & TMM_OFFSET) { // adjust for loop point if subtracting if (position < 0 && S_GetMusicLength() && @@ -2432,7 +2544,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } // Fade current music to target volume (if music won't be changed) - if ((line->flags & ML_EFFECT2) && fadetarget && musicsame) + if ((line->args[0] & TMM_FADE) && fadetarget && musicsame) { // 0 fadesource means fade from current volume. // meaning that we can't specify volume 0 as the source volume -- this starts at 1. @@ -2450,22 +2562,25 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Change the music and apply position/fade operations else { - strncpy(mapmusname, sides[line->sidenum[0]].text, 7); + if (!line->stringargs[0]) + break; + + strncpy(mapmusname, line->stringargs[0], 7); mapmusname[6] = 0; mapmusflags = tracknum & MUSIC_TRACKMASK; - if (!(line->flags & ML_BLOCKMONSTERS)) + if (!(line->args[0] & TMM_NORELOAD)) mapmusflags |= MUSIC_RELOADRESET; - if (line->flags & ML_BOUNCY) + if (line->args[0] & TMM_FORCERESET) mapmusflags |= MUSIC_FORCERESET; mapmusposition = position; - S_ChangeMusicEx(mapmusname, mapmusflags, !(line->flags & ML_EFFECT4), position, - !(line->flags & ML_EFFECT2) ? prefadems : 0, - !(line->flags & ML_EFFECT2) ? postfadems : 0); + S_ChangeMusicEx(mapmusname, mapmusflags, !(line->args[0] & TMM_NOLOOP), position, + !(line->args[0] & TMM_FADE) ? prefadems : 0, + !(line->args[0] & TMM_FADE) ? postfadems : 0); - if ((line->flags & ML_EFFECT2) && fadetarget) + if ((line->args[0] & TMM_FADE) && fadetarget) { if (!postfadems) S_SetInternalMusicVolume(fadetarget); @@ -2474,302 +2589,55 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } } - // Except, you can use the ML_BLOCKMONSTERS flag to change this behavior. + // Except, you can use the TMM_NORELOAD flag to change this behavior. // if (mapmusflags & MUSIC_RELOADRESET) then it will reset the music in G_PlayerReborn. } break; case 414: // Play SFX - { - INT32 sfxnum; - - sfxnum = sides[line->sidenum[0]].toptexture; - - if (sfxnum == sfx_None) - return; // Do nothing! - if (sfxnum < sfx_None || sfxnum >= NUMSFX) - { - CONS_Debug(DBG_GAMELOGIC, "Line type 414 Executor: sfx number %d is invalid!\n", sfxnum); - return; - } - - if (tag != 0) // Do special stuff only if a non-zero linedef tag is set - { - // Play sounds from tagged sectors' origins. - if (line->flags & ML_EFFECT5) // Repeat Midtexture - { - // Additionally play the sound from tagged sectors' soundorgs - sector_t *sec; - - TAG_ITER_SECTORS(0, tag, secnum) - { - sec = §ors[secnum]; - S_StartSound(&sec->soundorg, sfxnum); - } - } - - // Play the sound without origin for anyone, as long as they're inside tagged areas. - else - { - UINT8 i = 0; - mobj_t* camobj = players[displayplayer].mo; - ffloor_t *rover; - boolean foundit = false; - - for (i = 0; i < 2; camobj = players[secondarydisplayplayer].mo, i++) - { - if (!camobj) - continue; - - if (foundit || Tag_Find(&camobj->subsector->sector->tags, tag)) - { - foundit = true; - break; - } - - // Only trigger if mobj is touching the tag - for(rover = camobj->subsector->sector->ffloors; rover; rover = rover->next) - { - if (!Tag_Find(&rover->master->frontsector->tags, tag)) - continue; - - if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) - continue; - - if (camobj->z + camobj->height < P_GetSpecialBottomZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) - continue; - - foundit = true; - break; - } - } - - if (foundit) - S_StartSound(NULL, sfxnum); - } - } - else - { - if (line->flags & ML_NOCLIMB) - { - // play the sound from nowhere, but only if display player triggered it - if (mo && mo->player && (mo->player == &players[displayplayer] || mo->player == &players[secondarydisplayplayer])) - S_StartSound(NULL, sfxnum); - } - else if (line->flags & ML_EFFECT4) - { - // play the sound from nowhere - S_StartSound(NULL, sfxnum); - } - else if (line->flags & ML_BLOCKMONSTERS) - { - // play the sound from calling sector's soundorg - if (callsec) - S_StartSound(&callsec->soundorg, sfxnum); - else if (mo) - S_StartSound(&mo->subsector->sector->soundorg, sfxnum); - } - else if (mo) - { - // play the sound from mobj that triggered it - S_StartSound(mo, sfxnum); - } - } - } + P_PlaySFX(line->stringargs[0] ? get_number(line->stringargs[0]) : sfx_None, mo, callsec, line->args[2], line->args[0], line->args[1]); break; case 415: // Run a script if (cv_runscripts.value) { - INT32 scrnum; - lumpnum_t lumpnum; - char newname[9]; - - strcpy(newname, G_BuildMapName(gamemap)); - newname[0] = 'S'; - newname[1] = 'C'; - newname[2] = 'R'; - - scrnum = sides[line->sidenum[0]].textureoffset>>FRACBITS; - if (scrnum < 0 || scrnum > 999) - { - scrnum = 0; - newname[5] = newname[6] = newname[7] = '0'; - } - else - { - newname[5] = (char)('0' + (char)((scrnum/100))); - newname[6] = (char)('0' + (char)((scrnum%100)/10)); - newname[7] = (char)('0' + (char)(scrnum%10)); - } - newname[8] = '\0'; - - lumpnum = W_CheckNumForName(newname); + lumpnum_t lumpnum = W_CheckNumForName(line->stringargs[0]); if (lumpnum == LUMPERROR || W_LumpLength(lumpnum) == 0) - { - CONS_Debug(DBG_SETUP, "SOC Error: script lump %s not found/not valid.\n", newname); - } + CONS_Debug(DBG_SETUP, "Line type 415 Executor: script lump %s not found/not valid.\n", line->stringargs[0]); else COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); } break; case 416: // Spawn adjustable fire flicker - TAG_ITER_SECTORS(0, tag, secnum) - { - if (line->flags & ML_NOCLIMB && line->backsector) - { - // Use front sector for min light level, back sector for max. - // This is tricky because P_SpawnAdjustableFireFlicker expects - // the maxsector (second argument) to also be the target - // sector, so we have to do some light level twiddling. - fireflicker_t *flick; - INT16 reallightlevel = sectors[secnum].lightlevel; - sectors[secnum].lightlevel = line->backsector->lightlevel; - - flick = P_SpawnAdjustableFireFlicker(line->frontsector, §ors[secnum], - P_AproxDistance(line->dx, line->dy)>>FRACBITS); - - // Make sure the starting light level is in range. - if (reallightlevel < flick->minlight) - reallightlevel = (INT16)flick->minlight; - else if (reallightlevel > flick->maxlight) - reallightlevel = (INT16)flick->maxlight; - - sectors[secnum].lightlevel = reallightlevel; - } - else - { - // Use front sector for min, target sector for max, - // the same way linetype 61 does it. - P_SpawnAdjustableFireFlicker(line->frontsector, §ors[secnum], - P_AproxDistance(line->dx, line->dy)>>FRACBITS); - } - } + TAG_ITER_SECTORS(line->args[0], secnum) + P_SpawnAdjustableFireFlicker(§ors[secnum], line->args[2], + line->args[3] ? sectors[secnum].lightlevel : line->args[4], line->args[1]); break; case 417: // Spawn adjustable glowing light - TAG_ITER_SECTORS(0, tag, secnum) - { - if (line->flags & ML_NOCLIMB && line->backsector) - { - // Use front sector for min light level, back sector for max. - // This is tricky because P_SpawnAdjustableGlowingLight expects - // the maxsector (second argument) to also be the target - // sector, so we have to do some light level twiddling. - glow_t *glow; - INT16 reallightlevel = sectors[secnum].lightlevel; - sectors[secnum].lightlevel = line->backsector->lightlevel; - - glow = P_SpawnAdjustableGlowingLight(line->frontsector, §ors[secnum], - P_AproxDistance(line->dx, line->dy)>>FRACBITS); - - // Make sure the starting light level is in range. - if (reallightlevel < glow->minlight) - reallightlevel = (INT16)glow->minlight; - else if (reallightlevel > glow->maxlight) - reallightlevel = (INT16)glow->maxlight; - - sectors[secnum].lightlevel = reallightlevel; - } - else - { - // Use front sector for min, target sector for max, - // the same way linetype 602 does it. - P_SpawnAdjustableGlowingLight(line->frontsector, §ors[secnum], - P_AproxDistance(line->dx, line->dy)>>FRACBITS); - } - } + TAG_ITER_SECTORS(line->args[0], secnum) + P_SpawnAdjustableGlowingLight(§ors[secnum], line->args[2], + line->args[3] ? sectors[secnum].lightlevel : line->args[4], line->args[1]); break; - case 418: // Spawn adjustable strobe flash (unsynchronized) - TAG_ITER_SECTORS(0, tag, secnum) - { - if (line->flags & ML_NOCLIMB && line->backsector) - { - // Use front sector for min light level, back sector for max. - // This is tricky because P_SpawnAdjustableGlowingLight expects - // the maxsector (second argument) to also be the target - // sector, so we have to do some light level twiddling. - strobe_t *flash; - INT16 reallightlevel = sectors[secnum].lightlevel; - sectors[secnum].lightlevel = line->backsector->lightlevel; - - flash = P_SpawnAdjustableStrobeFlash(line->frontsector, §ors[secnum], - abs(line->dx)>>FRACBITS, abs(line->dy)>>FRACBITS, false); - - // Make sure the starting light level is in range. - if (reallightlevel < flash->minlight) - reallightlevel = (INT16)flash->minlight; - else if (reallightlevel > flash->maxlight) - reallightlevel = (INT16)flash->maxlight; - - sectors[secnum].lightlevel = reallightlevel; - } - else - { - // Use front sector for min, target sector for max, - // the same way linetype 602 does it. - P_SpawnAdjustableStrobeFlash(line->frontsector, §ors[secnum], - abs(line->dx)>>FRACBITS, abs(line->dy)>>FRACBITS, false); - } - } - break; - - case 419: // Spawn adjustable strobe flash (synchronized) - TAG_ITER_SECTORS(0, tag, secnum) - { - if (line->flags & ML_NOCLIMB && line->backsector) - { - // Use front sector for min light level, back sector for max. - // This is tricky because P_SpawnAdjustableGlowingLight expects - // the maxsector (second argument) to also be the target - // sector, so we have to do some light level twiddling. - strobe_t *flash; - INT16 reallightlevel = sectors[secnum].lightlevel; - sectors[secnum].lightlevel = line->backsector->lightlevel; - - flash = P_SpawnAdjustableStrobeFlash(line->frontsector, §ors[secnum], - abs(line->dx)>>FRACBITS, abs(line->dy)>>FRACBITS, true); - - // Make sure the starting light level is in range. - if (reallightlevel < flash->minlight) - reallightlevel = (INT16)flash->minlight; - else if (reallightlevel > flash->maxlight) - reallightlevel = (INT16)flash->maxlight; - - sectors[secnum].lightlevel = reallightlevel; - } - else - { - // Use front sector for min, target sector for max, - // the same way linetype 602 does it. - P_SpawnAdjustableStrobeFlash(line->frontsector, §ors[secnum], - abs(line->dx)>>FRACBITS, abs(line->dy)>>FRACBITS, true); - } - } + case 418: // Spawn adjustable strobe flash + TAG_ITER_SECTORS(line->args[0], secnum) + P_SpawnAdjustableStrobeFlash(§ors[secnum], line->args[3], + (line->args[4] & TMB_USETARGET) ? sectors[secnum].lightlevel : line->args[5], + line->args[1], line->args[2], line->args[4] & TMB_SYNC); break; case 420: // Fade light levels in tagged sectors to new value - P_FadeLight(tag, - (line->flags & ML_DONTPEGBOTTOM) ? max(sides[line->sidenum[0]].textureoffset>>FRACBITS, 0) : line->frontsector->lightlevel, - // failsafe: if user specifies Back Y Offset and NOT Front Y Offset, use the Back Offset - // to be consistent with other light and fade specials - (line->flags & ML_DONTPEGBOTTOM) ? - ((line->sidenum[1] != 0xFFFF && !(sides[line->sidenum[0]].rowoffset>>FRACBITS)) ? - max(min(sides[line->sidenum[1]].rowoffset>>FRACBITS, 255), 0) - : max(min(sides[line->sidenum[0]].rowoffset>>FRACBITS, 255), 0)) - : abs(P_AproxDistance(line->dx, line->dy))>>FRACBITS, - (line->flags & ML_EFFECT4), - (line->flags & ML_EFFECT5)); + P_FadeLight(line->args[0], line->args[1], line->args[2], line->args[3] & TMF_TICBASED, line->args[3] & TMF_OVERRIDE, line->args[3] & TMF_RELATIVE); break; case 421: // Stop lighting effect in tagged sectors - TAG_ITER_SECTORS(0, tag, secnum) + TAG_ITER_SECTORS(line->args[0], secnum) if (sectors[secnum].lightingdata) { - P_RemoveThinker(&((elevator_t *)sectors[secnum].lightingdata)->thinker); + P_RemoveThinker(&((thinkerdata_t *)sectors[secnum].lightingdata)->thinker); sectors[secnum].lightingdata = NULL; } break; @@ -2777,15 +2645,13 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 422: // Cut away to another view { mobj_t *altview; + INT32 aim; if ((!mo || !mo->player) && !titlemapinaction) // only players have views, and title screens return; - if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) - return; - - altview = P_GetObjectTypeInSectorNum(MT_ALTVIEWMAN, secnum); - if (!altview) + altview = P_FindObjectTypeFromTag(MT_ALTVIEWMAN, line->args[0]); + if (!altview || !altview->spawnpoint) return; // If titlemap, set the camera ref for title's thinker @@ -2795,59 +2661,50 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) else { P_SetTarget(&mo->player->awayviewmobj, altview); - mo->player->awayviewtics = P_AproxDistance(line->dx, line->dy)>>FRACBITS; + mo->player->awayviewtics = line->args[1]; } - - if (line->flags & ML_NOCLIMB) // lets you specify a vertical angle - { - INT32 aim; - - aim = sides[line->sidenum[0]].textureoffset>>FRACBITS; - aim = (aim + 360) % 360; - aim *= (ANGLE_90>>8); - aim /= 90; - aim <<= 8; - if (titlemapinaction) - titlemapcameraref->cusval = (angle_t)aim; - else - mo->player->awayviewaiming = (angle_t)aim; - } + aim = udmf ? altview->spawnpoint->pitch : line->args[2]; + aim = (aim + 360) % 360; + aim *= (ANGLE_90>>8); + aim /= 90; + aim <<= 8; + if (titlemapinaction) + titlemapcameraref->cusval = (angle_t)aim; else - { - // straight ahead - if (!titlemapinaction) - mo->player->awayviewaiming = 0; - // don't do cusval cause that's annoying - } + mo->player->awayviewaiming = (angle_t)aim; } break; case 423: // Change Sky - if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB)) - P_SetupLevelSky(sides[line->sidenum[0]].textureoffset>>FRACBITS, (line->flags & ML_NOCLIMB)); + if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || line->args[1]) + P_SetupLevelSky(line->args[0], line->args[1]); break; case 424: // Change Weather - if (line->flags & ML_NOCLIMB) + if (line->args[1]) { - globalweather = (UINT8)(sides[line->sidenum[0]].textureoffset>>FRACBITS); + globalweather = (UINT8)(line->args[0]); P_SwitchWeather(globalweather); } else if (mo && mo->player && P_IsLocalPlayer(mo->player)) - P_SwitchWeather(sides[line->sidenum[0]].textureoffset>>FRACBITS); + P_SwitchWeather(line->args[0]); break; case 425: // Calls P_SetMobjState on calling mobj if (mo && !mo->player) - P_SetMobjState(mo, sides[line->sidenum[0]].toptexture); //P_AproxDistance(line->dx, line->dy)>>FRACBITS); + { + statenum_t state = line->stringargs[0] ? get_number(line->stringargs[0]) : S_NULL; + if (state >= 0 && state < NUMSTATES) + P_SetMobjState(mo, state); + } break; case 426: // Moves the mobj to its sector's soundorg and on the floor, and stops it if (!mo) return; - if (line->flags & ML_NOCLIMB) + if (line->args[0]) { P_UnsetThingPosition(mo); mo->x = mo->subsector->sector->soundorg.x; @@ -2868,7 +2725,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Reset bot too. if (bot) { - if (line->flags & ML_NOCLIMB) + if (line->args[0]) P_TeleportMove(bot, mo->x, mo->y, mo->z); bot->momx = bot->momy = bot->momz = 1; bot->pmomz = 0; @@ -2882,29 +2739,26 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 427: // Awards points if the mobj is a player if (mo && mo->player) - P_AddPlayerScore(mo->player, sides[line->sidenum[0]].textureoffset>>FRACBITS); + P_AddPlayerScore(mo->player, line->args[0]); break; case 428: // Start floating platform movement - EV_DoElevator(line, elevateContinuous, true); + EV_DoElevator(line->args[0], line, elevateContinuous); break; - case 429: // Crush Ceiling Down Once - EV_DoCrush(line, crushCeilOnce); + case 429: // Crush planes once + if (line->args[1] == TMP_FLOOR) + EV_DoFloor(line->args[0], line, crushFloorOnce); + else if (line->args[1] == TMP_CEILING) + EV_DoCrush(line->args[0], line, crushCeilOnce); + else + EV_DoCrush(line->args[0], line, crushBothOnce); break; - case 430: // Crush Floor Up Once - EV_DoFloor(line, crushFloorOnce); - break; - - case 431: // Crush Floor & Ceiling to middle Once - EV_DoCrush(line, crushBothOnce); - break; - - case 432: // Enable 2D Mode (Disable if noclimb) + case 432: // Enable/Disable 2D Mode if (mo && mo->player) { - if (line->flags & ML_NOCLIMB) + if (line->args[0]) mo->flags2 &= ~MF2_TWOD; else mo->flags2 |= MF2_TWOD; @@ -2918,8 +2772,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; - case 433: // Flip gravity (Flop gravity if noclimb) Works on pushables, too! - if (line->flags & ML_NOCLIMB) + case 433: // Flip/flop gravity. Works on pushables, too! + if (line->args[0]) mo->flags2 &= ~MF2_OBJECTFLIP; else mo->flags2 |= MF2_OBJECTFLIP; @@ -2930,25 +2784,15 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 434: // Custom Power if (mo && mo->player) { - mobj_t *dummy = P_SpawnMobj(mo->x, mo->y, mo->z, MT_NULL); + powertype_t power = line->stringargs[0] ? get_number(line->stringargs[0]) : 0; + INT32 value = line->stringargs[1] ? get_number(line->stringargs[1]) : 0; + if (value == -1) // 'Infinite' + value = UINT16_MAX; - var1 = sides[line->sidenum[0]].toptexture; //(line->dx>>FRACBITS)-1; + P_SetPower(mo->player, power, value); - if (line->sidenum[1] != 0xffff && line->flags & ML_BLOCKMONSTERS) // read power from back sidedef - var2 = sides[line->sidenum[1]].toptexture; - else if (line->flags & ML_NOCLIMB) // 'Infinite' - var2 = UINT16_MAX; - else - var2 = sides[line->sidenum[0]].textureoffset>>FRACBITS; - - P_SetTarget(&dummy->target, mo); - A_CustomPower(dummy); - - if (bot) { - P_SetTarget(&dummy->target, bot); - A_CustomPower(dummy); - } - P_RemoveMobj(dummy); + if (bot) + P_SetPower(bot->player, power, value); } break; @@ -2957,30 +2801,35 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) scroll_t *scroller; thinker_t *th; + fixed_t length = R_PointToDist2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); + fixed_t speed = line->args[1] << FRACBITS; + fixed_t dx = FixedMul(FixedMul(FixedDiv(line->dx, length), speed) >> SCROLL_SHIFT, CARRYFACTOR); + fixed_t dy = FixedMul(FixedMul(FixedDiv(line->dy, length), speed) >> SCROLL_SHIFT, CARRYFACTOR); + for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next) { if (th->function.acp1 != (actionf_p1)T_Scroll) continue; scroller = (scroll_t *)th; - if (!Tag_Find(§ors[scroller->affectee].tags, tag)) + if (!Tag_Find(§ors[scroller->affectee].tags, line->args[0])) continue; - scroller->dx = FixedMul(line->dx>>SCROLL_SHIFT, CARRYFACTOR); - scroller->dy = FixedMul(line->dy>>SCROLL_SHIFT, CARRYFACTOR); + scroller->dx = dx; + scroller->dy = dy; } } break; case 436: // Shatter block remotely { - INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT16 sectag = (INT16)(line->args[0]); + INT16 foftag = (INT16)(line->args[1]); sector_t *sec; // Sector that the FOF is visible in ffloor_t *rover; // FOF that we are going to crumble boolean foundrover = false; // for debug, "Can't find a FOF" message - TAG_ITER_SECTORS(0, sectag, secnum) + TAG_ITER_SECTORS(sectag, secnum) { sec = sectors + secnum; @@ -3012,10 +2861,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 437: // Disable Player Controls if (mo && mo->player) { - UINT16 fractime = (UINT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); + UINT16 fractime = (UINT16)(line->args[0]); if (fractime < 1) fractime = 1; //instantly wears off upon leaving - if (line->flags & ML_NOCLIMB) + if (line->args[1]) fractime |= 1<<15; //more crazy &ing, as if music stuff wasn't enough mo->player->powers[pw_nocontrol] = fractime; if (bot) @@ -3026,7 +2875,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 438: // Set player scale if (mo) { - mo->destscale = FixedDiv(P_AproxDistance(line->dx, line->dy), 100<destscale = FixedDiv(line->args[0]<destscale < FRACUNIT/100) mo->destscale = FRACUNIT/100; if (mo->player && bot) @@ -3038,30 +2887,33 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { size_t linenum; side_t *set = &sides[line->sidenum[0]], *this; - boolean always = !(line->flags & ML_NOCLIMB); // If noclimb: Only change mid texture if mid texture already exists on tagged lines, etc. + boolean always = !(line->args[2]); // If args[2] is set: Only change mid texture if mid texture already exists on tagged lines, etc. for (linenum = 0; linenum < numlines; linenum++) { if (lines[linenum].special == 439) continue; // Don't override other set texture lines! - if (!Tag_Find(&lines[linenum].tags, tag)) + if (!Tag_Find(&lines[linenum].tags, line->args[0])) continue; // Find tagged lines // Front side - this = &sides[lines[linenum].sidenum[0]]; - if (always || this->toptexture) this->toptexture = set->toptexture; - if (always || this->midtexture) this->midtexture = set->midtexture; - if (always || this->bottomtexture) this->bottomtexture = set->bottomtexture; - - if (lines[linenum].sidenum[1] == 0xffff) - continue; // One-sided stops here. + if (line->args[1] != TMSD_BACK) + { + this = &sides[lines[linenum].sidenum[0]]; + if (always || this->toptexture) this->toptexture = set->toptexture; + if (always || this->midtexture) this->midtexture = set->midtexture; + if (always || this->bottomtexture) this->bottomtexture = set->bottomtexture; + } // Back side - this = &sides[lines[linenum].sidenum[1]]; - if (always || this->toptexture) this->toptexture = set->toptexture; - if (always || this->midtexture) this->midtexture = set->midtexture; - if (always || this->bottomtexture) this->bottomtexture = set->bottomtexture; + if (line->args[1] != TMSD_FRONT && lines[linenum].sidenum[1] != 0xffff) + { + this = &sides[lines[linenum].sidenum[1]]; + if (always || this->toptexture) this->toptexture = set->toptexture; + if (always || this->midtexture) this->midtexture = set->midtexture; + if (always || this->bottomtexture) this->bottomtexture = set->bottomtexture; + } } } break; @@ -3074,7 +2926,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 441: // Trigger unlockable if ((!modifiedgame || savemoddata) && !(netgame || multiplayer)) { - INT32 trigid = (INT32)(sides[line->sidenum[0]].textureoffset>>FRACBITS); + INT32 trigid = line->args[0]; if (trigid < 0 || trigid > 31) // limited by 32 bit variable CONS_Debug(DBG_GAMELOGIC, "Unlockable trigger (sidedef %hu): bad trigger ID %d\n", line->sidenum[0], trigid); @@ -3097,37 +2949,37 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors { - const mobjtype_t type = (mobjtype_t)sides[line->sidenum[0]].toptexture; + const mobjtype_t type = line->stringargs[0] ? get_number(line->stringargs[0]) : MT_NULL; statenum_t state = NUMSTATES; - sector_t *sec; mobj_t *thing; - if (line->sidenum[1] != 0xffff) - state = (statenum_t)sides[line->sidenum[1]].toptexture; + if (type < 0 || type >= NUMMOBJTYPES) + break; - TAG_ITER_SECTORS(0, tag, secnum) + if (!line->args[1]) + { + state = line->stringargs[1] ? get_number(line->stringargs[1]) : S_NULL; + + if (state < 0 || state >= NUMSTATES) + break; + } + + TAG_ITER_SECTORS(line->args[0], secnum) { boolean tryagain; - sec = sectors + secnum; do { tryagain = false; - for (thing = sec->thinglist; thing; thing = thing->snext) - if (thing->type == type) - { - if (state != NUMSTATES) - { - if (!P_SetMobjState(thing, state)) // set state to specific state - { // mobj was removed - tryagain = true; // snext is corrupt, we'll have to start over. - break; - } - } - else if (!P_SetMobjState(thing, thing->state->nextstate)) // set state to nextstate - { // mobj was removed - tryagain = true; // snext is corrupt, we'll have to start over. - break; - } + for (thing = sectors[secnum].thinglist; thing; thing = thing->snext) + { + if (thing->type != type) + continue; + + if (!P_SetMobjState(thing, line->args[1] ? thing->state->nextstate : state)) + { // mobj was removed + tryagain = true; // snext is corrupt, we'll have to start over. + break; } + } } while (tryagain); } break; @@ -3135,16 +2987,16 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 443: // Calls a named Lua function if (line->stringargs[0]) - LUAh_LinedefExecute(line, mo, callsec); + LUA_HookLinedefExecute(line, mo, callsec); else - CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in arg0str)\n", sizeu1(line-lines)); + CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in stringarg0)\n", sizeu1(line-lines)); break; case 444: // Earthquake camera { - quake.intensity = sides[line->sidenum[0]].textureoffset; - quake.radius = sides[line->sidenum[0]].rowoffset; - quake.time = P_AproxDistance(line->dx, line->dy)>>FRACBITS; + quake.intensity = line->args[1] << FRACBITS; + quake.radius = line->args[2] << FRACBITS; + quake.time = line->args[0]; quake.epicenter = NULL; /// \todo @@ -3156,16 +3008,16 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; } - case 445: // Force block disappear remotely (reappear if noclimb) + case 445: // Force block disappear remotely (reappear if args[2] is set) { - INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT16 sectag = (INT16)(line->args[0]); + INT16 foftag = (INT16)(line->args[1]); sector_t *sec; // Sector that the FOF is visible (or not visible) in ffloor_t *rover; // FOF to vanish/un-vanish boolean foundrover = false; // for debug, "Can't find a FOF" message ffloortype_e oldflags; // store FOF's old flags - TAG_ITER_SECTORS(0, sectag, secnum) + TAG_ITER_SECTORS(sectag, secnum) { sec = sectors + secnum; @@ -3184,7 +3036,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) oldflags = rover->flags; // Abracadabra! - if (line->flags & ML_NOCLIMB) + if (line->args[2]) rover->flags |= FF_EXISTS; else rover->flags &= ~FF_EXISTS; @@ -3209,8 +3061,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 446: // Make block fall remotely (acts like FF_CRUMBLE) { - INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT16 sectag = (INT16)(line->args[0]); + INT16 foftag = (INT16)(line->args[1]); sector_t *sec; // Sector that the FOF is visible in ffloor_t *rover; // FOF that we are going to make fall down boolean foundrover = false; // for debug, "Can't find a FOF" message @@ -3220,10 +3072,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (mo) // NULL check player = mo->player; - if (line->flags & ML_NOCLIMB) // don't respawn! + if (line->args[2] & TMFR_NORETURN) // don't respawn! respawn = false; - TAG_ITER_SECTORS(0, sectag, secnum) + TAG_ITER_SECTORS(sectag, secnum) { sec = sectors + secnum; @@ -3239,8 +3091,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { foundrover = true; - if (line->flags & ML_BLOCKMONSTERS) // FOF flags determine respawn ability instead? - respawn = !(rover->flags & FF_NORETURN) ^ !!(line->flags & ML_NOCLIMB); // no climb inverts + if (line->args[2] & TMFR_CHECKFLAG) // FOF flags determine respawn ability instead? + respawn = !(rover->flags & FF_NORETURN) ^ !!(line->args[2] & TMFR_NORETURN); // TMFR_NORETURN inverts EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, respawn); } @@ -3279,7 +3131,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) source = sectors[sourcesec].extra_colormap; } } - TAG_ITER_SECTORS(0, line->args[0], secnum) + TAG_ITER_SECTORS(line->args[0], secnum) { if (sectors[secnum].colormap_protected) continue; @@ -3322,57 +3174,48 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; } case 448: // Change skybox viewpoint/centerpoint - if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || (line->flags & ML_NOCLIMB)) + if ((mo && mo->player && P_IsLocalPlayer(mo->player)) || line->args[3]) { - INT32 viewid = sides[line->sidenum[0]].textureoffset>>FRACBITS; - INT32 centerid = sides[line->sidenum[0]].rowoffset>>FRACBITS; + INT32 viewid = line->args[0]; + INT32 centerid = line->args[1]; - if ((line->flags & (ML_EFFECT4|ML_BLOCKMONSTERS)) == ML_EFFECT4) // Solid Midtexture is on but Block Enemies is off? + // set viewpoint mobj + if (line->args[2] != TMS_CENTERPOINT) { - CONS_Alert(CONS_WARNING, - M_GetText("Skybox switch linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), - tag); + if (viewid >= 0 && viewid < 16) + skyboxmo[0] = skyboxviewpnts[viewid]; + else + skyboxmo[0] = NULL; } - else - { - // set viewpoint mobj - if (!(line->flags & ML_EFFECT4)) // Solid Midtexture turns off viewpoint setting - { - if (viewid >= 0 && viewid < 16) - skyboxmo[0] = skyboxviewpnts[viewid]; - else - skyboxmo[0] = NULL; - } - // set centerpoint mobj - if (line->flags & ML_BLOCKMONSTERS) // Block Enemies turns ON centerpoint setting - { - if (centerid >= 0 && centerid < 16) - skyboxmo[1] = skyboxcenterpnts[centerid]; - else - skyboxmo[1] = NULL; - } + // set centerpoint mobj + if (line->args[2] != TMS_VIEWPOINT) + { + if (centerid >= 0 && centerid < 16) + skyboxmo[1] = skyboxcenterpnts[centerid]; + else + skyboxmo[1] = NULL; } CONS_Debug(DBG_GAMELOGIC, "Line type 448 Executor: viewid = %d, centerid = %d, viewpoint? = %s, centerpoint? = %s\n", viewid, centerid, - ((line->flags & ML_EFFECT4) ? "no" : "yes"), - ((line->flags & ML_BLOCKMONSTERS) ? "yes" : "no")); + ((line->args[2] == TMS_CENTERPOINT) ? "no" : "yes"), + ((line->args[2] == TMS_VIEWPOINT) ? "no" : "yes")); } break; case 449: // Enable bosses with parameter { - INT32 bossid = sides[line->sidenum[0]].textureoffset>>FRACBITS; + INT32 bossid = line->args[0]; if (bossid & ~15) // if any bits other than first 16 are set { CONS_Alert(CONS_WARNING, - M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), - tag); + M_GetText("Boss enable linedef has an invalid boss ID (%d).\nConsider changing it or removing it entirely.\n"), + bossid); break; } - if (line->flags & ML_NOCLIMB) + if (line->args[1]) { bossdisabled |= (1<args[0], mo, NULL); break; case 451: // Execute Random Linedef Executor { - INT32 rvalue1 = sides[line->sidenum[0]].textureoffset>>FRACBITS; - INT32 rvalue2 = sides[line->sidenum[0]].rowoffset>>FRACBITS; + INT32 rvalue1 = line->args[0]; + INT32 rvalue2 = line->args[1]; INT32 result; if (rvalue1 <= rvalue2) @@ -3406,15 +3249,14 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 452: // Set FOF alpha { - INT16 destvalue = line->sidenum[1] != 0xffff ? - (INT16)(sides[line->sidenum[1]].textureoffset>>FRACBITS) : (INT16)(P_AproxDistance(line->dx, line->dy)>>FRACBITS); - INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT16 destvalue = (INT16)(line->args[2]); + INT16 sectag = (INT16)(line->args[0]); + INT16 foftag = (INT16)(line->args[1]); sector_t *sec; // Sector that the FOF is visible in ffloor_t *rover; // FOF that we are going to operate boolean foundrover = false; // for debug, "Can't find a FOF" message - TAG_ITER_SECTORS(0, sectag, secnum) + TAG_ITER_SECTORS(sectag, secnum) { sec = sectors + secnum; @@ -3433,7 +3275,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // If fading an invisible FOF whose render flags we did not yet set, // initialize its alpha to 1 // for relative alpha calc - if (!(line->flags & ML_NOCLIMB) && // do translucent + if (!(line->args[3] & TMST_DONTDOTRANSLUCENT) && // do translucent (rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE !(rover->spawnflags & FF_RENDERSIDES) && !(rover->spawnflags & FF_RENDERPLANES) && @@ -3443,16 +3285,16 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) P_RemoveFakeFloorFader(rover); P_FadeFakeFloor(rover, rover->alpha, - max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)), - 0, // set alpha immediately - false, NULL, // tic-based logic - false, // do not handle FF_EXISTS - !(line->flags & ML_NOCLIMB), // handle FF_TRANSLUCENT - false, // do not handle lighting - false, // do not handle colormap - false, // do not handle collision - false, // do not do ghost fade (no collision during fade) - true); // use exact alpha values (for opengl) + max(1, min(256, (line->args[3] & TMST_RELATIVE) ? rover->alpha + destvalue : destvalue)), + 0, // set alpha immediately + false, NULL, // tic-based logic + false, // do not handle FF_EXISTS + !(line->args[3] & TMST_DONTDOTRANSLUCENT), // handle FF_TRANSLUCENT + false, // do not handle lighting + false, // do not handle colormap + false, // do not handle collision + false, // do not do ghost fade (no collision during fade) + true); // use exact alpha values (for opengl) } } @@ -3467,18 +3309,16 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 453: // Fade FOF { - INT16 destvalue = line->sidenum[1] != 0xffff ? - (INT16)(sides[line->sidenum[1]].textureoffset>>FRACBITS) : (INT16)(line->dx>>FRACBITS); - INT16 speed = line->sidenum[1] != 0xffff ? - (INT16)(abs(sides[line->sidenum[1]].rowoffset>>FRACBITS)) : (INT16)(abs(line->dy)>>FRACBITS); - INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT16 destvalue = (INT16)(line->args[2]); + INT16 speed = (INT16)(line->args[3]); + INT16 sectag = (INT16)(line->args[0]); + INT16 foftag = (INT16)(line->args[1]); sector_t *sec; // Sector that the FOF is visible in ffloor_t *rover; // FOF that we are going to operate boolean foundrover = false; // for debug, "Can't find a FOF" message size_t j = 0; // sec->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc - TAG_ITER_SECTORS(0, sectag, secnum) + TAG_ITER_SECTORS(sectag, secnum) { sec = sectors + secnum; @@ -3495,7 +3335,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) foundrover = true; // Prevent continuous execs from interfering on an existing fade - if (!(line->flags & ML_EFFECT5) + if (!(line->args[4] & TMFT_OVERRIDE) && rover->fadingdata) //&& ((fade_t*)rover->fadingdata)->timer > (ticbased ? 2 : speed*2)) { @@ -3507,21 +3347,21 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) P_AddFakeFloorFader(rover, secnum, j, destvalue, speed, - (line->flags & ML_EFFECT4), // tic-based logic - (line->flags & ML_EFFECT3), // Relative destvalue - !(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS - !(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT - !(line->flags & ML_EFFECT2), // do not handle lighting - !(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags) - !(line->flags & ML_BOUNCY), // do not handle collision - (line->flags & ML_EFFECT1), // do ghost fade (no collision during fade) - (line->flags & ML_TFERLINE)); // use exact alpha values (for opengl) + (line->args[4] & TMFT_TICBASED), // tic-based logic + (line->args[4] & TMFT_RELATIVE), // Relative destvalue + !(line->args[4] & TMFT_DONTDOEXISTS), // do not handle FF_EXISTS + !(line->args[4] & TMFT_DONTDOTRANSLUCENT), // do not handle FF_TRANSLUCENT + !(line->args[4] & TMFT_DONTDOLIGHTING), // do not handle lighting + !(line->args[4] & TMFT_DONTDOCOLORMAP), // do not handle colormap + !(line->args[4] & TMFT_IGNORECOLLISION), // do not handle collision + (line->args[4] & TMFT_GHOSTFADE), // do ghost fade (no collision during fade) + (line->args[4] & TMFT_USEEXACTALPHA)); // use exact alpha values (for opengl) else { // If fading an invisible FOF whose render flags we did not yet set, // initialize its alpha to 1 // for relative alpha calc - if (!(line->flags & ML_NOCLIMB) && // do translucent + if (!(line->args[4] & TMFT_DONTDOTRANSLUCENT) && // do translucent (rover->spawnflags & FF_NOSHADE) && // do not include light blocks, which don't set FF_NOSHADE !(rover->spawnflags & FF_RENDERSIDES) && !(rover->spawnflags & FF_RENDERPLANES) && @@ -3531,16 +3371,16 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) P_RemoveFakeFloorFader(rover); P_FadeFakeFloor(rover, rover->alpha, - max(1, min(256, (line->flags & ML_EFFECT3) ? rover->alpha + destvalue : destvalue)), - 0, // set alpha immediately - false, NULL, // tic-based logic - !(line->flags & ML_BLOCKMONSTERS), // do not handle FF_EXISTS - !(line->flags & ML_NOCLIMB), // do not handle FF_TRANSLUCENT - !(line->flags & ML_EFFECT2), // do not handle lighting - !(line->flags & ML_EFFECT2), // do not handle colormap (ran out of flags) - !(line->flags & ML_BOUNCY), // do not handle collision - (line->flags & ML_EFFECT1), // do ghost fade (no collision during fade) - (line->flags & ML_TFERLINE)); // use exact alpha values (for opengl) + max(1, min(256, (line->args[4] & TMFT_RELATIVE) ? rover->alpha + destvalue : destvalue)), + 0, // set alpha immediately + false, NULL, // tic-based logic + !(line->args[4] & TMFT_DONTDOEXISTS), // do not handle FF_EXISTS + !(line->args[4] & TMFT_DONTDOTRANSLUCENT), // do not handle FF_TRANSLUCENT + !(line->args[4] & TMFT_DONTDOLIGHTING), // do not handle lighting + !(line->args[4] & TMFT_DONTDOCOLORMAP), // do not handle colormap + !(line->args[4] & TMFT_IGNORECOLLISION), // do not handle collision + (line->args[4] & TMFT_GHOSTFADE), // do ghost fade (no collision during fade) + (line->args[4] & TMFT_USEEXACTALPHA)); // use exact alpha values (for opengl) } } j++; @@ -3557,13 +3397,13 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 454: // Stop fading FOF { - INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT16 sectag = (INT16)(line->args[0]); + INT16 foftag = (INT16)(line->args[1]); sector_t *sec; // Sector that the FOF is visible in ffloor_t *rover; // FOF that we are going to operate boolean foundrover = false; // for debug, "Can't find a FOF" message - TAG_ITER_SECTORS(0, sectag, secnum) + TAG_ITER_SECTORS(sectag, secnum) { sec = sectors + secnum; @@ -3580,7 +3420,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) foundrover = true; P_ResetFakeFloorFader(rover, NULL, - !(line->flags & ML_BLOCKMONSTERS)); // do not finalize collision flags + !(line->args[2])); // do not finalize collision flags } } @@ -3614,7 +3454,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } } - TAG_ITER_SECTORS(0, line->args[0], secnum) + TAG_ITER_SECTORS(line->args[0], secnum) { extracolormap_t *source_exc, *dest_exc, *exc; @@ -3694,24 +3534,20 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; } case 456: // Stop fade colormap - TAG_ITER_SECTORS(0, line->args[0], secnum) + TAG_ITER_SECTORS(line->args[0], secnum) P_ResetColormapFader(§ors[secnum]); break; case 457: // Track mobj angle to point if (mo) { - INT32 failureangle = FixedAngle((min(max(abs(sides[line->sidenum[0]].textureoffset>>FRACBITS), 0), 360))*FRACUNIT); - INT32 failuredelay = abs(sides[line->sidenum[0]].rowoffset>>FRACBITS); - INT32 failureexectag = line->sidenum[1] != 0xffff ? - (INT32)(sides[line->sidenum[1]].textureoffset>>FRACBITS) : 0; - boolean persist = (line->flags & ML_EFFECT2); + INT32 failureangle = FixedAngle((min(max(abs(line->args[1]), 0), 360))*FRACUNIT); + INT32 failuredelay = abs(line->args[2]); + INT32 failureexectag = line->args[3]; + boolean persist = !!(line->args[4]); mobj_t *anchormo; - if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) - return; - - anchormo = P_GetObjectTypeInSectorNum(MT_ANGLEMAN, secnum); + anchormo = P_FindObjectTypeFromTag(MT_ANGLEMAN, line->args[0]); if (!anchormo) return; @@ -3734,27 +3570,27 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 459: // Control Text Prompt - // console player only unless NOCLIMB is set + // console player only if (mo && mo->player && P_IsLocalPlayer(mo->player) && (!bot || bot != mo)) { - INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); - INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); - INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : tag); + INT32 promptnum = max(0, line->args[0] - 1); + INT32 pagenum = max(0, line->args[1] - 1); + INT32 postexectag = abs(line->args[3]); - boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); - //boolean allplayers = (line->flags & ML_NOCLIMB); - boolean runpostexec = (line->flags & ML_EFFECT1); - boolean blockcontrols = !(line->flags & ML_EFFECT2); - boolean freezerealtime = !(line->flags & ML_EFFECT3); - //boolean freezethinkers = (line->flags & ML_EFFECT4); - boolean callbynamedtag = (line->flags & ML_TFERLINE); + boolean closetextprompt = (line->args[2] & TMP_CLOSE); + //boolean allplayers = (line->args[2] & TMP_ALLPLAYERS); + boolean runpostexec = (line->args[2] & TMP_RUNPOSTEXEC); + boolean blockcontrols = !(line->args[2] & TMP_KEEPCONTROLS); + boolean freezerealtime = !(line->args[2] & TMP_KEEPREALTIME); + //boolean freezethinkers = (line->args[2] & TMP_FREEZETHINKERS); + boolean callbynamedtag = (line->args[2] & TMP_CALLBYNAME); if (closetextprompt) F_EndTextPrompt(false, false); else { - if (callbynamedtag && sides[line->sidenum[0]].text && sides[line->sidenum[0]].text[0]) - F_GetPromptPageByNamedTag(sides[line->sidenum[0]].text, &promptnum, &pagenum); + if (callbynamedtag && line->stringargs[0] && line->stringargs[0][0]) + F_GetPromptPageByNamedTag(line->stringargs[0], &promptnum, &pagenum); F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime); } } @@ -3762,8 +3598,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 460: // Award rings { - INT16 rings = (sides[line->sidenum[0]].textureoffset>>FRACBITS); - INT32 delay = (sides[line->sidenum[0]].rowoffset>>FRACBITS); + INT16 rings = line->args[0]; + INT32 delay = line->args[1]; if (mo && mo->player) { if (delay <= 0 || !(leveltime % delay)) @@ -3774,34 +3610,28 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 461: // Spawns an object on the map based on texture offsets { - const mobjtype_t type = (mobjtype_t)(sides[line->sidenum[0]].toptexture); + const mobjtype_t type = line->stringargs[0] ? get_number(line->stringargs[0]) : MT_NULL; mobj_t *mobj; fixed_t x, y, z; - x = sides[line->sidenum[0]].textureoffset; - y = sides[line->sidenum[0]].rowoffset; - z = line->frontsector->floorheight; - if (line->flags & ML_NOCLIMB) // If noclimb is set, spawn randomly within a range + if (line->args[4]) // If args[4] is set, spawn randomly within a range { - if (line->sidenum[1] != 0xffff) // Make sure the linedef has a back side - { - x = P_RandomRange(sides[line->sidenum[0]].textureoffset>>FRACBITS, sides[line->sidenum[1]].textureoffset>>FRACBITS)<sidenum[0]].rowoffset>>FRACBITS, sides[line->sidenum[1]].rowoffset>>FRACBITS)<frontsector->floorheight>>FRACBITS, line->frontsector->ceilingheight>>FRACBITS)<special); - break; - } + x = P_RandomRange(line->args[0], line->args[5])<args[1], line->args[6])<args[2], line->args[7])<args[0] << FRACBITS; + y = line->args[1] << FRACBITS; + z = line->args[2] << FRACBITS; } mobj = P_SpawnMobj(x, y, z, type); if (mobj) { - if (line->flags & ML_EFFECT1) - mobj->angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); + mobj->angle = FixedAngle(line->args[3] << FRACBITS); CONS_Debug(DBG_GAMELOGIC, "Linedef Type %d - Spawn Object: %d spawned at (%d, %d, %d)\n", line->special, mobj->type, mobj->x>>FRACBITS, mobj->y>>FRACBITS, mobj->z>>FRACBITS); //TODO: Convert mobj->type to a string somehow. } else @@ -3829,10 +3659,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 463: // Dye object { - INT32 color = sides[line->sidenum[0]].toptexture; - if (mo) { + INT32 color = line->stringargs[0] ? get_number(line->stringargs[0]) : SKINCOLOR_NONE; + if (color < 0 || color >= numskincolors) return; @@ -3845,31 +3675,28 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 464: // Trigger Egg Capsule { - thinker_t *th; + INT32 mtnum; mobj_t *mo2; // Find the center of the Eggtrap and release all the pretty animals! // The chimps are my friends.. heeheeheheehehee..... - LouisJM - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + TAG_ITER_THINGS(line->args[0], mtnum) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + mo2 = mapthings[mtnum].mobj; - mo2 = (mobj_t *)th; + if (!mo2) + continue; if (mo2->type != MT_EGGTRAP) continue; - if (!mo2->spawnpoint) - continue; - - if (mo2->spawnpoint->angle != tag) + if (mo2->thinker.function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; P_KillMobj(mo2, NULL, mo, 0); } - if (!(line->flags & ML_NOCLIMB)) + if (!(line->args[1])) { INT32 i; @@ -3887,12 +3714,11 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 465: // Set linedef executor delay { INT32 linenum; - TAG_ITER_DECLARECOUNTER(1); if (!udmf) break; - TAG_ITER_LINES(1, line->args[0], linenum) + TAG_ITER_LINES(line->args[0], linenum) { if (line->args[2]) lines[linenum].executordelay += line->args[1]; @@ -3902,28 +3728,121 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } break; + case 466: // Set level failure state + { + if (line->args[1]) + { + stagefailed = false; + CONS_Debug(DBG_GAMELOGIC, "Stage can be completed successfully!\n"); + } + else + { + stagefailed = true; + CONS_Debug(DBG_GAMELOGIC, "Stage will end in failure...\n"); + } + } + break; + + case 467: // Set light level + TAG_ITER_SECTORS(line->args[0], secnum) + { + if (sectors[secnum].lightingdata) + { + // Stop any lighting effects going on in the sector + P_RemoveThinker(&((thinkerdata_t *)sectors[secnum].lightingdata)->thinker); + sectors[secnum].lightingdata = NULL; + } + + if (line->args[2] == TML_FLOOR) + { + if (line->args[3]) + sectors[secnum].floorlightlevel += line->args[1]; + else + sectors[secnum].floorlightlevel = line->args[1]; + } + else if (line->args[2] == TML_CEILING) + { + if (line->args[3]) + sectors[secnum].ceilinglightlevel += line->args[1]; + else + sectors[secnum].ceilinglightlevel = line->args[1]; + } + else + { + if (line->args[3]) + sectors[secnum].lightlevel += line->args[1]; + else + sectors[secnum].lightlevel = line->args[1]; + sectors[secnum].lightlevel = max(0, min(255, sectors[secnum].lightlevel)); + } + } + break; + + case 468: // Change linedef executor argument + { + INT32 linenum; + + if (!udmf) + break; + + if (line->args[1] < 0 || line->args[1] >= NUMLINEARGS) + { + CONS_Debug(DBG_GAMELOGIC, "Linedef type 468: Invalid linedef arg %d\n", line->args[1]); + break; + } + + TAG_ITER_LINES(line->args[0], linenum) + { + if (line->args[3]) + lines[linenum].args[line->args[1]] += line->args[2]; + else + lines[linenum].args[line->args[1]] = line->args[2]; + } + } + break; + + case 469: // Change sector gravity + { + fixed_t gravityvalue; + + if (!udmf) + break; + + if (!line->stringargs[0]) + break; + + gravityvalue = FloatToFixed(atof(line->stringargs[0])); + + TAG_ITER_SECTORS(line->args[0], secnum) + { + if (line->args[1]) + sectors[secnum].gravity = FixedMul(sectors[secnum].gravity, gravityvalue); + else + sectors[secnum].gravity = gravityvalue; + + if (line->args[2] == TMF_ADD) + sectors[secnum].flags |= MSF_GRAVITYFLIP; + else if (line->args[2] == TMF_REMOVE) + sectors[secnum].flags &= ~MSF_GRAVITYFLIP; + } + } + break; + case 480: // Polyobj_DoorSlide case 481: // Polyobj_DoorSwing PolyDoor(line); break; case 482: // Polyobj_Move - case 483: // Polyobj_OR_Move PolyMove(line); break; case 484: // Polyobj_RotateRight - case 485: // Polyobj_OR_RotateRight - case 486: // Polyobj_RotateLeft - case 487: // Polyobj_OR_RotateLeft PolyRotate(line); break; case 488: // Polyobj_Waypoint PolyWaypoint(line); break; case 489: - PolyInvisible(line); - break; - case 490: - PolyVisible(line); + PolySetVisibilityTangibility(line); break; case 491: PolyTranslucency(line); @@ -4014,7 +3933,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag) { thinker_t *think; mobj_t *mo; - INT32 specialnum = (flag == MT_REDFLAG) ? 3 : 4; + sectorspecialflags_t specialflag = (flag == MT_REDFLAG) ? SSF_REDTEAMBASE : SSF_BLUETEAMBASE; for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next) { @@ -4026,7 +3945,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag) if (mo->type != flag) continue; - if (GETSECSPECIAL(mo->subsector->sector->special, 4) == specialnum) + if (mo->subsector->sector->specialflags & specialflag) return true; else if (mo->subsector->sector->ffloors) // Check the 3D floors { @@ -4037,7 +3956,7 @@ boolean P_IsFlagAtBase(mobjtype_t flag) if (!(rover->flags & FF_EXISTS)) continue; - if (GETSECSPECIAL(rover->master->frontsector->special, 4) != specialnum) + if (!(rover->master->frontsector->specialflags & specialflag)) continue; if (!(mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector) @@ -4051,6 +3970,235 @@ boolean P_IsFlagAtBase(mobjtype_t flag) return false; } +static boolean P_IsMobjTouchingPlane(mobj_t *mo, sector_t *sec, fixed_t floorz, fixed_t ceilingz) +{ + boolean floorallowed = ((sec->flags & MSF_FLIPSPECIAL_FLOOR) && ((sec->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == floorz)); + boolean ceilingallowed = ((sec->flags & MSF_FLIPSPECIAL_CEILING) && ((sec->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == ceilingz)); + return (floorallowed || ceilingallowed); +} + +boolean P_IsMobjTouchingSectorPlane(mobj_t *mo, sector_t *sec) +{ + return P_IsMobjTouchingPlane(mo, sec, P_GetSpecialBottomZ(mo, sec, sec), P_GetSpecialTopZ(mo, sec, sec)); +} + +boolean P_IsMobjTouching3DFloor(mobj_t *mo, ffloor_t *ffloor, sector_t *sec) +{ + fixed_t topheight = P_GetSpecialTopZ(mo, sectors + ffloor->secnum, sec); + fixed_t bottomheight = P_GetSpecialBottomZ(mo, sectors + ffloor->secnum, sec); + + if (((ffloor->flags & FF_BLOCKPLAYER) && mo->player) + || ((ffloor->flags & FF_BLOCKOTHERS) && !mo->player)) + { + // Solid 3D floor: Mobj must touch the top or bottom + return P_IsMobjTouchingPlane(mo, ffloor->master->frontsector, topheight, bottomheight); + } + else + { + // Water or intangible 3D floor: Mobj must be inside + return mo->z <= topheight && (mo->z + mo->height) >= bottomheight; + } +} + +boolean P_IsMobjTouchingPolyobj(mobj_t *mo, polyobj_t *po, sector_t *polysec) +{ + if (!(po->flags & POF_TESTHEIGHT)) // Don't do height checking + return true; + + if (po->flags & POF_SOLID) + { + // Solid polyobject: Player must touch the top or bottom + return P_IsMobjTouchingPlane(mo, polysec, polysec->ceilingheight, polysec->floorheight); + } + else + { + // Water or intangible polyobject: Player must be inside + return mo->z <= polysec->ceilingheight && (mo->z + mo->height) >= polysec->floorheight; + } +} + +static sector_t *P_MobjTouching3DFloorSpecial(mobj_t *mo, sector_t *sector, INT32 section, INT32 number) +{ + ffloor_t *rover; + + for (rover = sector->ffloors; rover; rover = rover->next) + { + if (GETSECSPECIAL(rover->master->frontsector->special, section) != number) + continue; + + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!P_IsMobjTouching3DFloor(mo, rover, sector)) + continue; + + // This FOF has the special we're looking for, but are we allowed to touch it? + if (sector == mo->subsector->sector + || (rover->master->frontsector->flags & MSF_TRIGGERSPECIAL_TOUCH)) + return rover->master->frontsector; + } + + return NULL; +} + +static sector_t *P_MobjTouching3DFloorSpecialFlag(mobj_t *mo, sector_t *sector, sectorspecialflags_t flag) +{ + ffloor_t *rover; + + for (rover = sector->ffloors; rover; rover = rover->next) + { + if (!(rover->master->frontsector->specialflags & flag)) + continue; + + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!P_IsMobjTouching3DFloor(mo, rover, sector)) + continue; + + // This FOF has the special we're looking for, but are we allowed to touch it? + if (sector == mo->subsector->sector + || (rover->master->frontsector->flags & MSF_TRIGGERSPECIAL_TOUCH)) + return rover->master->frontsector; + } + + return NULL; +} + +static sector_t *P_MobjTouchingPolyobjSpecial(mobj_t *mo, INT32 section, INT32 number) +{ + polyobj_t *po; + sector_t *polysec; + boolean touching = false; + boolean inside = false; + + for (po = mo->subsector->polyList; po; po = (polyobj_t *)(po->link.next)) + { + if (po->flags & POF_NOSPECIALS) + continue; + + polysec = po->lines[0]->backsector; + + if (GETSECSPECIAL(polysec->special, section) != number) + continue; + + touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, mo); + inside = P_MobjInsidePolyobj(po, mo); + + if (!(inside || touching)) + continue; + + if (!P_IsMobjTouchingPolyobj(mo, po, polysec)) + continue; + + return polysec; + } + + return NULL; +} + +static sector_t *P_MobjTouchingPolyobjSpecialFlag(mobj_t *mo, sectorspecialflags_t flag) +{ + polyobj_t *po; + sector_t *polysec; + boolean touching = false; + boolean inside = false; + + for (po = mo->subsector->polyList; po; po = (polyobj_t *)(po->link.next)) + { + if (po->flags & POF_NOSPECIALS) + continue; + + polysec = po->lines[0]->backsector; + + if (!(polysec->specialflags & flag)) + continue; + + touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, mo); + inside = P_MobjInsidePolyobj(po, mo); + + if (!(inside || touching)) + continue; + + if (!P_IsMobjTouchingPolyobj(mo, po, polysec)) + continue; + + return polysec; + } + + return NULL; +} + +sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number) +{ + msecnode_t *node; + sector_t *result; + + result = P_MobjTouching3DFloorSpecial(mo, mo->subsector->sector, section, number); + if (result) + return result; + + result = P_MobjTouchingPolyobjSpecial(mo, section, number); + if (result) + return result; + + if (GETSECSPECIAL(mo->subsector->sector->special, section) == number) + return mo->subsector->sector; + + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) + { + if (node->m_sector == mo->subsector->sector) // Don't duplicate + continue; + + result = P_MobjTouching3DFloorSpecial(mo, node->m_sector, section, number); + if (result) + return result; + + if (!(node->m_sector->flags & MSF_TRIGGERSPECIAL_TOUCH)) + continue; + + if (GETSECSPECIAL(node->m_sector->special, section) == number) + return node->m_sector; + } + + return NULL; +} + +sector_t *P_MobjTouchingSectorSpecialFlag(mobj_t *mo, sectorspecialflags_t flag) +{ + msecnode_t *node; + sector_t *result; + + result = P_MobjTouching3DFloorSpecialFlag(mo, mo->subsector->sector, flag); + if (result) + return result; + + result = P_MobjTouchingPolyobjSpecialFlag(mo, flag); + if (result) + return result; + + if (mo->subsector->sector->specialflags & flag) + return mo->subsector->sector; + + for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next) + { + if (node->m_sector == mo->subsector->sector) // Don't duplicate + continue; + + result = P_MobjTouching3DFloorSpecialFlag(mo, node->m_sector, flag); + if (result) + return result; + + if (!(node->m_sector->flags & MSF_TRIGGERSPECIAL_TOUCH)) + continue; + + if (node->m_sector->specialflags & flag) + return node->m_sector; + } + + return NULL; +} + // // P_PlayerTouchingSectorSpecial // @@ -4064,163 +4212,891 @@ boolean P_IsFlagAtBase(mobjtype_t flag) // sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 number) { - msecnode_t *node; - ffloor_t *rover; - if (!player->mo) return NULL; - // Check default case first - if (GETSECSPECIAL(player->mo->subsector->sector->special, section) == number) - return player->mo->subsector->sector; + return P_MobjTouchingSectorSpecial(player->mo, section, number); +} - // Hmm.. maybe there's a FOF that has it... - for (rover = player->mo->subsector->sector->ffloors; rover; rover = rover->next) +sector_t *P_PlayerTouchingSectorSpecialFlag(player_t *player, sectorspecialflags_t flag) +{ + if (!player->mo) + return NULL; + + return P_MobjTouchingSectorSpecialFlag(player->mo, flag); +} + +static sector_t *P_CheckPlayer3DFloorTrigger(player_t *player, sector_t *sector, line_t *sourceline) +{ + ffloor_t *rover; + + for (rover = sector->ffloors; rover; rover = rover->next) { - fixed_t topheight, bottomheight; + if (!rover->master->frontsector->triggertag) + continue; - if (GETSECSPECIAL(rover->master->frontsector->special, section) != number) + if (rover->master->frontsector->triggerer == TO_MOBJ) continue; if (!(rover->flags & FF_EXISTS)) continue; - topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector); - bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector); + if (!Tag_Find(&sourceline->tags, rover->master->frontsector->triggertag)) + continue; - // Check the 3D floor's type... - if (rover->flags & FF_BLOCKPLAYER) - { - boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight)); - boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight)); - // Thing must be on top of the floor to be affected... - if (!(floorallowed || ceilingallowed)) - continue; - } - else - { - // Water and DEATH FOG!!! heh - if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight) - continue; - } + if (!P_IsMobjTouching3DFloor(player->mo, rover, sector)) + continue; - // This FOF has the special we're looking for! - return rover->master->frontsector; - } - - for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (GETSECSPECIAL(node->m_sector->special, section) == number) - { - // This sector has the special we're looking for, but - // are we allowed to touch it? - if (node->m_sector == player->mo->subsector->sector - || (node->m_sector->flags & SF_TRIGGERSPECIAL_TOUCH)) - return node->m_sector; - } - - // Hmm.. maybe there's a FOF that has it... - for (rover = node->m_sector->ffloors; rover; rover = rover->next) - { - fixed_t topheight, bottomheight; - - if (GETSECSPECIAL(rover->master->frontsector->special, section) != number) - continue; - - if (!(rover->flags & FF_EXISTS)) - continue; - - topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector); - bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector); - - // Check the 3D floor's type... - if (rover->flags & FF_BLOCKPLAYER) - { - boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight)); - boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight)); - // Thing must be on top of the floor to be affected... - if (!(floorallowed || ceilingallowed)) - continue; - } - else - { - // Water and DEATH FOG!!! heh - if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight) - continue; - } - - // This FOF has the special we're looking for, but are we allowed to touch it? - if (node->m_sector == player->mo->subsector->sector - || (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH)) - return rover->master->frontsector; - } + // This FOF has the special we're looking for, but are we allowed to touch it? + if (sector == player->mo->subsector->sector + || (rover->master->frontsector->flags & MSF_TRIGGERSPECIAL_TOUCH)) + return rover->master->frontsector; } return NULL; } -// -// P_ThingIsOnThe3DFloor -// -// This checks whether the mobj is on/in the FOF we want it to be at -// Needed for the "All players" trigger sector specials only -// -static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *targetsec) +static sector_t *P_CheckPlayerPolyobjTrigger(player_t *player, line_t *sourceline) { - ffloor_t *rover; - fixed_t top, bottom; + polyobj_t *po; + sector_t *polysec; + boolean touching = false; + boolean inside = false; - if (!mo->player) // should NEVER happen - return false; - - if (!targetsec->ffloors) // also should NEVER happen - return false; - - for (rover = targetsec->ffloors; rover; rover = rover->next) + for (po = player->mo->subsector->polyList; po; po = (polyobj_t *)(po->link.next)) { - if (rover->master->frontsector != sector) + if (po->flags & POF_NOSPECIALS) continue; - // we're assuming the FOF existed when the first player touched it - //if (!(rover->flags & FF_EXISTS)) - // return false; + polysec = po->lines[0]->backsector; - top = P_GetSpecialTopZ(mo, sector, targetsec); - bottom = P_GetSpecialBottomZ(mo, sector, targetsec); + if (!polysec->triggertag) + continue; - // Check the 3D floor's type... - if (rover->flags & FF_BLOCKPLAYER) - { - boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == top)); - boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == bottom)); - // Thing must be on top of the floor to be affected... - if (!(floorallowed || ceilingallowed)) - continue; - } - else - { - // Water and intangible FOFs - if (mo->z > top || (mo->z + mo->height) < bottom) - return false; - } + if (polysec->triggerer == TO_MOBJ) + continue; - return true; + if (!Tag_Find(&sourceline->tags, polysec->triggertag)) + continue; + + touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, player->mo); + inside = P_MobjInsidePolyobj(po, player->mo); + + if (!(inside || touching)) + continue; + + if (!P_IsMobjTouchingPolyobj(player->mo, po, polysec)) + continue; + + return polysec; + } + + return NULL; +} + +static boolean P_CheckPlayerSectorTrigger(player_t *player, sector_t *sector, line_t *sourceline) +{ + if (!sector->triggertag) + return false; + + if (sector->triggerer == TO_MOBJ) + return false; + + if (!Tag_Find(&sourceline->tags, sector->triggertag)) + return false; + + if (!(sector->flags & MSF_TRIGGERLINE_PLANE)) + return true; // Don't require plane touch + + return P_IsMobjTouchingSectorPlane(player->mo, sector); + +} + +sector_t *P_FindPlayerTrigger(player_t *player, line_t *sourceline) +{ + sector_t *originalsector; + sector_t *loopsector; + msecnode_t *node; + sector_t *caller; + + if (!player->mo) + return NULL; + + originalsector = player->mo->subsector->sector; + + caller = P_CheckPlayer3DFloorTrigger(player, originalsector, sourceline); // Handle FOFs first. + + if (caller) + return caller; + + // Allow sector specials to be applied to polyobjects! + caller = P_CheckPlayerPolyobjTrigger(player, sourceline); + + if (caller) + return caller; + + if (P_CheckPlayerSectorTrigger(player, originalsector, sourceline)) + return originalsector; + + // Iterate through touching_sectorlist for SF_TRIGGERSPECIAL_TOUCH + for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) + { + loopsector = node->m_sector; + + if (loopsector == originalsector) // Don't duplicate + continue; + + // Check 3D floors... + caller = P_CheckPlayer3DFloorTrigger(player, loopsector, sourceline); // Handle FOFs first. + + if (caller) + return caller; + + if (!(loopsector->flags & MSF_TRIGGERSPECIAL_TOUCH)) + continue; + + if (P_CheckPlayerSectorTrigger(player, loopsector, sourceline)) + return loopsector; } return false; } -// -// P_MobjReadyToTrigger -// -// Is player standing on the sector's "ground"? -// -static boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec) +boolean P_IsPlayerValid(size_t playernum) { - boolean floorallowed = ((sec->flags & SF_FLIPSPECIAL_FLOOR) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == P_GetSpecialBottomZ(mo, sec, sec))); - boolean ceilingallowed = ((sec->flags & SF_FLIPSPECIAL_CEILING) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == P_GetSpecialTopZ(mo, sec, sec))); - // Thing must be on top of the floor to be affected... - return (floorallowed || ceilingallowed); + if (!playeringame[playernum]) + return false; + + if (!players[playernum].mo) + return false; + + if (players[playernum].mo->health <= 0) + return false; + + if (players[playernum].spectator) + return false; + + return true; +} + +boolean P_CanPlayerTrigger(size_t playernum) +{ + return P_IsPlayerValid(playernum) && !players[playernum].bot; +} + +/// \todo check continues for proper splitscreen support? +static boolean P_DoAllPlayersTrigger(mtag_t triggertag) +{ + INT32 i; + line_t dummyline; + dummyline.tags.count = 1; + dummyline.tags.tags = &triggertag; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!P_CanPlayerTrigger(i)) + continue; + if (!P_FindPlayerTrigger(&players[i], &dummyline)) + return false; + } + + return true; +} + +static void P_ProcessEggCapsule(player_t *player, sector_t *sector) +{ + thinker_t *th; + mobj_t *mo2; + INT32 i; + + if (player->bot || sector->ceilingdata || sector->floordata) + return; + + // Find the center of the Eggtrap and release all the pretty animals! + // The chimps are my friends.. heeheeheheehehee..... - LouisJM + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + mo2 = (mobj_t *)th; + if (mo2->type != MT_EGGTRAP) + continue; + P_KillMobj(mo2, NULL, player->mo, 0); + } + + // clear the special so you can't push the button twice. + sector->special = 0; + + // Move the button down + EV_DoElevator(LE_CAPSULE0, NULL, elevateDown); + + // Open the top FOF + EV_DoFloor(LE_CAPSULE1, NULL, raiseFloorToNearestFast); + // Open the bottom FOF + EV_DoCeiling(LE_CAPSULE2, NULL, lowerToLowestFast); + + // Mark all players with the time to exit thingy! + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + P_DoPlayerExit(&players[i]); + } +} + +static void P_ProcessSpeedPad(player_t *player, sector_t *sector, sector_t *roversector, mtag_t sectag) +{ + INT32 lineindex = -1; + angle_t lineangle; + fixed_t linespeed; + fixed_t sfxnum; + size_t i; + + if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2) + return; + + // Try for lines facing the sector itself, with tag 0. + for (i = 0; i < sector->linecount; i++) + { + line_t *li = sector->lines[i]; + + if (li->frontsector != sector) + continue; + + if (li->special != 4) + continue; + + if (!Tag_Find(&li->tags, 0)) + continue; + + lineindex = li - lines; + break; + } + + // Nothing found? Look via tag. + if (lineindex == -1) + lineindex = Tag_FindLineSpecial(4, sectag); + + if (lineindex == -1) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad missing line special #4.\n"); + return; + } + + lineangle = R_PointToAngle2(lines[lineindex].v1->x, lines[lineindex].v1->y, lines[lineindex].v2->x, lines[lineindex].v2->y); + linespeed = lines[lineindex].args[0] << FRACBITS; + + if (linespeed == 0) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sectag); + return; + } + + player->mo->angle = player->drawangle = lineangle; + + if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) + P_SetPlayerAngle(player, player->mo->angle); + + if (!(lines[lineindex].args[1] & TMSP_NOTELEPORT)) + { + P_UnsetThingPosition(player->mo); + if (roversector) // make FOF speed pads work + { + player->mo->x = roversector->soundorg.x; + player->mo->y = roversector->soundorg.y; + } + else + { + player->mo->x = sector->soundorg.x; + player->mo->y = sector->soundorg.y; + } + P_SetThingPosition(player->mo); + } + + P_InstaThrust(player->mo, player->mo->angle, linespeed); + + if (lines[lineindex].args[1] & TMSP_FORCESPIN) // Roll! + { + if (!(player->pflags & PF_SPINNING)) + player->pflags |= PF_SPINNING; + + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + } + + player->powers[pw_flashing] = TICRATE/3; + + sfxnum = lines[lineindex].stringargs[0] ? get_number(lines[lineindex].stringargs[0]) : sfx_spdpad; + + if (!sfxnum) + sfxnum = sfx_spdpad; + + S_StartSound(player->mo, sfxnum); +} + +static void P_ProcessSpecialStagePit(player_t* player) +{ + if (!(gametyperules & GTR_ALLOWEXIT)) + return; + + if (player->bot) + return; + + if (!G_IsSpecialStage(gamemap)) + return; + + if (maptol & TOL_NIGHTS) + return; + + if (player->nightstime <= 6) + return; + + player->nightstime = 6; // Just let P_Ticker take care of the rest. +} + +static void P_ProcessExitSector(player_t *player, mtag_t sectag) +{ + INT32 lineindex; + + if (!(gametyperules & GTR_ALLOWEXIT)) + return; + + if (player->bot) + return; + + // Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c) + P_DoPlayerFinish(player); + + P_SetupSignExit(player); + + if (!G_CoopGametype()) + return; + + // Custom exit! + // important: use sectag on next line instead of player->mo->subsector->tag + // this part is different from in P_PlayerThink, this is what was causing + // FOF custom exits not to work. + lineindex = Tag_FindLineSpecial(2, sectag); + + if (lineindex == -1) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Exit sector missing line special #2.\n"); + return; + } + + // Special goodies depending on emeralds collected + if ((lines[lineindex].args[1] & TMEF_EMERALDCHECK) && ALL7EMERALDS(emeralds)) + nextmapoverride = (INT16)(udmf ? lines[lineindex].args[2] : lines[lineindex].frontsector->ceilingheight>>FRACBITS); + else + nextmapoverride = (INT16)(udmf ? lines[lineindex].args[0] : lines[lineindex].frontsector->floorheight>>FRACBITS); + + if (lines[lineindex].args[1] & TMEF_SKIPTALLY) + skipstats = 1; +} + +static void P_ProcessTeamBase(player_t *player, boolean redteam) +{ + mobj_t *mo; + + if (!(gametyperules & GTR_TEAMFLAGS)) + return; + + if (!P_IsObjectOnGround(player->mo)) + return; + + if (player->ctfteam != (redteam ? 1 : 2)) + return; + + if (!(player->gotflag & (redteam ? GF_BLUEFLAG : GF_REDFLAG))) + return; + + // Make sure the team still has their own + // flag at their base so they can score. + if (!P_IsFlagAtBase(redteam ? MT_BLUEFLAG : MT_REDFLAG)) + return; + + HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE); + HU_SetCEchoDuration(5); + HU_DoCEcho(va(M_GetText("%s%s\200\\CAPTURED THE %s%s FLAG\200.\\\\\\\\"), redteam ? "\205" : "\204", player_names[player-players], redteam ? "\204" : "\205", redteam ? "BLUE" : "RED")); + + if (splitscreen || players[consoleplayer].ctfteam == (redteam ? 1 : 2)) + S_StartSound(NULL, sfx_flgcap); + else if (players[consoleplayer].ctfteam == (redteam ? 2 : 1)) + S_StartSound(NULL, sfx_lose); + + mo = P_SpawnMobj(player->mo->x,player->mo->y,player->mo->z, redteam ? MT_BLUEFLAG : MT_REDFLAG); + player->gotflag &= ~(redteam ? GF_BLUEFLAG : GF_REDFLAG); + mo->flags &= ~MF_SPECIAL; + mo->fuse = TICRATE; + mo->spawnpoint = redteam ? bflagpoint : rflagpoint; + mo->flags2 |= MF2_JUSTATTACKED; + if (redteam) + redscore += 1; + else + bluescore += 1; + P_AddPlayerScore(player, 250); +} + +static void P_ProcessZoomTube(player_t *player, mtag_t sectag, boolean end) +{ + INT32 sequence; + fixed_t speed; + INT32 lineindex; + mobj_t *waypoint = NULL; + angle_t an; + + if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ZOOMTUBE) + return; + + if (player->powers[pw_ignorelatch] & (1<<15)) + return; + + // Find line #3 tagged to this sector + lineindex = Tag_FindLineSpecial(3, sectag); + + if (lineindex == -1) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Zoom tube missing line special #3.\n"); + return; + } + + // Grab speed and sequence values + speed = abs(lines[lineindex].args[0])<<(FRACBITS-3); + if (end) + speed *= -1; + sequence = abs(lines[lineindex].args[1]); + + if (speed == 0) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence); + return; + } + + waypoint = end ? P_GetLastWaypoint(sequence) : P_GetFirstWaypoint(sequence); + + if (!waypoint) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: %s WAYPOINT IN SEQUENCE %d NOT FOUND.\n", end ? "LAST" : "FIRST", sequence); + return; + } + + CONS_Debug(DBG_GAMELOGIC, "Waypoint %d found in sequence %d - speed = %d\n", waypoint->health, sequence, speed); + + an = R_PointToAngle2(player->mo->x, player->mo->y, waypoint->x, waypoint->y) - player->mo->angle; + + if (an > ANGLE_90 && an < ANGLE_270 && !(lines[lineindex].args[2])) + return; // behind back + + P_SetTarget(&player->mo->tracer, waypoint); + player->powers[pw_carry] = CR_ZOOMTUBE; + player->speed = speed; + player->pflags |= PF_SPINNING; + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); + player->climbing = 0; + + if (player->mo->state-states != S_PLAY_ROLL) + { + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartSound(player->mo, sfx_spin); + } +} + +static void P_ProcessFinishLine(player_t *player) +{ + if ((gametyperules & (GTR_RACE|GTR_LIVES)) != GTR_RACE) + return; + + if (player->exiting) + return; + + if (player->starpostnum == numstarposts) // Must have touched all the starposts + { + player->laps++; + + if (player->powers[pw_carry] == CR_NIGHTSMODE) + player->drillmeter += 48*20; + + if (player->laps >= (UINT8)cv_numlaps.value) + CONS_Printf(M_GetText("%s has finished the race.\n"), player_names[player-players]); + else if (player->laps == (UINT8)cv_numlaps.value-1) + CONS_Printf(M_GetText("%s started the \205final lap\200!\n"), player_names[player-players]); + else + CONS_Printf(M_GetText("%s started lap %u\n"), player_names[player-players], (UINT32)player->laps+1); + + // Reset starposts (checkpoints) info + player->starpostscale = player->starpostangle = player->starposttime = player->starpostnum = 0; + player->starpostx = player->starposty = player->starpostz = 0; + P_ResetStarposts(); + + // Play the starpost sound for 'consistency' + S_StartSound(player->mo, sfx_strpst); + } + else if (player->starpostnum) + { + // blatant reuse of a variable that's normally unused in circuit + if (!player->tossdelay) + S_StartSound(player->mo, sfx_lose); + player->tossdelay = 3; + } + + if (player->laps >= (unsigned)cv_numlaps.value) + { + if (P_IsLocalPlayer(player)) + { + HU_SetCEchoFlags(0); + HU_SetCEchoDuration(5); + HU_DoCEcho("FINISHED!"); + } + + P_DoPlayerExit(player); + } +} + +static void P_ProcessRopeHang(player_t *player, mtag_t sectag) +{ + INT32 sequence; + fixed_t speed; + INT32 lineindex; + mobj_t *waypointmid = NULL; + mobj_t *waypointhigh = NULL; + mobj_t *waypointlow = NULL; + mobj_t *closest = NULL; + vector3_t p, line[2], resulthigh, resultlow; + + if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ROPEHANG) + return; + + if (player->powers[pw_ignorelatch] & (1<<15)) + return; + + if (player->mo->momz > 0) + return; + + if (player->cmd.buttons & BT_SPIN) + return; + + if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate]) + return; + + if (player->exiting) + return; + + //initialize resulthigh and resultlow with 0 + memset(&resultlow, 0x00, sizeof(resultlow)); + memset(&resulthigh, 0x00, sizeof(resulthigh)); + + // Find line #11 tagged to this sector + lineindex = Tag_FindLineSpecial(11, sectag); + + if (lineindex == -1) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Rope hang missing line special #11.\n"); + return; + } + + // Grab speed and sequence values + speed = abs(lines[lineindex].args[0]) << (FRACBITS - 3); + sequence = abs(lines[lineindex].args[1]); + + // Find the closest waypoint + // Find the preceding waypoint + // Find the proceeding waypoint + // Determine the closest spot on the line between the three waypoints + // Put player at that location. + + waypointmid = P_GetClosestWaypoint(sequence, player->mo); + + if (!waypointmid) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: WAYPOINT(S) IN SEQUENCE %d NOT FOUND.\n", sequence); + return; + } + + waypointlow = P_GetPreviousWaypoint(waypointmid, true); + waypointhigh = P_GetNextWaypoint(waypointmid, true); + + CONS_Debug(DBG_GAMELOGIC, "WaypointMid: %d; WaypointLow: %d; WaypointHigh: %d\n", + waypointmid->health, waypointlow ? waypointlow->health : -1, waypointhigh ? waypointhigh->health : -1); + + // Now we have three waypoints... the closest one we're near, and the one that comes before, and after. + // Next, we need to find the closest point on the line between each set, and determine which one we're + // closest to. + + p.x = player->mo->x; + p.y = player->mo->y; + p.z = player->mo->z; + + // Waypointmid and Waypointlow: + if (waypointlow) + { + line[0].x = waypointmid->x; + line[0].y = waypointmid->y; + line[0].z = waypointmid->z; + line[1].x = waypointlow->x; + line[1].y = waypointlow->y; + line[1].z = waypointlow->z; + + P_ClosestPointOnLine3D(&p, line, &resultlow); + } + + // Waypointmid and Waypointhigh: + if (waypointhigh) + { + line[0].x = waypointmid->x; + line[0].y = waypointmid->y; + line[0].z = waypointmid->z; + line[1].x = waypointhigh->x; + line[1].y = waypointhigh->y; + line[1].z = waypointhigh->z; + + P_ClosestPointOnLine3D(&p, line, &resulthigh); + } + + // 3D support now available. Disregard the previous notice here. -Red + + P_UnsetThingPosition(player->mo); + P_ResetPlayer(player); + player->mo->momx = player->mo->momy = player->mo->momz = 0; + + if (lines[lineindex].args[2]) // Don't wrap + { + mobj_t *highest = P_GetLastWaypoint(sequence); + highest->flags |= MF_SLIDEME; + } + + // Changing the conditions on these ifs to fix issues with snapping to the wrong spot -Red + if ((lines[lineindex].args[2]) && waypointmid->health == 0) + { + closest = waypointhigh; + player->mo->x = resulthigh.x; + player->mo->y = resulthigh.y; + player->mo->z = resulthigh.z - P_GetPlayerHeight(player); + } + else if ((lines[lineindex].args[2]) && waypointmid->health == numwaypoints[sequence] - 1) + { + closest = waypointmid; + player->mo->x = resultlow.x; + player->mo->y = resultlow.y; + player->mo->z = resultlow.z - P_GetPlayerHeight(player); + } + else + { + if (P_AproxDistance(P_AproxDistance(player->mo->x-resultlow.x, player->mo->y-resultlow.y), + player->mo->z-resultlow.z) < P_AproxDistance(P_AproxDistance(player->mo->x-resulthigh.x, + player->mo->y-resulthigh.y), player->mo->z-resulthigh.z)) + { + // Line between Mid and Low is closer + closest = waypointmid; + player->mo->x = resultlow.x; + player->mo->y = resultlow.y; + player->mo->z = resultlow.z - P_GetPlayerHeight(player); + } + else + { + // Line between Mid and High is closer + closest = waypointhigh; + player->mo->x = resulthigh.x; + player->mo->y = resulthigh.y; + player->mo->z = resulthigh.z - P_GetPlayerHeight(player); + } + } + + P_SetTarget(&player->mo->tracer, closest); + player->powers[pw_carry] = CR_ROPEHANG; + player->speed = speed; + + S_StartSound(player->mo, sfx_s3k4a); + + player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); + player->climbing = 0; + P_SetThingPosition(player->mo); + P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); +} + +static boolean P_SectorHasSpecial(sector_t *sec) +{ + if (sec->specialflags) + return true; + + if (sec->damagetype != SD_NONE) + return true; + + if (sec->triggertag) + return true; + + if (sec->special) + return true; + + return false; +} + +static void P_EvaluateSpecialFlags(player_t *player, sector_t *sector, sector_t *roversector, boolean isTouching) +{ + mtag_t sectag = Tag_FGet(§or->tags); + + if (sector->specialflags & SSF_OUTERSPACE) + { + if (!(player->powers[pw_shield] & SH_PROTECTWATER) && !player->powers[pw_spacetime]) + player->powers[pw_spacetime] = spacetimetics + 1; + } + if (sector->specialflags & SSF_WINDCURRENT) + player->onconveyor = 2; + if (sector->specialflags & SSF_CONVEYOR) + player->onconveyor = 4; + if ((sector->specialflags & SSF_SPEEDPAD) && isTouching) + P_ProcessSpeedPad(player, sector, roversector, sectag); + if (sector->specialflags & SSF_STARPOSTACTIVATOR) + { + mobj_t *post = P_GetObjectTypeInSectorNum(MT_STARPOST, sector - sectors); + if (post) + P_TouchStarPost(post, player, false); + } + if (sector->specialflags & SSF_EXIT) + P_ProcessExitSector(player, sectag); + if ((sector->specialflags & SSF_SPECIALSTAGEPIT) && isTouching) + P_ProcessSpecialStagePit(player); + if ((sector->specialflags & SSF_REDTEAMBASE) && isTouching) + P_ProcessTeamBase(player, true); + if ((sector->specialflags & SSF_BLUETEAMBASE) && isTouching) + P_ProcessTeamBase(player, false); + if (sector->specialflags & SSF_FAN) + { + player->mo->momz += mobjinfo[MT_FAN].mass/4; + + if (player->mo->momz > mobjinfo[MT_FAN].mass) + player->mo->momz = mobjinfo[MT_FAN].mass; + + P_ResetPlayer(player); + if (player->panim != PA_FALL) + P_SetPlayerMobjState(player->mo, S_PLAY_FALL); + } + if (sector->specialflags & SSF_SUPERTRANSFORM) + { + if (player->mo->health > 0 && !player->bot && (player->charflags & SF_SUPER) && !player->powers[pw_super] && ALL7EMERALDS(emeralds)) + P_DoSuperTransformation(player, true); + } + if ((sector->specialflags & SSF_FORCESPIN) && isTouching) + { + if (!(player->pflags & PF_SPINNING)) + { + player->pflags |= PF_SPINNING; + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + S_StartAttackSound(player->mo, sfx_spin); + + if (abs(player->rmomx) < FixedMul(5*FRACUNIT, player->mo->scale) + && abs(player->rmomy) < FixedMul(5*FRACUNIT, player->mo->scale)) + P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale)); + } + } + if (sector->specialflags & SSF_ZOOMTUBESTART) + P_ProcessZoomTube(player, sectag, false); + if (sector->specialflags & SSF_ZOOMTUBEEND) + P_ProcessZoomTube(player, sectag, true); + if (sector->specialflags & SSF_FINISHLINE) + P_ProcessFinishLine(player); + if ((sector->specialflags & SSF_ROPEHANG) && isTouching) + P_ProcessRopeHang(player, sectag); +} + +static void P_EvaluateDamageType(player_t *player, sector_t *sector, boolean isTouching) +{ + switch (sector->damagetype) + { + case SD_GENERIC: + if (isTouching) + P_DamageMobj(player->mo, NULL, NULL, 1, 0); + break; + case SD_WATER: + if (isTouching && (player->powers[pw_underwater] || player->powers[pw_carry] == CR_NIGHTSMODE)) + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_WATER); + break; + case SD_FIRE: + case SD_LAVA: + if (isTouching) + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_FIRE); + break; + case SD_ELECTRIC: + if (isTouching) + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_ELECTRIC); + break; + case SD_SPIKE: + if (isTouching) + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_SPIKE); + break; + case SD_DEATHPITTILT: + case SD_DEATHPITNOTILT: + if (!isTouching) + break; + if (player->quittime) + G_MovePlayerToSpawnOrStarpost(player - players); + else + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT); + break; + case SD_INSTAKILL: + if (player->quittime) + G_MovePlayerToSpawnOrStarpost(player - players); + else + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); + break; + case SD_SPECIALSTAGE: + if (!isTouching) + break; + + if (player->exiting || player->bot) // Don't do anything for bots or players who have just finished + break; + + if (!(player->powers[pw_shield] || player->spheres > 0)) // Don't do anything if no shield or spheres anyway + break; + + P_SpecialStageDamage(player, NULL, NULL); + break; + default: + break; + } +} + +static void P_EvaluateLinedefExecutorTrigger(player_t *player, sector_t *sector, boolean isTouching) +{ + if (player->bot) + return; + + if (!sector->triggertag) + return; + + if (sector->triggerer == TO_MOBJ) + return; + else if (sector->triggerer == TO_ALLPLAYERS && !P_DoAllPlayersTrigger(sector->triggertag)) + return; + + if ((sector->flags & MSF_TRIGGERLINE_PLANE) && !isTouching) + return; + + P_LinedefExecute(sector->triggertag, player->mo, sector); +} + +static void P_EvaluateOldSectorSpecial(player_t *player, sector_t *sector, sector_t *roversector, boolean isTouching) +{ + switch (GETSECSPECIAL(sector->special, 1)) + { + case 9: // Ring Drainer (Floor Touch) + if (!isTouching) + break; + /* FALLTHRU */ + case 10: // Ring Drainer (No Floor Touch) + if (leveltime % (TICRATE/2) == 0 && player->rings > 0) + { + player->rings--; + S_StartSound(player->mo, sfx_antiri); + } + break; + } + + switch (GETSECSPECIAL(sector->special, 2)) + { + case 9: // Egg trap capsule + if (roversector) + P_ProcessEggCapsule(player, sector); + break; + } } /** Applies a sector special to a player. @@ -4229,20 +5105,14 @@ static boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec) * \param sector Sector with the special. * \param roversector If !NULL, sector is actually an FOF; otherwise, sector * is being physically contacted by the player. - * \todo Split up into multiple functions. * \sa P_PlayerInSpecialSector, P_PlayerOnSpecial3DFloor */ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *roversector) { - INT32 i = 0; - INT32 section1, section2, section3, section4; - INT32 special; - mtag_t sectag = Tag_FGet(§or->tags); + boolean isTouching; - section1 = GETSECSPECIAL(sector->special, 1); - section2 = GETSECSPECIAL(sector->special, 2); - section3 = GETSECSPECIAL(sector->special, 3); - section4 = GETSECSPECIAL(sector->special, 4); + if (!P_SectorHasSpecial(sector)) + return; // Ignore spectators if (player->spectator) @@ -4254,849 +5124,17 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers if (player->playerstate != PST_LIVE) return; - // Conveyor stuff - if (section3 == 2 || section3 == 4) - player->onconveyor = section3; + isTouching = roversector || P_IsMobjTouchingSectorPlane(player->mo, sector); - special = section1; + P_EvaluateSpecialFlags(player, sector, roversector, isTouching); + P_EvaluateDamageType(player, sector, isTouching); + P_EvaluateLinedefExecutorTrigger(player, sector, isTouching); - // Process Section 1 - switch (special) - { - case 1: // Damage (Generic) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - P_DamageMobj(player->mo, NULL, NULL, 1, 0); - break; - case 2: // Damage (Water) - if ((roversector || P_MobjReadyToTrigger(player->mo, sector)) && (player->powers[pw_underwater] || player->powers[pw_carry] == CR_NIGHTSMODE)) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_WATER); - break; - case 3: // Damage (Fire) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_FIRE); - break; - case 4: // Damage (Electrical) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_ELECTRIC); - break; - case 5: // Spikes - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_SPIKE); - break; - case 6: // Death Pit (Camera Mod) - case 7: // Death Pit (No Camera Mod) - if (roversector || P_MobjReadyToTrigger(player->mo, sector)) - { - if (player->quittime) - G_MovePlayerToSpawnOrStarpost(player - players); - else - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_DEATHPIT); - } - break; - case 8: // Instant Kill - if (player->quittime) - G_MovePlayerToSpawnOrStarpost(player - players); - else - P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); - break; - case 9: // Ring Drainer (Floor Touch) - case 10: // Ring Drainer (No Floor Touch) - if (leveltime % (TICRATE/2) == 0 && player->rings > 0) - { - player->rings--; - S_StartSound(player->mo, sfx_itemup); - } - break; - case 11: // Special Stage Damage - if (player->exiting || player->bot) // Don't do anything for bots or players who have just finished - break; - - if (!(player->powers[pw_shield] || player->spheres > 0)) // Don't do anything if no shield or spheres anyway - break; - - P_SpecialStageDamage(player, NULL, NULL); - break; - case 12: // Space Countdown - if (!(player->powers[pw_shield] & SH_PROTECTWATER) && !player->powers[pw_spacetime]) - player->powers[pw_spacetime] = spacetimetics + 1; - break; - case 13: // Ramp Sector (Increase step-up/down) - case 14: // Non-Ramp Sector (Don't step-down) - case 15: // Bouncy Sector (FOF Control Only) - break; - } - - special = section2; - - // Process Section 2 - switch (special) - { - case 1: // Trigger Linedef Exec (Pushable Objects) - break; - case 2: // Linedef executor requires all players present+doesn't require touching floor - case 3: // Linedef executor requires all players present - /// \todo check continues for proper splitscreen support? - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - if (!players[i].mo) - continue; - if (players[i].spectator) - continue; - if (players[i].bot) - continue; - if (G_CoopGametype() && players[i].lives <= 0) - continue; - if (roversector) - { - if (sector->flags & SF_TRIGGERSPECIAL_TOUCH) - { - msecnode_t *node; - for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (P_ThingIsOnThe3DFloor(players[i].mo, sector, node->m_sector)) - break; - } - if (!node) - goto DoneSection2; - } - else if (players[i].mo->subsector && !P_ThingIsOnThe3DFloor(players[i].mo, sector, players[i].mo->subsector->sector)) // this function handles basically everything for us lmao - goto DoneSection2; - } - else - { - if (players[i].mo->subsector->sector == sector) - ; - else if (sector->flags & SF_TRIGGERSPECIAL_TOUCH) - { - msecnode_t *node; - for (node = players[i].mo->touching_sectorlist; node; node = node->m_sectorlist_next) - { - if (node->m_sector == sector) - break; - } - if (!node) - goto DoneSection2; - } - else - goto DoneSection2; - - if (special == 3 && !P_MobjReadyToTrigger(players[i].mo, sector)) - goto DoneSection2; - } - } - /* FALLTHRU */ - case 4: // Linedef executor that doesn't require touching floor - case 5: // Linedef executor - case 6: // Linedef executor (7 Emeralds) - case 7: // Linedef executor (NiGHTS Mare) - if (!player->bot) - P_LinedefExecute(sectag, player->mo, sector); - break; - case 8: // Tells pushable things to check FOFs - break; - case 9: // Egg trap capsule - { - thinker_t *th; - mobj_t *mo2; - line_t junk; - - if (player->bot || sector->ceilingdata || sector->floordata) - return; - - // Find the center of the Eggtrap and release all the pretty animals! - // The chimps are my friends.. heeheeheheehehee..... - LouisJM - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - mo2 = (mobj_t *)th; - if (mo2->type != MT_EGGTRAP) - continue; - P_KillMobj(mo2, NULL, player->mo, 0); - } - - // clear the special so you can't push the button twice. - sector->special = 0; - - // Initialize my junk - junk.tags.tags = NULL; - junk.tags.count = 0; - - // Move the button down - Tag_FSet(&junk.tags, LE_CAPSULE0); - EV_DoElevator(&junk, elevateDown, false); - - // Open the top FOF - Tag_FSet(&junk.tags, LE_CAPSULE1); - EV_DoFloor(&junk, raiseFloorToNearestFast); - // Open the bottom FOF - Tag_FSet(&junk.tags, LE_CAPSULE2); - EV_DoCeiling(&junk, lowerToLowestFast); - - // Mark all players with the time to exit thingy! - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - P_DoPlayerExit(&players[i]); - } - break; - } - case 10: // Special Stage Time/Rings - case 11: // Custom Gravity - break; - case 12: // Lua sector special - break; - } -DoneSection2: - - special = section3; - - // Process Section 3 - switch (special) - { - case 1: // Unused - case 2: // Wind/Current - case 3: // Unused - case 4: // Conveyor Belt - break; - - case 5: // Speed pad - if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2) - break; - - i = Tag_FindLineSpecial(4, sectag); - - if (i != -1) - { - angle_t lineangle; - fixed_t linespeed; - fixed_t sfxnum; - - lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); - linespeed = sides[lines[i].sidenum[0]].textureoffset; - - if (linespeed == 0) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sectag); - break; - } - - player->mo->angle = player->drawangle = lineangle; - - if (!demoplayback || P_ControlStyle(player) == CS_LMAOGALOG) - P_SetPlayerAngle(player, player->mo->angle); - - if (!(lines[i].flags & ML_EFFECT4)) - { - P_UnsetThingPosition(player->mo); - if (roversector) // make FOF speed pads work - { - player->mo->x = roversector->soundorg.x; - player->mo->y = roversector->soundorg.y; - } - else - { - player->mo->x = sector->soundorg.x; - player->mo->y = sector->soundorg.y; - } - P_SetThingPosition(player->mo); - } - - P_InstaThrust(player->mo, player->mo->angle, linespeed); - - if (lines[i].flags & ML_EFFECT5) // Roll! - { - if (!(player->pflags & PF_SPINNING)) - player->pflags |= PF_SPINNING; - - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - } - - player->powers[pw_flashing] = TICRATE/3; - - sfxnum = sides[lines[i].sidenum[0]].toptexture; - - if (!sfxnum) - sfxnum = sfx_spdpad; - - S_StartSound(player->mo, sfxnum); - } - break; - - case 6: // Unused - case 7: // Unused - case 8: // Unused - case 9: // Unused - case 10: // Unused - case 11: // Unused - case 12: // Unused - case 13: // Unused - case 14: // Unused - case 15: // Unused - break; - } - - special = section4; - - // Process Section 4 - switch (special) - { - case 1: // Starpost Activator - { - mobj_t *post = P_GetObjectTypeInSectorNum(MT_STARPOST, sector - sectors); - - if (!post) - break; - - P_TouchStarPost(post, player, false); - break; - } - - case 2: // Special stage GOAL sector / Exit Sector / CTF Flag Return - if (player->bot || !(gametyperules & GTR_ALLOWEXIT)) - break; - if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6) - { - player->nightstime = 6; // Just let P_Ticker take care of the rest. - return; - } - - // Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c) - { - INT32 lineindex; - - P_DoPlayerFinish(player); - - P_SetupSignExit(player); - // important: use sector->tag on next line instead of player->mo->subsector->tag - // this part is different from in P_PlayerThink, this is what was causing - // FOF custom exits not to work. - lineindex = Tag_FindLineSpecial(2, sectag); - - if (G_CoopGametype() && lineindex != -1) // Custom exit! - { - // Special goodies with the block monsters flag depending on emeralds collected - if ((lines[lineindex].flags & ML_BLOCKMONSTERS) && ALL7EMERALDS(emeralds)) - nextmapoverride = (INT16)(lines[lineindex].frontsector->ceilingheight>>FRACBITS); - else - nextmapoverride = (INT16)(lines[lineindex].frontsector->floorheight>>FRACBITS); - - if (lines[lineindex].flags & ML_NOCLIMB) - skipstats = 1; - } - } - break; - - case 3: // Red Team's Base - if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo)) - { - if (player->ctfteam == 1 && (player->gotflag & GF_BLUEFLAG)) - { - mobj_t *mo; - - // Make sure the red team still has their own - // flag at their base so they can score. - if (!P_IsFlagAtBase(MT_REDFLAG)) - break; - - HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE); - HU_SetCEchoDuration(5); - HU_DoCEcho(va(M_GetText("%s%s%s\\CAPTURED THE %sBLUE FLAG%s.\\\\\\\\"), "\x85", player_names[player-players], "\x80", "\x84", "\x80")); - - if (splitscreen || players[consoleplayer].ctfteam == 1) - S_StartSound(NULL, sfx_flgcap); - else if (players[consoleplayer].ctfteam == 2) - S_StartSound(NULL, sfx_lose); - - mo = P_SpawnMobj(player->mo->x,player->mo->y,player->mo->z,MT_BLUEFLAG); - player->gotflag &= ~GF_BLUEFLAG; - mo->flags &= ~MF_SPECIAL; - mo->fuse = TICRATE; - mo->spawnpoint = bflagpoint; - mo->flags2 |= MF2_JUSTATTACKED; - redscore += 1; - P_AddPlayerScore(player, 250); - } - } - break; - - case 4: // Blue Team's Base - if ((gametyperules & GTR_TEAMFLAGS) && P_IsObjectOnGround(player->mo)) - { - if (player->ctfteam == 2 && (player->gotflag & GF_REDFLAG)) - { - mobj_t *mo; - - // Make sure the blue team still has their own - // flag at their base so they can score. - if (!P_IsFlagAtBase(MT_BLUEFLAG)) - break; - - HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE); - HU_SetCEchoDuration(5); - HU_DoCEcho(va(M_GetText("%s%s%s\\CAPTURED THE %sRED FLAG%s.\\\\\\\\"), "\x84", player_names[player-players], "\x80", "\x85", "\x80")); - - if (splitscreen || players[consoleplayer].ctfteam == 2) - S_StartSound(NULL, sfx_flgcap); - else if (players[consoleplayer].ctfteam == 1) - S_StartSound(NULL, sfx_lose); - - mo = P_SpawnMobj(player->mo->x,player->mo->y,player->mo->z,MT_REDFLAG); - player->gotflag &= ~GF_REDFLAG; - mo->flags &= ~MF_SPECIAL; - mo->fuse = TICRATE; - mo->spawnpoint = rflagpoint; - mo->flags2 |= MF2_JUSTATTACKED; - bluescore += 1; - P_AddPlayerScore(player, 250); - } - } - break; - - case 5: // Fan sector - player->mo->momz += mobjinfo[MT_FAN].mass/4; - - if (player->mo->momz > mobjinfo[MT_FAN].mass) - player->mo->momz = mobjinfo[MT_FAN].mass; - - if (!player->powers[pw_carry]) - { - P_ResetPlayer(player); - P_SetPlayerMobjState(player->mo, S_PLAY_FALL); - P_SetTarget(&player->mo->tracer, player->mo); - player->powers[pw_carry] = CR_FAN; - } - break; - - case 6: // Super Sonic transformer - if (player->mo->health > 0 && !player->bot && (player->charflags & SF_SUPER) && !player->powers[pw_super] && ALL7EMERALDS(emeralds)) - P_DoSuperTransformation(player, true); - break; - - case 7: // Make player spin - if (!(player->pflags & PF_SPINNING)) - { - player->pflags |= PF_SPINNING; - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartAttackSound(player->mo, sfx_spin); - - if (abs(player->rmomx) < FixedMul(5*FRACUNIT, player->mo->scale) - && abs(player->rmomy) < FixedMul(5*FRACUNIT, player->mo->scale)) - P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale)); - } - break; - - case 8: // Zoom Tube Start - { - INT32 sequence; - fixed_t speed; - INT32 lineindex; - mobj_t *waypoint = NULL; - angle_t an; - - if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ZOOMTUBE) - break; - - if (player->powers[pw_ignorelatch] & (1<<15)) - break; - - // Find line #3 tagged to this sector - lineindex = Tag_FindLineSpecial(3, sectag); - - if (lineindex == -1) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Sector special %d missing line special #3.\n", sector->special); - break; - } - - // Grab speed and sequence values - speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; - sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS; - - if (speed == 0) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence); - break; - } - - waypoint = P_GetFirstWaypoint(sequence); - - if (!waypoint) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: FIRST WAYPOINT IN SEQUENCE %d NOT FOUND.\n", sequence); - break; - } - else - { - CONS_Debug(DBG_GAMELOGIC, "Waypoint %d found in sequence %d - speed = %d\n", waypoint->health, sequence, speed); - } - - an = R_PointToAngle2(player->mo->x, player->mo->y, waypoint->x, waypoint->y) - player->mo->angle; - - if (an > ANGLE_90 && an < ANGLE_270 && !(lines[lineindex].flags & ML_EFFECT4)) - break; // behind back - - P_SetTarget(&player->mo->tracer, waypoint); - player->powers[pw_carry] = CR_ZOOMTUBE; - player->speed = speed; - player->pflags |= PF_SPINNING; - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); - player->climbing = 0; - - if (player->mo->state-states != S_PLAY_ROLL) - { - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_spin); - } - } - break; - - case 9: // Zoom Tube End - { - INT32 sequence; - fixed_t speed; - INT32 lineindex; - mobj_t *waypoint = NULL; - angle_t an; - - if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ZOOMTUBE) - break; - - if (player->powers[pw_ignorelatch] & (1<<15)) - break; - - // Find line #3 tagged to this sector - lineindex = Tag_FindLineSpecial(3, sectag); - - if (lineindex == -1) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Sector special %d missing line special #3.\n", sector->special); - break; - } - - // Grab speed and sequence values - speed = -abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; // Negative means reverse - sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS; - - if (speed == 0) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence); - break; - } - - waypoint = P_GetLastWaypoint(sequence); - - if (!waypoint) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: LAST WAYPOINT IN SEQUENCE %d NOT FOUND.\n", sequence); - break; - } - else - { - CONS_Debug(DBG_GAMELOGIC, "Waypoint %d found in sequence %d - speed = %d\n", waypoint->health, sequence, speed); - } - - an = R_PointToAngle2(player->mo->x, player->mo->y, waypoint->x, waypoint->y) - player->mo->angle; - - if (an > ANGLE_90 && an < ANGLE_270 && !(lines[lineindex].flags & ML_EFFECT4)) - break; // behind back - - P_SetTarget(&player->mo->tracer, waypoint); - player->powers[pw_carry] = CR_ZOOMTUBE; - player->speed = speed; - player->pflags |= PF_SPINNING; - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); - player->climbing = 0; - - if (player->mo->state-states != S_PLAY_ROLL) - { - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - S_StartSound(player->mo, sfx_spin); - } - } - break; - - case 10: // Finish Line - if (((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) && !player->exiting) - { - if (player->starpostnum == numstarposts) // Must have touched all the starposts - { - player->laps++; - - if (player->powers[pw_carry] == CR_NIGHTSMODE) - player->drillmeter += 48*20; - - if (player->laps >= (UINT8)cv_numlaps.value) - CONS_Printf(M_GetText("%s has finished the race.\n"), player_names[player-players]); - else - CONS_Printf(M_GetText("%s started lap %u\n"), player_names[player-players], (UINT32)player->laps+1); - - // Reset starposts (checkpoints) info - player->starpostscale = player->starpostangle = player->starposttime = player->starpostnum = 0; - player->starpostx = player->starposty = player->starpostz = 0; - P_ResetStarposts(); - - // Play the starpost sound for 'consistency' - S_StartSound(player->mo, sfx_strpst); - } - else if (player->starpostnum) - { - // blatant reuse of a variable that's normally unused in circuit - if (!player->tossdelay) - S_StartSound(player->mo, sfx_lose); - player->tossdelay = 3; - } - - if (player->laps >= (unsigned)cv_numlaps.value) - { - if (P_IsLocalPlayer(player)) - { - HU_SetCEchoFlags(0); - HU_SetCEchoDuration(5); - HU_DoCEcho("FINISHED!"); - } - - P_DoPlayerExit(player); - } - } - break; - - case 11: // Rope hang - { - INT32 sequence; - fixed_t speed; - INT32 lineindex; - mobj_t *waypointmid = NULL; - mobj_t *waypointhigh = NULL; - mobj_t *waypointlow = NULL; - mobj_t *closest = NULL; - vector3_t p, line[2], resulthigh, resultlow; - - if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && player->powers[pw_carry] == CR_ROPEHANG) - break; - - if (player->powers[pw_ignorelatch] & (1<<15)) - break; - - if (player->mo->momz > 0) - break; - - if (player->cmd.buttons & BT_SPIN) - break; - - if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate]) - break; - - if (player->exiting) - break; - - //initialize resulthigh and resultlow with 0 - memset(&resultlow, 0x00, sizeof(resultlow)); - memset(&resulthigh, 0x00, sizeof(resulthigh)); - - // Find line #11 tagged to this sector - lineindex = Tag_FindLineSpecial(11, sectag); - - if (lineindex == -1) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Sector special %d missing line special #11.\n", sector->special); - break; - } - - // Grab speed and sequence values - speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; - sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS; - - if (speed == 0) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence); - break; - } - - // Find the closest waypoint - // Find the preceding waypoint - // Find the proceeding waypoint - // Determine the closest spot on the line between the three waypoints - // Put player at that location. - - waypointmid = P_GetClosestWaypoint(sequence, player->mo); - - if (!waypointmid) - { - CONS_Debug(DBG_GAMELOGIC, "ERROR: WAYPOINT(S) IN SEQUENCE %d NOT FOUND.\n", sequence); - break; - } - - waypointlow = P_GetPreviousWaypoint(waypointmid, true); - waypointhigh = P_GetNextWaypoint(waypointmid, true); - - CONS_Debug(DBG_GAMELOGIC, "WaypointMid: %d; WaypointLow: %d; WaypointHigh: %d\n", - waypointmid->health, waypointlow ? waypointlow->health : -1, waypointhigh ? waypointhigh->health : -1); - - // Now we have three waypoints... the closest one we're near, and the one that comes before, and after. - // Next, we need to find the closest point on the line between each set, and determine which one we're - // closest to. - - p.x = player->mo->x; - p.y = player->mo->y; - p.z = player->mo->z; - - // Waypointmid and Waypointlow: - if (waypointlow) - { - line[0].x = waypointmid->x; - line[0].y = waypointmid->y; - line[0].z = waypointmid->z; - line[1].x = waypointlow->x; - line[1].y = waypointlow->y; - line[1].z = waypointlow->z; - - P_ClosestPointOnLine3D(&p, line, &resultlow); - } - - // Waypointmid and Waypointhigh: - if (waypointhigh) - { - line[0].x = waypointmid->x; - line[0].y = waypointmid->y; - line[0].z = waypointmid->z; - line[1].x = waypointhigh->x; - line[1].y = waypointhigh->y; - line[1].z = waypointhigh->z; - - P_ClosestPointOnLine3D(&p, line, &resulthigh); - } - - // 3D support now available. Disregard the previous notice here. -Red - - P_UnsetThingPosition(player->mo); - P_ResetPlayer(player); - player->mo->momx = player->mo->momy = player->mo->momz = 0; - - if (lines[lineindex].flags & ML_EFFECT1) // Don't wrap - { - mobj_t *highest = P_GetLastWaypoint(sequence); - highest->flags |= MF_SLIDEME; - } - - // Changing the conditions on these ifs to fix issues with snapping to the wrong spot -Red - if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == 0) - { - closest = waypointhigh; - player->mo->x = resulthigh.x; - player->mo->y = resulthigh.y; - player->mo->z = resulthigh.z - P_GetPlayerHeight(player); - } - else if ((lines[lineindex].flags & ML_EFFECT1) && waypointmid->health == numwaypoints[sequence] - 1) - { - closest = waypointmid; - player->mo->x = resultlow.x; - player->mo->y = resultlow.y; - player->mo->z = resultlow.z - P_GetPlayerHeight(player); - } - else - { - if (P_AproxDistance(P_AproxDistance(player->mo->x-resultlow.x, player->mo->y-resultlow.y), - player->mo->z-resultlow.z) < P_AproxDistance(P_AproxDistance(player->mo->x-resulthigh.x, - player->mo->y-resulthigh.y), player->mo->z-resulthigh.z)) - { - // Line between Mid and Low is closer - closest = waypointmid; - player->mo->x = resultlow.x; - player->mo->y = resultlow.y; - player->mo->z = resultlow.z - P_GetPlayerHeight(player); - } - else - { - // Line between Mid and High is closer - closest = waypointhigh; - player->mo->x = resulthigh.x; - player->mo->y = resulthigh.y; - player->mo->z = resulthigh.z - P_GetPlayerHeight(player); - } - } - - P_SetTarget(&player->mo->tracer, closest); - player->powers[pw_carry] = CR_ROPEHANG; - - // Option for static ropes. - if (lines[lineindex].flags & ML_NOCLIMB) - player->speed = 0; - else - player->speed = speed; - - S_StartSound(player->mo, sfx_s3k4a); - - player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_BOUNCING|PF_SLIDING|PF_CANCARRY); - player->climbing = 0; - P_SetThingPosition(player->mo); - P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); - } - break; - case 12: // Camera noclip - case 13: // Unused - case 14: // Unused - case 15: // Unused - break; - } + if (!udmf) + P_EvaluateOldSectorSpecial(player, sector, roversector, isTouching); } -/** Checks if an object is standing on or is inside a special 3D floor. - * If so, the sector is returned. - * - * \param mo Object to check. - * \return Pointer to the sector with a special type, or NULL if no special 3D - * floors are being contacted. - * \sa P_PlayerOnSpecial3DFloor - */ -sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo) -{ - sector_t *sector; - ffloor_t *rover; - fixed_t topheight, bottomheight; - - sector = mo->subsector->sector; - if (!sector->ffloors) - return NULL; - - for (rover = sector->ffloors; rover; rover = rover->next) - { - if (!rover->master->frontsector->special) - continue; - - if (!(rover->flags & FF_EXISTS)) - continue; - - topheight = P_GetSpecialTopZ(mo, sectors + rover->secnum, sector); - bottomheight = P_GetSpecialBottomZ(mo, sectors + rover->secnum, sector); - - // Check the 3D floor's type... - if (((rover->flags & FF_BLOCKPLAYER) && mo->player) - || ((rover->flags & FF_BLOCKOTHERS) && !mo->player)) - { - boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == topheight)); - boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == bottomheight)); - // Thing must be on top of the floor to be affected... - if (!(floorallowed || ceilingallowed)) - continue; - } - else - { - // Water and intangible FOFs - if (mo->z > topheight || (mo->z + mo->height) < bottomheight) - continue; - } - - return rover->master->frontsector; - } - - return NULL; -} - -#define TELEPORTED (player->mo->subsector->sector != originalsector) +#define TELEPORTED(mo) (mo->subsector->sector != originalsector) /** Checks if a player is standing on or is inside a 3D floor (e.g. water) and * applies any specials. @@ -5108,200 +5146,58 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector) { sector_t *originalsector = player->mo->subsector->sector; ffloor_t *rover; - fixed_t topheight, bottomheight; for (rover = sector->ffloors; rover; rover = rover->next) { - if (!rover->master->frontsector->special) + if (!P_SectorHasSpecial(rover->master->frontsector)) continue; if (!(rover->flags & FF_EXISTS)) continue; - topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector); - bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector); - - // Check the 3D floor's type... - if (rover->flags & FF_BLOCKPLAYER) - { - boolean floorallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == topheight)); - boolean ceilingallowed = ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING) && ((rover->master->frontsector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == bottomheight)); - // Thing must be on top of the floor to be affected... - if (!(floorallowed || ceilingallowed)) - continue; - } - else - { - // Water and DEATH FOG!!! heh - if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight) - continue; - } + if (!P_IsMobjTouching3DFloor(player->mo, rover, sector)) + continue; // This FOF has the special we're looking for, but are we allowed to touch it? if (sector == player->mo->subsector->sector - || (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH)) + || (rover->master->frontsector->flags & MSF_TRIGGERSPECIAL_TOUCH)) { P_ProcessSpecialSector(player, rover->master->frontsector, sector); - if TELEPORTED return; - } - } - - // Allow sector specials to be applied to polyobjects! - if (player->mo->subsector->polyList) - { - polyobj_t *po = player->mo->subsector->polyList; - sector_t *polysec; - boolean touching = false; - boolean inside = false; - - while (po) - { - if (po->flags & POF_NOSPECIALS) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - polysec = po->lines[0]->backsector; - - if ((polysec->flags & SF_TRIGGERSPECIAL_TOUCH)) - touching = P_MobjTouchingPolyobj(po, player->mo); - else - touching = false; - - inside = P_MobjInsidePolyobj(po, player->mo); - - if (!(inside || touching)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - // We're inside it! Yess... - if (!polysec->special) - { - po = (polyobj_t *)(po->link.next); - continue; - } - - if (!(po->flags & POF_TESTHEIGHT)) // Don't do height checking - ; - else if (po->flags & POF_SOLID) - { - boolean floorallowed = ((polysec->flags & SF_FLIPSPECIAL_FLOOR) && ((polysec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == polysec->ceilingheight)); - boolean ceilingallowed = ((polysec->flags & SF_FLIPSPECIAL_CEILING) && ((polysec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == polysec->floorheight)); - // Thing must be on top of the floor to be affected... - if (!(floorallowed || ceilingallowed)) - { - po = (polyobj_t *)(po->link.next); - continue; - } - } - else - { - // Water and DEATH FOG!!! heh - if (player->mo->z > polysec->ceilingheight || (player->mo->z + player->mo->height) < polysec->floorheight) - { - po = (polyobj_t *)(po->link.next); - continue; - } - } - - P_ProcessSpecialSector(player, polysec, sector); - if TELEPORTED return; - - po = (polyobj_t *)(po->link.next); + if TELEPORTED(player->mo) return; } } } -#define VDOORSPEED (FRACUNIT*2) - -// -// P_RunSpecialSectorCheck -// -// Helper function to P_PlayerInSpecialSector -// -static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector) +static void P_PlayerOnSpecialPolyobj(player_t *player) { - boolean nofloorneeded = false; - fixed_t f_affectpoint, c_affectpoint; + sector_t *originalsector = player->mo->subsector->sector; + polyobj_t *po; + sector_t *polysec; + boolean touching = false; + boolean inside = false; - if (!sector->special) // nothing special, exit - return; - - if (GETSECSPECIAL(sector->special, 2) == 9) // Egg trap capsule -- should only be for 3dFloors! - return; - - // The list of specials that activate without floor touch - // Check Section 1 - switch(GETSECSPECIAL(sector->special, 1)) + for (po = player->mo->subsector->polyList; po; po = (polyobj_t *)(po->link.next)) { - case 2: // Damage (water) - case 8: // Instant kill - case 10: // Ring drainer that doesn't require floor touch - case 12: // Space countdown - nofloorneeded = true; - break; + if (po->flags & POF_NOSPECIALS) + continue; + + polysec = po->lines[0]->backsector; + + if (!P_SectorHasSpecial(polysec)) + continue; + + touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, player->mo); + inside = P_MobjInsidePolyobj(po, player->mo); + + if (!(inside || touching)) + continue; + + if (!P_IsMobjTouchingPolyobj(player->mo, po, polysec)) + continue; + + P_ProcessSpecialSector(player, polysec, originalsector); + if TELEPORTED(player->mo) return; } - - // Check Section 2 - switch(GETSECSPECIAL(sector->special, 2)) - { - case 2: // Linedef executor (All players needed) - case 4: // Linedef executor - case 6: // Linedef executor (7 Emeralds) - case 7: // Linedef executor (NiGHTS Mare) - nofloorneeded = true; - break; - } - - // Check Section 3 -/* switch(GETSECSPECIAL(sector->special, 3)) - { - - }*/ - - // Check Section 4 - switch(GETSECSPECIAL(sector->special, 4)) - { - case 2: // Level Exit / GOAL Sector / Flag Return - if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap)) - { - // Special stage GOAL sector - // requires touching floor. - break; - } - /* FALLTHRU */ - - case 1: // Starpost activator - case 5: // Fan sector - case 6: // Super Sonic Transform - case 8: // Zoom Tube Start - case 9: // Zoom Tube End - case 10: // Finish line - nofloorneeded = true; - break; - } - - if (nofloorneeded) - { - P_ProcessSpecialSector(player, sector, NULL); - return; - } - - f_affectpoint = P_GetSpecialBottomZ(player->mo, sector, sector); - c_affectpoint = P_GetSpecialTopZ(player->mo, sector, sector); - - { - boolean floorallowed = ((sector->flags & SF_FLIPSPECIAL_FLOOR) && ((sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z == f_affectpoint)); - boolean ceilingallowed = ((sector->flags & SF_FLIPSPECIAL_CEILING) && ((sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (player->mo->eflags & MFE_VERTICALFLIP)) && (player->mo->z + player->mo->height == c_affectpoint)); - // Thing must be on top of the floor to be affected... - if (!(floorallowed || ceilingallowed)) - return; - } - - P_ProcessSpecialSector(player, sector, NULL); } /** Checks if the player is in a special sector or FOF and apply any specials. @@ -5321,10 +5217,14 @@ void P_PlayerInSpecialSector(player_t *player) originalsector = player->mo->subsector->sector; P_PlayerOnSpecial3DFloor(player, originalsector); // Handle FOFs first. - if TELEPORTED return; + if TELEPORTED(player->mo) return; - P_RunSpecialSectorCheck(player, originalsector); - if TELEPORTED return; + // Allow sector specials to be applied to polyobjects! + P_PlayerOnSpecialPolyobj(player); + if TELEPORTED(player->mo) return; + + P_ProcessSpecialSector(player, originalsector, NULL); + if TELEPORTED(player->mo) return; // Iterate through touching_sectorlist for SF_TRIGGERSPECIAL_TOUCH for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next) @@ -5336,16 +5236,110 @@ void P_PlayerInSpecialSector(player_t *player) // Check 3D floors... P_PlayerOnSpecial3DFloor(player, loopsector); - if TELEPORTED return; + if TELEPORTED(player->mo) return; - if (!(loopsector->flags & SF_TRIGGERSPECIAL_TOUCH)) + if (!(loopsector->flags & MSF_TRIGGERSPECIAL_TOUCH)) continue; - P_RunSpecialSectorCheck(player, loopsector); - if TELEPORTED return; + P_ProcessSpecialSector(player, loopsector, NULL); + if TELEPORTED(player->mo) return; } } +static void P_CheckMobj3DFloorTrigger(mobj_t *mo, sector_t *sec) +{ + sector_t *originalsector = mo->subsector->sector; + ffloor_t *rover; + + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (!rover->master->frontsector->triggertag) + continue; + + if (rover->master->frontsector->triggerer != TO_MOBJ) + continue; + + if (!(rover->flags & FF_EXISTS)) + continue; + + if (!P_IsMobjTouching3DFloor(mo, rover, sec)) + continue; + + P_LinedefExecute(rover->master->frontsector->triggertag, mo, rover->master->frontsector); + if TELEPORTED(mo) return; + } +} + +static void P_CheckMobjPolyobjTrigger(mobj_t *mo) +{ + sector_t *originalsector = mo->subsector->sector; + polyobj_t *po; + sector_t *polysec; + boolean touching = false; + boolean inside = false; + + for (po = mo->subsector->polyList; po; po = (polyobj_t *)(po->link.next)) + { + if (po->flags & POF_NOSPECIALS) + continue; + + polysec = po->lines[0]->backsector; + + if (!polysec->triggertag) + continue; + + if (polysec->triggerer != TO_MOBJ) + continue; + + touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, mo); + inside = P_MobjInsidePolyobj(po, mo); + + if (!(inside || touching)) + continue; + + if (!P_IsMobjTouchingPolyobj(mo, po, polysec)) + continue; + + P_LinedefExecute(polysec->triggertag, mo, polysec); + if TELEPORTED(mo) return; + } +} + +static void P_CheckMobjSectorTrigger(mobj_t *mo, sector_t *sec) +{ + if (!sec->triggertag) + return; + + if (sec->triggerer != TO_MOBJ) + return; + + if ((sec->flags & MSF_TRIGGERLINE_PLANE) && !P_IsMobjTouchingSectorPlane(mo, sec)) + return; + + P_LinedefExecute(sec->triggertag, mo, sec); +} + +void P_CheckMobjTrigger(mobj_t *mobj, boolean pushable) +{ + sector_t *originalsector; + + if (!mobj->subsector) + return; + + originalsector = mobj->subsector->sector; + + if (!pushable && !(originalsector->flags & MSF_TRIGGERLINE_MOBJ)) + return; + + P_CheckMobj3DFloorTrigger(mobj, originalsector); + if TELEPORTED(mobj) return; + + P_CheckMobjPolyobjTrigger(mobj); + if TELEPORTED(mobj) return; + + P_CheckMobjSectorTrigger(mobj, originalsector); +} + #undef TELEPORTED /** Animate planes, scroll walls, etc. and keeps track of level timelimit and exits if time is up. @@ -5495,12 +5489,14 @@ static inline void P_AddFFloorToList(sector_t *sec, ffloor_t *fflr) * \param sec Target sector. * \param sec2 Control sector. * \param master Control linedef. + * \param alpha Alpha value (0-255). + * \param blendmode Blending mode. * \param flags Options affecting this 3Dfloor. * \param secthinkers List of relevant thinkers sorted by sector. May be NULL. * \return Pointer to the new 3Dfloor. * \sa P_AddFFloor, P_AddFakeFloorsByLine, P_SpawnSpecials */ -static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, ffloortype_e flags, thinkerlist_t *secthinkers) +static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, INT32 alpha, UINT8 blendmode, ffloortype_e flags, thinkerlist_t *secthinkers) { ffloor_t *fflr; thinker_t *th; @@ -5518,7 +5514,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f { fixed_t tempceiling = sec2->ceilingheight; //flip the sector around and print an error instead of crashing 12.1.08 -Inuyasha - CONS_Alert(CONS_ERROR, M_GetText("FOF (line %s) has a top height below its bottom.\n"), sizeu1(master - lines)); + CONS_Alert(CONS_ERROR, M_GetText("A FOF tagged %d has a top height below its bottom.\n"), master->args[0]); sec2->ceilingheight = sec2->floorheight; sec2->floorheight = tempceiling; } @@ -5574,12 +5570,6 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f if (sec2->hasslope) sec->hasslope = true; - if ((flags & FF_SOLID) && (master->flags & ML_EFFECT1)) // Block player only - flags &= ~FF_BLOCKOTHERS; - - if ((flags & FF_SOLID) && (master->flags & ML_EFFECT2)) // Block all BUT player - flags &= ~FF_BLOCKPLAYER; - fflr->spawnflags = fflr->flags = flags; fflr->master = master; fflr->norender = INFTICS; @@ -5620,35 +5610,50 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f p = (pusher_t *)th; if (p->affectee == (INT32)sec2num) - Add_Pusher(p->type, p->x_mag<y_mag<source, (INT32)(sec-sectors), p->affectee, p->exclusive, p->slider); + Add_Pusher(p->type, p->x_mag, p->y_mag, p->z_mag, (INT32)(sec-sectors), p->affectee, p->exclusive, p->slider); } if(secthinkers) i++; else th = th->next; } - - if (flags & FF_TRANSLUCENT) + fflr->alpha = max(0, min(0xff, alpha)); + if (fflr->alpha < 0xff || flags & FF_SPLAT) { - if (sides[master->sidenum[0]].toptexture > 0) - fflr->alpha = sides[master->sidenum[0]].toptexture; // for future reference, "#0" is 1, and "#255" is 256. Be warned - else - fflr->alpha = 0x80; + fflr->flags |= FF_TRANSLUCENT; + fflr->spawnflags = fflr->flags; } - else - fflr->alpha = 0xff; - fflr->spawnalpha = fflr->alpha; // save for netgames + switch (blendmode) + { + case TMB_TRANSLUCENT: + default: + fflr->blend = AST_COPY; + break; + case TMB_ADD: + fflr->blend = AST_ADD; + break; + case TMB_SUBTRACT: + fflr->blend = AST_SUBTRACT; + break; + case TMB_REVERSESUBTRACT: + fflr->blend = AST_REVERSESUBTRACT; + break; + case TMB_MODULATE: + fflr->blend = AST_MODULATE; + break; + } + if (flags & FF_QUICKSAND) CheckForQuicksand = true; - if ((flags & FF_BUSTUP) || (flags & FF_SHATTER) || (flags & FF_SPINBUST)) + if (flags & FF_BUSTUP) CheckForBustableBlocks = true; if ((flags & FF_MARIO)) { - if (!(flags & FF_SHATTERBOTTOM)) // Don't change the textures of a brick block, just a question block + if (!(flags & FF_GOOWATER)) // Don't change the textures of a brick block, just a question block P_AddBlockThinker(sec2, master); CheckForMarioBlocks = true; } @@ -5658,7 +5663,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f if ((flags & FF_FLOATBOB)) { - P_AddFloatThinker(sec2, Tag_FGet(&master->tags), master); + P_AddFloatThinker(sec2, master->args[0], master); CheckForFloatBob = true; } @@ -5774,7 +5779,7 @@ static void P_AddRaiseThinker(sector_t *sec, INT16 tag, fixed_t speed, fixed_t c raise->ceilingtop = ceilingtop; raise->ceilingbottom = ceilingbottom; - raise->basespeed = speed; + raise->basespeed = speed >> 2; if (lower) raise->flags |= RF_REVERSE; @@ -5838,7 +5843,7 @@ static inline void P_AddThwompThinker(sector_t *sec, line_t *sourceline, fixed_t thwomp->floorstartheight = sec->floorheight; thwomp->ceilingstartheight = sec->ceilingheight; thwomp->delay = 1; - thwomp->tag = Tag_FGet(&sourceline->tags); + thwomp->tag = sourceline->args[0]; thwomp->sound = sound; sec->floordata = thwomp; @@ -5874,7 +5879,7 @@ static inline void P_AddNoEnemiesThinker(line_t *sourceline) * \sa P_SpawnSpecials, T_EachTimeThinker * \author SSNTails */ -static void P_AddEachTimeThinker(line_t *sourceline) +static void P_AddEachTimeThinker(line_t *sourceline, boolean triggerOnExit) { eachtime_t *eachtime; @@ -5885,7 +5890,7 @@ static void P_AddEachTimeThinker(line_t *sourceline) eachtime->thinker.function.acp1 = (actionf_p1)T_EachTimeThinker; eachtime->sourceline = sourceline; - eachtime->triggerOnExit = !!(sourceline->flags & ML_BOUNCY); + eachtime->triggerOnExit = triggerOnExit; } /** Adds a camera scanner. @@ -5930,9 +5935,8 @@ void T_LaserFlash(laserthink_t *flash) sector_t *sector; sector_t *sourcesec = flash->sourceline->frontsector; fixed_t top, bottom; - TAG_ITER_DECLARECOUNTER(0); - TAG_ITER_SECTORS(0, flash->tag, s) + TAG_ITER_SECTORS(flash->tag, s) { sector = §ors[s]; for (fflr = sector->ffloors; fflr; fflr = fflr->next) @@ -6051,16 +6055,16 @@ void P_InitSpecials(void) globalweather = mapheaderinfo[gamemap-1]->weather; } -static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs) +void P_ApplyFlatAlignment(sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs, boolean floor, boolean ceiling) { - if (!(master->flags & ML_NETONLY)) // Modify floor flat alignment unless ML_NETONLY flag is set + if (floor) { sector->floorpic_angle = flatangle; sector->floor_xoffs += xoffs; sector->floor_yoffs += yoffs; } - if (!(master->flags & ML_NONET)) // Modify ceiling flat alignment unless ML_NONET flag is set + if (ceiling) { sector->ceilingpic_angle = flatangle; sector->ceiling_xoffs += xoffs; @@ -6069,6 +6073,58 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata } +static void P_MakeFOFBouncy(line_t *paramline, line_t *masterline) +{ + INT32 s; + + if (masterline->special < 100 || masterline->special >= 300) + return; + + TAG_ITER_SECTORS(masterline->args[0], s) + { + ffloor_t *rover; + + for (rover = sectors[s].ffloors; rover; rover = rover->next) + { + if (rover->master != masterline) + continue; + + rover->flags |= FF_BOUNCY; + rover->spawnflags |= FF_BOUNCY; + rover->bouncestrength = (paramline->args[1]<< FRACBITS)/100; + CheckForBouncySector = true; + break; + } + } + +} + +static boolean P_CheckGametypeRules(INT32 checktype, UINT32 target) +{ + switch (checktype) + { + case TMF_HASALL: + default: + return (gametyperules & target) == target; + case TMF_HASANY: + return !!(gametyperules & target); + case TMF_HASEXACTLY: + return gametyperules == target; + case TMF_DOESNTHAVEALL: + return (gametyperules & target) != target; + case TMF_DOESNTHAVEANY: + return !(gametyperules & target); + } +} + +fixed_t P_GetSectorGravityFactor(sector_t *sec) +{ + if (sec->gravityptr) + return FixedDiv(*sec->gravityptr >> FRACBITS, 1000); + else + return sec->gravity; +} + /** After the map has loaded, scans for specials that spawn 3Dfloors and * thinkers. * @@ -6097,6 +6153,14 @@ void P_SpawnSpecials(boolean fromnetsave) sector = sectors; for (i = 0; i < numsectors; i++, sector++) { + CheckForReverseGravity |= (sector->flags & MSF_GRAVITYFLIP); + + if (sector->specialflags & SSF_FINISHLINE) + { + if ((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) + circuitmap = true; + } + if (!sector->special) continue; @@ -6105,11 +6169,14 @@ void P_SpawnSpecials(boolean fromnetsave) { case 5: // Spikes //Terrible hack to replace an even worse hack: - //Spike damage automatically sets SF_TRIGGERSPECIAL_TOUCH. + //Spike damage automatically sets MSF_TRIGGERSPECIAL_TOUCH. //Yes, this also affects other specials on the same sector. Sorry. - sector->flags |= SF_TRIGGERSPECIAL_TOUCH; + sector->flags |= MSF_TRIGGERSPECIAL_TOUCH; break; - case 15: // Bouncy sector + case 15: // Bouncy FOF + if (udmf) + break; + CONS_Alert(CONS_WARNING, M_GetText("Deprecated bouncy FOF sector type detected. Please use linedef type 76 instead.\n")); CheckForBouncySector = true; break; } @@ -6118,29 +6185,20 @@ void P_SpawnSpecials(boolean fromnetsave) switch(GETSECSPECIAL(sector->special, 2)) { case 10: // Time for special stage + if (udmf) + break; + CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for special stage requirements detected. Please use the SpecialStageTime and SpecialStageSpheres level header options instead.\n")); sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage break; case 11: // Custom global gravity! + if (udmf) + break; + CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for global gravity detected. Please use the Gravity level header option instead.\n")); gravity = sector->floorheight/1000; break; } - - // Process Section 3 -/* switch(GETSECSPECIAL(player->specialsector, 3)) - { - - }*/ - - // Process Section 4 - switch(GETSECSPECIAL(sector->special, 4)) - { - case 10: // Circuit finish line - if ((gametyperules & (GTR_RACE|GTR_LIVES)) == GTR_RACE) - circuitmap = true; - break; - } } P_SpawnScrollers(); // Add generalized scrollers @@ -6187,528 +6245,406 @@ void P_SpawnSpecials(boolean fromnetsave) // Init line EFFECTs for (i = 0; i < numlines; i++) { - mtag_t tag = Tag_FGet(&lines[i].tags); - - if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment in netgames... + // set line specials to 0 here too, same reason as above + if (netgame || multiplayer) { - // set line specials to 0 here too, same reason as above - if (netgame || multiplayer) - { - if (lines[i].flags & ML_NONET) - { - lines[i].special = 0; - continue; - } - } - else if (lines[i].flags & ML_NETONLY) + if (lines[i].flags & ML_NONET) { lines[i].special = 0; continue; } } + else if (lines[i].flags & ML_NETONLY) + { + lines[i].special = 0; + continue; + } switch (lines[i].special) { INT32 s; + INT32 l; size_t sec; ffloortype_e ffloorflags; - TAG_ITER_DECLARECOUNTER(0); case 1: // Definable gravity per sector + if (udmf) + break; + sec = sides[*lines[i].sidenum].sector - sectors; - TAG_ITER_SECTORS(0, tag, s) + TAG_ITER_SECTORS(Tag_FGet(&lines[i].tags), s) { - sectors[s].gravity = §ors[sec].floorheight; // This allows it to change in realtime! + sectors[s].gravityptr = §ors[sec].floorheight; // This allows it to change in realtime! if (lines[i].flags & ML_NOCLIMB) - sectors[s].verticalflip = true; + sectors[s].flags |= MSF_GRAVITYFLIP; else - sectors[s].verticalflip = false; + sectors[s].flags &= ~MSF_GRAVITYFLIP; - CheckForReverseGravity = sectors[s].verticalflip; + CheckForReverseGravity |= (sectors[s].flags & MSF_GRAVITYFLIP); } break; - case 2: // Custom exit - break; - - case 3: // Zoom Tube Parameters - break; - - case 4: // Speed pad (combines with sector special Section3:5 or Section3:6) - break; - case 5: // Change camera info + if (udmf) + break; + sec = sides[*lines[i].sidenum].sector - sectors; - TAG_ITER_SECTORS(0, tag, s) + TAG_ITER_SECTORS(Tag_FGet(&lines[i].tags), s) P_AddCameraScanner(§ors[sec], §ors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y)); break; case 7: // Flat alignment - redone by toast - if ((lines[i].flags & (ML_NETONLY|ML_NONET)) != (ML_NETONLY|ML_NONET)) // If you can do something... + { + // Set calculated offsets such that line's v1 is the apparent origin + angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)); + fixed_t xoffs = -lines[i].v1->x; + fixed_t yoffs = lines[i].v1->y; + + //If no tag is given, apply to front sector + if (lines[i].args[0] == 0) + P_ApplyFlatAlignment(lines[i].frontsector, flatangle, xoffs, yoffs, lines[i].args[1] != TMP_CEILING, lines[i].args[1] != TMP_FLOOR); + else { - angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)); - fixed_t xoffs; - fixed_t yoffs; - - if (lines[i].flags & ML_EFFECT6) // Set offset through x and y texture offsets if ML_EFFECT6 flag is set - { - xoffs = sides[lines[i].sidenum[0]].textureoffset; - yoffs = sides[lines[i].sidenum[0]].rowoffset; - } - else // Otherwise, set calculated offsets such that line's v1 is the apparent origin - { - xoffs = -lines[i].v1->x; - yoffs = lines[i].v1->y; - } - - //If no tag is given, apply to front sector - if (tag == 0) - P_ApplyFlatAlignment(lines + i, lines[i].frontsector, flatangle, xoffs, yoffs); - else - { - TAG_ITER_SECTORS(0, tag, s) - P_ApplyFlatAlignment(lines + i, sectors + s, flatangle, xoffs, yoffs); - } - } - else // Otherwise, print a helpful warning. Can I do no less? - CONS_Alert(CONS_WARNING, - M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), - tag); - break; - - case 8: // Sector Parameters - TAG_ITER_SECTORS(0, tag, s) - { - if (lines[i].flags & ML_NOCLIMB) - { - sectors[s].flags &= ~SF_FLIPSPECIAL_FLOOR; - sectors[s].flags |= SF_FLIPSPECIAL_CEILING; - } - else if (lines[i].flags & ML_EFFECT4) - sectors[s].flags |= SF_FLIPSPECIAL_BOTH; - - if (lines[i].flags & ML_EFFECT3) - sectors[s].flags |= SF_TRIGGERSPECIAL_TOUCH; - if (lines[i].flags & ML_EFFECT2) - sectors[s].flags |= SF_TRIGGERSPECIAL_HEADBUMP; - - if (lines[i].flags & ML_EFFECT1) - sectors[s].flags |= SF_INVERTPRECIP; - - if (lines[i].frontsector && GETSECSPECIAL(lines[i].frontsector->special, 4) == 12) - sectors[s].camsec = sides[*lines[i].sidenum].sector-sectors; + TAG_ITER_SECTORS(lines[i].args[0], s) + P_ApplyFlatAlignment(sectors + s, flatangle, xoffs, yoffs, lines[i].args[1] != TMP_CEILING, lines[i].args[1] != TMP_FLOOR); } break; + } - case 9: // Chain Parameters + case 8: // Set camera collision planes + if (lines[i].frontsector) + TAG_ITER_SECTORS(lines[i].args[0], s) + sectors[s].camsec = lines[i].frontsector-sectors; break; case 10: // Vertical culling plane for sprites and FOFs - TAG_ITER_SECTORS(0, tag, s) + TAG_ITER_SECTORS(lines[i].args[0], s) sectors[s].cullheight = &lines[i]; // This allows it to change in realtime! break; case 50: // Insta-Lower Sector - EV_DoFloor(&lines[i], instantLower); + if (!udmf) + EV_DoFloor(lines[i].args[0], &lines[i], instantLower); break; case 51: // Instant raise for ceilings - EV_DoCeiling(&lines[i], instantRaise); + if (!udmf) + EV_DoCeiling(lines[i].args[0], &lines[i], instantRaise); break; case 52: // Continuously Falling sector - EV_DoContinuousFall(lines[i].frontsector, lines[i].backsector, P_AproxDistance(lines[i].dx, lines[i].dy), (lines[i].flags & ML_NOCLIMB)); + EV_DoContinuousFall(lines[i].frontsector, lines[i].backsector, lines[i].args[0] << FRACBITS, lines[i].args[1]); break; - case 53: // New super cool and awesome moving floor and ceiling type - case 54: // New super cool and awesome moving floor type + case 53: // Continuous plane movement (slowdown) if (lines[i].backsector) - EV_DoFloor(&lines[i], bounceFloor); - if (lines[i].special == 54) - break; - /* FALLTHRU */ - - case 55: // New super cool and awesome moving ceiling type - if (lines[i].backsector) - EV_DoCeiling(&lines[i], bounceCeiling); + { + if (lines[i].args[1] != TMP_CEILING) + EV_DoFloor(lines[i].args[0], &lines[i], bounceFloor); + if (lines[i].args[1] != TMP_FLOOR) + EV_DoCeiling(lines[i].args[0], &lines[i], bounceCeiling); + } break; - case 56: // New super cool and awesome moving floor and ceiling crush type - case 57: // New super cool and awesome moving floor crush type + case 56: // Continuous plane movement (constant) if (lines[i].backsector) - EV_DoFloor(&lines[i], bounceFloorCrush); - - if (lines[i].special == 57) - break; //only move the floor - /* FALLTHRU */ - - case 58: // New super cool and awesome moving ceiling crush type - if (lines[i].backsector) - EV_DoCeiling(&lines[i], bounceCeilingCrush); + { + if (lines[i].args[1] != TMP_CEILING) + EV_DoFloor(lines[i].args[0], &lines[i], bounceFloorCrush); + if (lines[i].args[1] != TMP_FLOOR) + EV_DoCeiling(lines[i].args[0], &lines[i], bounceCeilingCrush); + } break; - case 59: // Activate floating platform - EV_DoElevator(&lines[i], elevateContinuous, false); - break; - - case 60: // Floating platform with adjustable speed - EV_DoElevator(&lines[i], elevateContinuous, true); + case 60: // Moving platform + EV_DoElevator(lines[i].args[0], &lines[i], elevateContinuous); break; case 61: // Crusher! - EV_DoCrush(&lines[i], crushAndRaise); - break; - - case 62: // Crusher (up and then down)! - EV_DoCrush(&lines[i], fastCrushAndRaise); + EV_DoCrush(lines[i].args[0], &lines[i], lines[i].args[1] ? raiseAndCrush : crushAndRaise); break; case 63: // support for drawn heights coming from different sector sec = sides[*lines[i].sidenum].sector-sectors; - TAG_ITER_SECTORS(0, tag, s) + TAG_ITER_SECTORS(lines[i].args[0], s) sectors[s].heightsec = (INT32)sec; break; case 64: // Appearing/Disappearing FOF option - if (lines[i].flags & ML_BLOCKMONSTERS) { // Find FOFs by control sector tag - TAG_ITER_SECTORS(0, tag, s) - for (j = 0; (unsigned)j < sectors[s].linecount; j++) - if (sectors[s].lines[j]->special >= 100 && sectors[s].lines[j]->special < 300) - Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), (INT32)(sectors[s].lines[j]-lines), (INT32)i); - } else // Find FOFs by effect sector tag + if (lines[i].args[0] == 0) // Find FOFs by control sector tag { - TAG_ITER_LINES(0, tag, s) + TAG_ITER_SECTORS(lines[i].args[1], s) { - if ((size_t)s == i) + for (j = 0; (unsigned)j < sectors[s].linecount; j++) + { + if (sectors[s].lines[j]->special < 100 || sectors[s].lines[j]->special >= 300) + continue; + + Add_MasterDisappearer(abs(lines[i].args[2]), abs(lines[i].args[3]), abs(lines[i].args[4]), (INT32)(sectors[s].lines[j] - lines), (INT32)i); + } + } + } + else // Find FOFs by effect sector tag + { + TAG_ITER_LINES(lines[i].args[0], s) + { + if (lines[s].special < 100 || lines[s].special >= 300) continue; - if (Tag_Find(&sides[lines[s].sidenum[0]].sector->tags, Tag_FGet(&sides[lines[i].sidenum[0]].sector->tags))) - Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), s, (INT32)i); + + if (lines[i].args[1] != 0 && !Tag_Find(&lines[s].frontsector->tags, lines[i].args[1])) + continue; + + Add_MasterDisappearer(abs(lines[i].args[2]), abs(lines[i].args[3]), abs(lines[i].args[4]), s, (INT32)i); } } break; - case 66: // Displace floor by front sector - TAG_ITER_SECTORS(0, tag, s) - P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); - break; - case 67: // Displace ceiling by front sector - TAG_ITER_SECTORS(0, tag, s) - P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); - break; - case 68: // Displace both floor AND ceiling by front sector - TAG_ITER_SECTORS(0, tag, s) - P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); + case 66: // Displace planes by front sector + TAG_ITER_SECTORS(lines[i].args[0], s) + P_AddPlaneDisplaceThinker(lines[i].args[1], abs(lines[i].args[2])<<8, sides[lines[i].sidenum[0]].sector-sectors, s, lines[i].args[2] < 0); break; - case 100: // FOF (solid, opaque, shadows) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - break; - - case 101: // FOF (solid, opaque, no shadows) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_NOSHADE|FF_CUTLEVEL, secthinkers); - break; - - case 102: // TL block: FOF (solid, translucent) - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_NOSHADE|FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA; - - // Draw the 'insides' of the block too - if (lines[i].flags & ML_NOCLIMB) + case 70: // Add raise thinker to FOF + if (udmf) { - ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; - ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); + fixed_t destheight = lines[i].args[2] << FRACBITS; + fixed_t startheight, topheight, bottomheight; + + TAG_ITER_LINES(lines[i].args[0], l) + { + if (lines[l].special < 100 || lines[l].special >= 300) + continue; + + startheight = lines[l].frontsector->ceilingheight; + topheight = max(startheight, destheight); + bottomheight = min(startheight, destheight); + + P_AddRaiseThinker(lines[l].frontsector, lines[l].args[0], lines[i].args[1] << FRACBITS, topheight, bottomheight, (destheight < startheight), !!(lines[i].args[3])); + } + } + break; + + case 71: // Add air bob thinker to FOF + if (udmf) + { + TAG_ITER_LINES(lines[i].args[0], l) + { + if (lines[l].special < 100 || lines[l].special >= 300) + continue; + + P_AddAirbob(lines[l].frontsector, lines[l].args[0], lines[i].args[1] << FRACBITS, !!(lines[i].args[2] & TMFB_REVERSE), !!(lines[i].args[2] & TMFB_SPINDASH), !!(lines[i].args[2] & TMFB_DYNAMIC)); + } + } + break; + + case 72: // Add thwomp thinker to FOF + if (udmf) + { + UINT16 sound = (lines[i].stringargs[0]) ? get_number(lines[i].stringargs[0]) : sfx_thwomp; + + TAG_ITER_LINES(lines[i].args[0], l) + { + if (lines[l].special < 100 || lines[l].special >= 300) + continue; + + P_AddThwompThinker(lines[l].frontsector, &lines[l], lines[i].args[1] << (FRACBITS - 3), lines[i].args[2] << (FRACBITS - 3), sound); + } + } + break; + + case 73: // Add laser thinker to FOF + if (udmf) + { + TAG_ITER_LINES(lines[i].args[0], l) + { + if (lines[l].special < 100 || lines[l].special >= 300) + continue; + + P_AddLaserThinker(lines[l].args[0], lines + l, !!(lines[i].args[1])); + } + } + break; + + case 100: // FOF (solid) + ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL; + + //Appearance settings + if (lines[i].args[3] & TMFA_NOPLANES) + ffloorflags &= ~FF_RENDERPLANES; + if (lines[i].args[3] & TMFA_NOSIDES) + ffloorflags &= ~FF_RENDERSIDES; + if (lines[i].args[3] & TMFA_INSIDES) + { + if (ffloorflags & FF_RENDERPLANES) + ffloorflags |= FF_BOTHPLANES; + if (ffloorflags & FF_RENDERSIDES) + ffloorflags |= FF_ALLSIDES; + } + if (lines[i].args[3] & TMFA_ONLYINSIDES) + { + if (ffloorflags & FF_RENDERPLANES) + ffloorflags |= FF_INVERTPLANES; + if (ffloorflags & FF_RENDERSIDES) + ffloorflags |= FF_INVERTSIDES; + } + if (lines[i].args[3] & TMFA_NOSHADE) + ffloorflags |= FF_NOSHADE; + if (lines[i].args[3] & TMFA_SPLAT) + ffloorflags |= FF_SPLAT; + + //Tangibility settings + if (lines[i].args[4] & TMFT_INTANGIBLETOP) + ffloorflags |= FF_REVERSEPLATFORM; + if (lines[i].args[4] & TMFT_INTANGIBLEBOTTOM) + ffloorflags |= FF_PLATFORM; + if (lines[i].args[4] & TMFT_DONTBLOCKPLAYER) + ffloorflags &= ~FF_BLOCKPLAYER; + if (lines[i].args[4] & TMFT_DONTBLOCKOTHERS) + ffloorflags &= ~FF_BLOCKOTHERS; + + //Cutting options + if (ffloorflags & FF_RENDERALL) + { + //If translucent or player can enter it, cut inner walls + if ((lines[i].args[1] < 255) || (lines[i].args[4] & TMFT_VISIBLEFROMINSIDE)) + ffloorflags |= FF_CUTEXTRA|FF_EXTRA; + else + ffloorflags |= FF_CUTLEVEL; } - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); break; - case 103: // Solid FOF with no floor/ceiling (quite possibly useless) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERSIDES|FF_NOSHADE|FF_CUTLEVEL, secthinkers); - break; - - case 104: // 3D Floor type that doesn't draw sides - // If line has no-climb set, give it shadows, otherwise don't - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERPLANES|FF_CUTLEVEL; - if (!(lines[i].flags & ML_NOCLIMB)) - ffloorflags |= FF_NOSHADE; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 105: // FOF (solid, invisible) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_NOSHADE, secthinkers); - break; - - case 120: // Opaque water - ffloorflags = FF_EXISTS|FF_RENDERALL|FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_DOUBLESHADOW; - if (lines[i].flags & ML_EFFECT4) - ffloorflags |= FF_COLORMAPONLY; - if (lines[i].flags & ML_EFFECT5) - ffloorflags |= FF_RIPPLE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 121: // TL water - ffloorflags = FF_EXISTS|FF_RENDERALL|FF_TRANSLUCENT|FF_SWIMMABLE|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_DOUBLESHADOW; - if (lines[i].flags & ML_EFFECT4) - ffloorflags |= FF_COLORMAPONLY; - if (lines[i].flags & ML_EFFECT5) - ffloorflags |= FF_RIPPLE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 122: // Opaque water, no sides + case 120: // FOF (water) ffloorflags = FF_EXISTS|FF_RENDERPLANES|FF_SWIMMABLE|FF_BOTHPLANES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES; - if (lines[i].flags & ML_NOCLIMB) + if (!(lines[i].args[3] & TMFW_NOSIDES)) + ffloorflags |= FF_RENDERSIDES|FF_ALLSIDES; + if (lines[i].args[3] & TMFW_DOUBLESHADOW) ffloorflags |= FF_DOUBLESHADOW; - if (lines[i].flags & ML_EFFECT4) + if (lines[i].args[3] & TMFW_COLORMAPONLY) ffloorflags |= FF_COLORMAPONLY; - if (lines[i].flags & ML_EFFECT5) + if (!(lines[i].args[3] & TMFW_NORIPPLE)) ffloorflags |= FF_RIPPLE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + if (lines[i].args[3] & TMFW_GOOWATER) + ffloorflags |= FF_GOOWATER; + if (lines[i].args[3] & TMFW_SPLAT) + ffloorflags |= FF_SPLAT; + P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); break; - case 123: // TL water, no sides - ffloorflags = FF_EXISTS|FF_RENDERPLANES|FF_TRANSLUCENT|FF_SWIMMABLE|FF_BOTHPLANES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_DOUBLESHADOW; - if (lines[i].flags & ML_EFFECT4) - ffloorflags |= FF_COLORMAPONLY; - if (lines[i].flags & ML_EFFECT5) - ffloorflags |= FF_RIPPLE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + case 150: // FOF (Air bobbing) + P_AddFakeFloorsByLine(i, 0xff, TMB_TRANSLUCENT, FF_EXISTS|FF_SOLID|FF_RENDERALL, secthinkers); + P_AddAirbob(lines[i].frontsector, lines[i].args[0], lines[i].args[1] << FRACBITS, !!(lines[i].args[2] & TMFB_REVERSE), !!(lines[i].args[2] & TMFB_SPINDASH), !!(lines[i].args[2] & TMFB_DYNAMIC)); break; - case 124: // goo water - ffloorflags = FF_EXISTS|FF_RENDERALL|FF_TRANSLUCENT|FF_SWIMMABLE|FF_GOOWATER|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_DOUBLESHADOW; - if (lines[i].flags & ML_EFFECT4) - ffloorflags |= FF_COLORMAPONLY; - if (lines[i].flags & ML_EFFECT5) - ffloorflags |= FF_RIPPLE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + case 160: // FOF (Water bobbing) + P_AddFakeFloorsByLine(i, 0xff, TMB_TRANSLUCENT, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB, secthinkers); break; - case 125: // goo water, no sides - ffloorflags = FF_EXISTS|FF_RENDERPLANES|FF_TRANSLUCENT|FF_SWIMMABLE|FF_GOOWATER|FF_BOTHPLANES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_DOUBLESHADOW; - if (lines[i].flags & ML_EFFECT4) - ffloorflags |= FF_COLORMAPONLY; - if (lines[i].flags & ML_EFFECT5) - ffloorflags |= FF_RIPPLE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; + case 170: // FOF (Crumbling) + ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CRUMBLE; - case 140: // 'Platform' - You can jump up through it - // If line has no-climb set, don't give it shadows, otherwise do - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_PLATFORM|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].flags & ML_NOCLIMB) + //Tangibility settings + if (lines[i].args[3] & TMFT_INTANGIBLETOP) + ffloorflags |= FF_REVERSEPLATFORM; + if (lines[i].args[3] & TMFT_INTANGIBLEBOTTOM) + ffloorflags |= FF_PLATFORM; + if (lines[i].args[3] & TMFT_DONTBLOCKPLAYER) + ffloorflags &= ~FF_BLOCKPLAYER; + if (lines[i].args[3] & TMFT_DONTBLOCKOTHERS) + ffloorflags &= ~FF_BLOCKOTHERS; + + //Flags + if (lines[i].args[4] & TMFC_NOSHADE) ffloorflags |= FF_NOSHADE; + if (lines[i].args[4] & TMFC_NORETURN) + ffloorflags |= FF_NORETURN; + if (lines[i].args[4] & TMFC_FLOATBOB) + ffloorflags |= FF_FLOATBOB; + if (lines[i].args[4] & TMFC_SPLAT) + ffloorflags |= FF_SPLAT; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; + //If translucent or player can enter it, cut inner walls + if (lines[i].args[1] < 0xff || (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE)) + ffloorflags |= FF_CUTEXTRA|FF_EXTRA; + else + ffloorflags |= FF_CUTLEVEL; - case 141: // Translucent "platform" - // If line has no-climb set, don't give it shadows, otherwise do - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_PLATFORM|FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_NOSHADE; - - // Draw the 'insides' of the block too - if (lines[i].flags & ML_EFFECT2) + //If player can enter it, render insides + if (lines[i].args[3] & TMFT_VISIBLEFROMINSIDE) { - ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; - ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); + if (ffloorflags & FF_RENDERPLANES) + ffloorflags |= FF_BOTHPLANES; + if (ffloorflags & FF_RENDERSIDES) + ffloorflags |= FF_ALLSIDES; } - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); + if (lines[i].args[4] & TMFC_AIRBOB) + P_AddAirbob(lines[i].frontsector, lines[i].args[0], 16*FRACUNIT, false, false, false); break; - case 142: // Translucent "platform" with no sides - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERPLANES|FF_TRANSLUCENT|FF_PLATFORM|FF_EXTRA|FF_CUTEXTRA; - if (lines[i].flags & ML_NOCLIMB) // shade it unless no-climb - ffloorflags |= FF_NOSHADE; - - // Draw the 'insides' of the block too - if (lines[i].flags & ML_EFFECT2) - { - ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; - ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); - } - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 143: // 'Reverse platform' - You fall through it - // If line has no-climb set, don't give it shadows, otherwise do - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_REVERSEPLATFORM|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_NOSHADE; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 144: // Translucent "reverse platform" - // If line has no-climb set, don't give it shadows, otherwise do - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_REVERSEPLATFORM|FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_NOSHADE; - - // Draw the 'insides' of the block too - if (lines[i].flags & ML_EFFECT2) - { - ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; - ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); - } - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 145: // Translucent "reverse platform" with no sides - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERPLANES|FF_TRANSLUCENT|FF_REVERSEPLATFORM|FF_EXTRA|FF_CUTEXTRA; - if (lines[i].flags & ML_NOCLIMB) // shade it unless no-climb - ffloorflags |= FF_NOSHADE; - - // Draw the 'insides' of the block too - if (lines[i].flags & ML_EFFECT2) - { - ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; - ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); - } - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 146: // Intangible floor/ceiling with solid sides (fences/hoops maybe?) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERSIDES|FF_ALLSIDES|FF_INTANGIBLEFLATS, secthinkers); - break; - - case 150: // Air bobbing platform - case 151: // Adjustable air bobbing platform + case 190: // FOF (Rising) { - fixed_t dist = (lines[i].special == 150) ? 16*FRACUNIT : P_AproxDistance(lines[i].dx, lines[i].dy); - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, tag, dist, false, !!(lines[i].flags & ML_NOCLIMB), false); - break; - } - case 152: // Adjustable air bobbing platform in reverse - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, tag, P_AproxDistance(lines[i].dx, lines[i].dy), true, !!(lines[i].flags & ML_NOCLIMB), false); - break; - case 153: // Dynamic Sinking Platform - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, tag, P_AproxDistance(lines[i].dx, lines[i].dy), false, !!(lines[i].flags & ML_NOCLIMB), true); - break; - - case 160: // Float/bob platform - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB, secthinkers); - break; - - case 170: // Crumbling platform - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE, secthinkers); - break; - - case 171: // Crumbling platform that will not return - P_AddFakeFloorsByLine(i, - FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE|FF_NORETURN, secthinkers); - break; - - case 172: // "Platform" that crumbles and returns - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_PLATFORM|FF_CRUMBLE|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].flags & ML_NOCLIMB) // shade it unless no-climb - ffloorflags |= FF_NOSHADE; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 173: // "Platform" that crumbles and doesn't return - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_PLATFORM|FF_CRUMBLE|FF_NORETURN|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].flags & ML_NOCLIMB) // shade it unless no-climb - ffloorflags |= FF_NOSHADE; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 174: // Translucent "platform" that crumbles and returns - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_CRUMBLE|FF_TRANSLUCENT|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].flags & ML_NOCLIMB) // shade it unless no-climb - ffloorflags |= FF_NOSHADE; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 175: // Translucent "platform" that crumbles and doesn't return - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_PLATFORM|FF_CRUMBLE|FF_NORETURN|FF_TRANSLUCENT|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].flags & ML_NOCLIMB) // shade it unless no-climb - ffloorflags |= FF_NOSHADE; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 176: // Air bobbing platform that will crumble and bob on the water when it falls and hits - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB|FF_CRUMBLE, secthinkers); - P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); - break; - - case 177: // Air bobbing platform that will crumble and bob on - // the water when it falls and hits, then never return - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB|FF_CRUMBLE|FF_NORETURN, secthinkers); - P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); - break; - - case 178: // Crumbling platform that will float when it hits water - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CRUMBLE|FF_FLOATBOB, secthinkers); - break; - - case 179: // Crumbling platform that will float when it hits water, but not return - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE|FF_FLOATBOB|FF_NORETURN, secthinkers); - break; - - case 180: // Air bobbing platform that will crumble - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE, secthinkers); - P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); - break; - - case 190: // Rising Platform FOF (solid, opaque, shadows) - case 191: // Rising Platform FOF (solid, opaque, no shadows) - case 192: // Rising Platform TL block: FOF (solid, translucent) - case 193: // Rising Platform FOF (solid, invisible) - case 194: // Rising Platform 'Platform' - You can jump up through it - case 195: // Rising Platform Translucent "platform" - { - fixed_t speed = FixedDiv(P_AproxDistance(lines[i].dx, lines[i].dy), 4*FRACUNIT); fixed_t ceilingtop = P_FindHighestCeilingSurrounding(lines[i].frontsector); fixed_t ceilingbottom = P_FindLowestCeilingSurrounding(lines[i].frontsector); - ffloorflags = FF_EXISTS|FF_SOLID; - if (lines[i].special != 193) - ffloorflags |= FF_RENDERALL; - if (lines[i].special <= 191) - ffloorflags |= FF_CUTLEVEL; - if (lines[i].special == 192 || lines[i].special == 195) - ffloorflags |= FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA; - if (lines[i].special >= 194) - ffloorflags |= FF_PLATFORM|FF_BOTHPLANES|FF_ALLSIDES; - if (lines[i].special != 190 && (lines[i].special <= 193 || lines[i].flags & ML_NOCLIMB)) - ffloorflags |= FF_NOSHADE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL; - P_AddRaiseThinker(lines[i].frontsector, tag, speed, ceilingtop, ceilingbottom, !!(lines[i].flags & ML_BLOCKMONSTERS), !!(lines[i].flags & ML_NOCLIMB)); + //Appearance settings + if (lines[i].args[3] & TMFA_NOPLANES) + ffloorflags &= ~FF_RENDERPLANES; + if (lines[i].args[3] & TMFA_NOSIDES) + ffloorflags &= ~FF_RENDERSIDES; + if (lines[i].args[3] & TMFA_INSIDES) + { + if (ffloorflags & FF_RENDERPLANES) + ffloorflags |= FF_BOTHPLANES; + if (ffloorflags & FF_RENDERSIDES) + ffloorflags |= FF_ALLSIDES; + } + if (lines[i].args[3] & TMFA_ONLYINSIDES) + { + if (ffloorflags & FF_RENDERPLANES) + ffloorflags |= FF_INVERTPLANES; + if (ffloorflags & FF_RENDERSIDES) + ffloorflags |= FF_INVERTSIDES; + } + if (lines[i].args[3] & TMFA_NOSHADE) + ffloorflags |= FF_NOSHADE; + if (lines[i].args[3] & TMFA_SPLAT) + ffloorflags |= FF_SPLAT; + + //Tangibility settings + if (lines[i].args[4] & TMFT_INTANGIBLETOP) + ffloorflags |= FF_REVERSEPLATFORM; + if (lines[i].args[4] & TMFT_INTANGIBLEBOTTOM) + ffloorflags |= FF_PLATFORM; + if (lines[i].args[4] & TMFT_DONTBLOCKPLAYER) + ffloorflags &= ~FF_BLOCKPLAYER; + if (lines[i].args[4] & TMFT_DONTBLOCKOTHERS) + ffloorflags &= ~FF_BLOCKOTHERS; + + //Cutting options + if (ffloorflags & FF_RENDERALL) + { + //If translucent or player can enter it, cut inner walls + if ((lines[i].args[1] < 255) || (lines[i].args[4] & TMFT_VISIBLEFROMINSIDE)) + ffloorflags |= FF_CUTEXTRA|FF_EXTRA; + else + ffloorflags |= FF_CUTLEVEL; + } + + P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); + P_AddRaiseThinker(lines[i].frontsector, lines[i].args[0], lines[i].args[5] << FRACBITS, ceilingtop, ceilingbottom, !!(lines[i].args[6] & TMFR_REVERSE), !!(lines[i].args[6] & TMFR_SPINDASH)); break; } - - case 200: // Double light effect - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_CUTSPRITES|FF_DOUBLESHADOW, secthinkers); - break; - - case 201: // Light effect - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_CUTSPRITES, secthinkers); + case 200: // Light block + ffloorflags = FF_EXISTS|FF_CUTSPRITES; + if (!lines[i].args[1]) + ffloorflags |= FF_DOUBLESHADOW; + P_AddFakeFloorsByLine(i, 0xff, TMB_TRANSLUCENT, ffloorflags, secthinkers); break; case 202: // Fog @@ -6717,136 +6653,274 @@ void P_SpawnSpecials(boolean fromnetsave) // SoM: Because it's fog, check for an extra colormap and set the fog flag... if (sectors[sec].extra_colormap) sectors[sec].extra_colormap->flags = CMF_FOG; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + P_AddFakeFloorsByLine(i, 0xff, TMB_TRANSLUCENT, ffloorflags, secthinkers); break; - case 220: // Like opaque water, but not swimmable. (Good for snow effect on FOFs) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES, secthinkers); - break; + case 220: //Intangible + ffloorflags = FF_EXISTS|FF_RENDERALL|FF_CUTEXTRA|FF_EXTRA|FF_CUTSPRITES; - case 221: // FOF (intangible, translucent) - // If line has no-climb set, give it shadows, otherwise don't - ffloorflags = FF_EXISTS|FF_RENDERALL|FF_TRANSLUCENT|FF_EXTRA|FF_CUTEXTRA|FF_CUTSPRITES; - if (!(lines[i].flags & ML_NOCLIMB)) + //Appearance settings + if (lines[i].args[3] & TMFA_NOPLANES) + ffloorflags &= ~FF_RENDERPLANES; + if (lines[i].args[3] & TMFA_NOSIDES) + ffloorflags &= ~FF_RENDERSIDES; + if (!(lines[i].args[3] & TMFA_INSIDES)) + { + if (ffloorflags & FF_RENDERPLANES) + ffloorflags |= FF_BOTHPLANES; + if (ffloorflags & FF_RENDERSIDES) + ffloorflags |= FF_ALLSIDES; + } + if (lines[i].args[3] & TMFA_ONLYINSIDES) + { + if (ffloorflags & FF_RENDERPLANES) + ffloorflags |= FF_INVERTPLANES; + if (ffloorflags & FF_RENDERSIDES) + ffloorflags |= FF_INVERTSIDES; + } + if (lines[i].args[3] & TMFA_NOSHADE) ffloorflags |= FF_NOSHADE; + if (lines[i].args[3] & TMFA_SPLAT) + ffloorflags |= FF_SPLAT; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 222: // FOF with no floor/ceiling (good for GFZGRASS effect on FOFs) - // If line has no-climb set, give it shadows, otherwise don't - ffloorflags = FF_EXISTS|FF_RENDERSIDES|FF_ALLSIDES; - if (!(lines[i].flags & ML_NOCLIMB)) - ffloorflags |= FF_NOSHADE|FF_CUTSPRITES; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); break; case 223: // FOF (intangible, invisible) - for combining specials in a sector - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_NOSHADE, secthinkers); + P_AddFakeFloorsByLine(i, 0xff, TMB_TRANSLUCENT, FF_EXISTS|FF_NOSHADE, secthinkers); break; case 250: // Mario Block ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_SHATTERBOTTOM; - if (lines[i].flags & ML_EFFECT1) + if (lines[i].args[1] & TMFM_BRICK) + ffloorflags |= FF_GOOWATER; + if (lines[i].args[1] & TMFM_INVISIBLE) ffloorflags &= ~(FF_SOLID|FF_RENDERALL|FF_CUTLEVEL); - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + P_AddFakeFloorsByLine(i, 0xff, TMB_TRANSLUCENT, ffloorflags, secthinkers); break; case 251: // A THWOMP! { - fixed_t crushspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dy >> 3 : 10*FRACUNIT; - fixed_t retractspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dx >> 3 : 2*FRACUNIT; - UINT16 sound = (lines[i].flags & ML_EFFECT4) ? sides[lines[i].sidenum[0]].textureoffset >> FRACBITS : sfx_thwomp; - P_AddThwompThinker(lines[i].frontsector, &lines[i], crushspeed, retractspeed, sound); - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); + UINT16 sound = (lines[i].stringargs[0]) ? get_number(lines[i].stringargs[0]) : sfx_thwomp; + P_AddThwompThinker(lines[i].frontsector, &lines[i], lines[i].args[1] << (FRACBITS - 3), lines[i].args[2] << (FRACBITS - 3), sound); + P_AddFakeFloorsByLine(i, 0xff, TMB_TRANSLUCENT, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); break; } - case 252: // Shatter block (breaks when touched) - ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_BLOCKPLAYER|FF_SHATTERBOTTOM; - - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - break; - - case 253: // Translucent shatter block (see 76) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_TRANSLUCENT, secthinkers); - break; - case 254: // Bustable block - ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP; - if (lines[i].flags & ML_NOCLIMB) - ffloorflags |= FF_STRONGBUST; + { + UINT8 busttype = BT_REGULAR; + ffloorbustflags_e bustflags = 0; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP; + + //Bustable type + switch (lines[i].args[3]) + { + case TMFB_TOUCH: + busttype = BT_TOUCH; + break; + case TMFB_SPIN: + busttype = BT_SPINBUST; + break; + case TMFB_REGULAR: + busttype = BT_REGULAR; + break; + case TMFB_STRONG: + busttype = BT_STRONG; + break; + } + + //Flags + if (lines[i].args[4] & TMFB_PUSHABLES) + bustflags |= FB_PUSHABLES; + if (lines[i].args[4] & TMFB_EXECUTOR) + bustflags |= FB_EXECUTOR; + if (lines[i].args[4] & TMFB_ONLYBOTTOM) + bustflags |= FB_ONLYBOTTOM; + if (lines[i].args[4] & TMFB_SPLAT) + ffloorflags |= FF_SPLAT; + + if (busttype != BT_TOUCH || bustflags & FB_ONLYBOTTOM) + ffloorflags |= FF_BLOCKPLAYER; + + TAG_ITER_SECTORS(lines[i].args[0], s) + { + ffloor_t *fflr = P_AddFakeFloor(§ors[s], lines[i].frontsector, lines + i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); + if (!fflr) + continue; + fflr->bustflags = bustflags; + fflr->busttype = busttype; + fflr->busttag = lines[i].args[5]; + } break; - - case 255: // Spin bust block (breaks when jumped or spun downwards onto) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SPINBUST, secthinkers); - break; - - case 256: // Translucent spin bust block (see 78) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SPINBUST|FF_TRANSLUCENT, secthinkers); - break; - + } case 257: // Quicksand ffloorflags = FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES; - if (lines[i].flags & ML_EFFECT5) + if (!(lines[i].args[1])) ffloorflags |= FF_RIPPLE; - P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); + TAG_ITER_SECTORS(lines[i].args[0], s) + { + ffloor_t *fflr = P_AddFakeFloor(§ors[s], lines[i].frontsector, lines + i, 0xff, TMB_TRANSLUCENT, ffloorflags, secthinkers); + if (!fflr) + continue; + fflr->sinkspeed = abs(lines[i].args[2]) << (FRACBITS - 1); + fflr->friction = abs(lines[i].args[3]) << (FRACBITS - 6); + } break; case 258: // Laser block - P_AddLaserThinker(tag, lines + i, !!(lines[i].flags & ML_EFFECT1)); - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT, secthinkers); + ffloorflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT; + P_AddLaserThinker(lines[i].args[0], lines + i, !!(lines[i].args[3] & TMFL_NOBOSSES)); + if (lines[i].args[3] & TMFL_SPLAT) + ffloorflags |= FF_SPLAT; + P_AddFakeFloorsByLine(i, lines[i].args[1], lines[i].args[2], ffloorflags, secthinkers); break; case 259: // Custom FOF - if (lines[i].sidenum[1] != 0xffff) + TAG_ITER_SECTORS(lines[i].args[0], s) { - ffloortype_e fofflags = sides[lines[i].sidenum[1]].toptexture; - P_AddFakeFloorsByLine(i, fofflags, secthinkers); + ffloor_t *fflr = P_AddFakeFloor(§ors[s], lines[i].frontsector, lines + i, lines[i].args[1], lines[i].args[2], lines[i].args[3], secthinkers); + if (!fflr) + continue; + if (!udmf) // Ugly backwards compatibility stuff + { + if (lines[i].args[3] & FF_QUICKSAND) + { + fflr->sinkspeed = abs(lines[i].dx) >> 1; + fflr->friction = abs(lines[i].dy) >> 6; + } + if (lines[i].args[3] & FF_BUSTUP) + { + switch (lines[i].args[4] % TMFB_ONLYBOTTOM) + { + case TMFB_TOUCH: + fflr->busttype = BT_TOUCH; + break; + case TMFB_SPIN: + fflr->busttype = BT_SPINBUST; + break; + case TMFB_REGULAR: + fflr->busttype = BT_REGULAR; + break; + case TMFB_STRONG: + fflr->busttype = BT_STRONG; + break; + } + + if (lines[i].args[4] & TMFB_ONLYBOTTOM) + fflr->bustflags |= FB_ONLYBOTTOM; + if (lines[i].flags & ML_MIDSOLID) + fflr->bustflags |= FB_PUSHABLES; + if (lines[i].flags & ML_WRAPMIDTEX) + { + fflr->bustflags |= FB_EXECUTOR; + fflr->busttag = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; + } + } + } } - else - I_Error("Custom FOF (tag %d) found without a linedef back side!", tag); break; - case 300: // Linedef executor (combines with sector special 974/975) and commands - case 302: - case 303: - case 304: + case 260: // GZDoom-like 3D Floor. + { + UINT8 dtype = lines[i].args[1] & 3; + UINT8 dflags1 = lines[i].args[1] - dtype; + UINT8 dflags2 = lines[i].args[2]; + UINT8 dopacity = lines[i].args[3]; + boolean isfog = false; - // Charability linedef executors - case 305: - case 307: + if (dtype == 0) + dtype = 1; + + ffloorflags = FF_EXISTS; + + if (dflags2 & 1) ffloorflags |= FF_NOSHADE; // Disable light effects (Means no shadowcast) + if (dflags2 & 2) ffloorflags |= FF_DOUBLESHADOW; // Restrict light inside (Means doubleshadow) + if (dflags2 & 4) isfog = true; // Fog effect (Explicitly render like a fog block) + + if (dflags1 & 4) ffloorflags |= FF_BOTHPLANES|FF_ALLSIDES; // Render-inside + if (dflags1 & 16) ffloorflags |= FF_INVERTSIDES|FF_INVERTPLANES; // Invert visibility rules + + // Fog block + if (isfog) + ffloorflags |= FF_RENDERALL|FF_CUTEXTRA|FF_CUTSPRITES|FF_BOTHPLANES|FF_EXTRA|FF_FOG|FF_INVERTPLANES|FF_ALLSIDES|FF_INVERTSIDES; + else + { + ffloorflags |= FF_RENDERALL; + + // Solid + if (dtype == 1) + ffloorflags |= FF_SOLID|FF_CUTLEVEL; + // Water + else if (dtype == 2) + ffloorflags |= FF_SWIMMABLE|FF_CUTEXTRA|FF_CUTSPRITES|FF_EXTRA|FF_RIPPLE; + // Intangible + else if (dtype == 3) + ffloorflags |= FF_CUTEXTRA|FF_CUTSPRITES|FF_EXTRA; + } + + // Non-opaque + if (dopacity < 255) + { + // Invisible + if (dopacity == 0) + { + // True invisible + if (ffloorflags & FF_NOSHADE) + ffloorflags &= ~(FF_RENDERALL|FF_CUTEXTRA|FF_CUTSPRITES|FF_EXTRA|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTLEVEL); + // Shadow block + else + { + ffloorflags |= FF_CUTSPRITES; + ffloorflags &= ~(FF_RENDERALL|FF_CUTEXTRA|FF_EXTRA|FF_BOTHPLANES|FF_ALLSIDES|FF_CUTLEVEL); + } + } + else + { + ffloorflags |= FF_TRANSLUCENT|FF_CUTEXTRA|FF_EXTRA; + ffloorflags &= ~FF_CUTLEVEL; + } + } + + P_AddFakeFloorsByLine(i, dopacity, TMB_TRANSLUCENT, ffloorflags, secthinkers); + } + break; + + case 300: // Trigger linedef executor + case 303: // Count rings + case 305: // Character ability + case 314: // Pushable linedef executors (count # of pushables) + case 317: // Condition set trigger + case 319: // Unlockable trigger + case 331: // Player skin + case 334: // Object dye + case 337: // Emerald check + if (lines[i].args[0] > TMT_EACHTIMEMASK) + P_AddEachTimeThinker(&lines[i], lines[i].args[0] == TMT_EACHTIMEENTERANDEXIT); break; case 308: // Race-only linedef executor. Triggers once. - if (!(gametyperules & GTR_RACE)) + if (!P_CheckGametypeRules(lines[i].args[2], (UINT32)lines[i].args[1])) + { lines[i].special = 0; + break; + } + if (lines[i].args[0] > TMT_EACHTIMEMASK) + P_AddEachTimeThinker(&lines[i], lines[i].args[0] == TMT_EACHTIMEENTERANDEXIT); break; // Linedef executor triggers for CTF teams. case 309: - case 311: if (!(gametyperules & GTR_TEAMFLAGS)) + { lines[i].special = 0; - break; - - // Each time executors - case 306: - case 301: - case 310: - case 312: - case 332: - case 335: - P_AddEachTimeThinker(&lines[i]); + break; + } + if (lines[i].args[0] > TMT_EACHTIMEMASK) + P_AddEachTimeThinker(&lines[i], lines[i].args[0] == TMT_EACHTIMEENTERANDEXIT); break; // No More Enemies Linedef Exec @@ -6854,100 +6928,24 @@ void P_SpawnSpecials(boolean fromnetsave) P_AddNoEnemiesThinker(&lines[i]); break; - // Pushable linedef executors (count # of pushables) - case 314: - case 315: - break; - - // Unlock trigger executors - case 317: - case 318: - break; - case 319: - case 320: - break; - // Trigger on X calls case 321: - case 322: - if (lines[i].flags & ML_NOCLIMB && sides[lines[i].sidenum[0]].rowoffset > 0) // optional "starting" count - lines[i].callcount = sides[lines[i].sidenum[0]].rowoffset>>FRACBITS; - else - lines[i].callcount = sides[lines[i].sidenum[0]].textureoffset>>FRACBITS; - if (lines[i].special == 322) // Each time - P_AddEachTimeThinker(&lines[i]); - break; - - // NiGHTS trigger executors - case 323: - case 324: - case 325: - case 326: - case 327: - case 328: - case 329: - case 330: - break; - - // Skin trigger executors - case 331: - case 333: - break; - - // Object dye executors - case 334: - case 336: - break; - - case 399: // Linedef execute on map load - // This is handled in P_RunLevelLoadExecutors. - break; - - case 400: - case 401: - case 402: - case 403: - case 404: - case 405: - case 406: - case 407: - case 408: - case 409: - case 410: - case 411: - case 412: - case 413: - case 414: - case 415: - case 416: - case 417: - case 418: - case 419: - case 420: - case 421: - case 422: - case 423: - case 424: - case 425: - case 426: - case 427: - case 428: - case 429: - case 430: - case 431: + lines[i].callcount = (lines[i].args[2] && lines[i].args[3] > 0) ? lines[i].args[3] : lines[i].args[1]; // optional "starting" count + if (lines[i].args[0] > TMXT_EACHTIMEMASK) // Each time + P_AddEachTimeThinker(&lines[i], lines[i].args[0] == TMXT_EACHTIMEENTERANDEXIT); break; case 449: // Enable bosses with parameter { - INT32 bossid = sides[*lines[i].sidenum].textureoffset>>FRACBITS; + INT32 bossid = lines[i].args[0]; if (bossid & ~15) // if any bits other than first 16 are set { CONS_Alert(CONS_WARNING, - M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), - tag); + M_GetText("Boss enable linedef has an invalid boss ID (%d).\nConsider changing it or removing it entirely.\n"), + bossid); break; } - if (!(lines[i].flags & ML_NOCLIMB)) + if (!(lines[i].args[1])) { bossdisabled |= (1<>FRACBITS); + TAG_ITER_SECTORS(lines[i].args[0], s) + P_SpawnAdjustableGlowingLight(§ors[s], lines[i].args[2], + lines[i].args[3] ? sectors[s].lightlevel : lines[i].args[4], lines[i].args[1]); break; case 603: // Adjustable flickering light sec = sides[*lines[i].sidenum].sector - sectors; - TAG_ITER_SECTORS(0, tag, s) - P_SpawnAdjustableFireFlicker(§ors[sec], §ors[s], - P_AproxDistance(lines[i].dx, lines[i].dy)>>FRACBITS); + TAG_ITER_SECTORS(lines[i].args[0], s) + P_SpawnAdjustableFireFlicker(§ors[s], lines[i].args[2], + lines[i].args[3] ? sectors[s].lightlevel : lines[i].args[4], lines[i].args[1]); break; - case 604: // Adjustable Blinking Light (unsynchronized) + case 604: // Adjustable Blinking Light sec = sides[*lines[i].sidenum].sector - sectors; - TAG_ITER_SECTORS(0, tag, s) - P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], - abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, false); - break; - - case 605: // Adjustable Blinking Light (synchronized) - sec = sides[*lines[i].sidenum].sector - sectors; - TAG_ITER_SECTORS(0, tag, s) - P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], - abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, true); + TAG_ITER_SECTORS(lines[i].args[0], s) + P_SpawnAdjustableStrobeFlash(§ors[s], lines[i].args[3], + (lines[i].args[4] & TMB_USETARGET) ? sectors[s].lightlevel : lines[i].args[5], + lines[i].args[1], lines[i].args[2], lines[i].args[4] & TMB_SYNC); break; case 606: // HACK! Copy colormaps. Just plain colormaps. - TAG_ITER_SECTORS(0, lines[i].args[0], s) + TAG_ITER_SECTORS(lines[i].args[0], s) { extracolormap_t *exc; @@ -7065,6 +7020,124 @@ void P_SpawnSpecials(boolean fromnetsave) } } + // And another round, this time with all FOFs already created + for (i = 0; i < numlines; i++) + { + switch (lines[i].special) + { + INT32 s; + INT32 l; + + case 74: // Make FOF bustable + { + UINT8 busttype = BT_REGULAR; + ffloorbustflags_e bustflags = 0; + + if (!udmf) + break; + + switch (lines[i].args[1]) + { + case TMFB_TOUCH: + busttype = BT_TOUCH; + break; + case TMFB_SPIN: + busttype = BT_SPINBUST; + break; + case TMFB_REGULAR: + busttype = BT_REGULAR; + break; + case TMFB_STRONG: + busttype = BT_STRONG; + break; + } + + if (lines[i].args[2] & TMFB_PUSHABLES) + bustflags |= FB_PUSHABLES; + if (lines[i].args[2] & TMFB_EXECUTOR) + bustflags |= FB_EXECUTOR; + if (lines[i].args[2] & TMFB_ONLYBOTTOM) + bustflags |= FB_ONLYBOTTOM; + + TAG_ITER_LINES(lines[i].args[0], l) + { + if (lines[l].special < 100 || lines[l].special >= 300) + continue; + + TAG_ITER_SECTORS(lines[l].args[0], s) + { + ffloor_t *rover; + + for (rover = sectors[s].ffloors; rover; rover = rover->next) + { + if (rover->master != lines + l) + continue; + + rover->flags |= FF_BUSTUP; + rover->spawnflags |= FF_BUSTUP; + rover->bustflags = bustflags; + rover->busttype = busttype; + rover->busttag = lines[i].args[3]; + CheckForBustableBlocks = true; + break; + } + } + } + break; + } + + case 75: // Make FOF quicksand + { + if (!udmf) + break; + TAG_ITER_LINES(lines[i].args[0], l) + { + if (lines[l].special < 100 || lines[l].special >= 300) + continue; + + TAG_ITER_SECTORS(lines[l].args[0], s) + { + ffloor_t *rover; + + for (rover = sectors[s].ffloors; rover; rover = rover->next) + { + if (rover->master != lines + l) + continue; + + rover->flags |= FF_QUICKSAND; + rover->spawnflags |= FF_QUICKSAND; + rover->sinkspeed = abs(lines[i].args[1]) << (FRACBITS - 1); + rover->friction = abs(lines[i].args[2]) << (FRACBITS - 6); + CheckForQuicksand = true; + break; + } + } + } + break; + } + + case 76: // Make FOF bouncy + { + if (udmf) + { + TAG_ITER_LINES(lines[i].args[0], l) + P_MakeFOFBouncy(lines + i, lines + l); + } + else + { + TAG_ITER_SECTORS(lines[i].args[0], s) + for (j = 0; (unsigned)j < sectors[s].linecount; j++) + P_MakeFOFBouncy(lines + i, sectors[s].lines[j]); + } + break; + } + } + } + + + + + // Allocate each list for (i = 0; i < numsectors; i++) if(secthinkers[i].thinkers) @@ -7093,27 +7166,29 @@ void P_SpawnSpecials(boolean fromnetsave) } } - P_RunLevelLoadExecutors(); + if (!fromnetsave) + P_RunLevelLoadExecutors(); } /** Adds 3Dfloors as appropriate based on a common control linedef. * * \param line Control linedef to use. + * \param alpha Alpha value (0-255). + * \param blendmode Blending mode. * \param ffloorflags 3Dfloor flags to use. * \param secthkiners Lists of thinkers sorted by sector. May be NULL. * \sa P_SpawnSpecials, P_AddFakeFloor * \author Graue */ -static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinkerlist_t *secthinkers) +static void P_AddFakeFloorsByLine(size_t line, INT32 alpha, UINT8 blendmode, ffloortype_e ffloorflags, thinkerlist_t *secthinkers) { - TAG_ITER_DECLARECOUNTER(0); INT32 s; - mtag_t tag = Tag_FGet(&lines[line].tags); + mtag_t tag = lines[line].args[0]; size_t sec = sides[*lines[line].sidenum].sector-sectors; line_t* li = lines + line; - TAG_ITER_SECTORS(0, tag, s) - P_AddFakeFloor(§ors[s], §ors[sec], li, ffloorflags, secthinkers); + TAG_ITER_SECTORS(tag, s) + P_AddFakeFloor(§ors[s], §ors[sec], li, alpha, blendmode, ffloorflags, secthinkers); } /* @@ -7222,7 +7297,6 @@ void T_Scroll(scroll_t *s) size_t i; INT32 sect; ffloor_t *rover; - TAG_ITER_DECLARECOUNTER(0); case sc_side: // scroll wall texture side = sides + s->affectee; @@ -7259,7 +7333,7 @@ void T_Scroll(scroll_t *s) if (!is3dblock) continue; - TAG_ITER_SECTORS(0, Tag_FGet(&line->tags), sect) + TAG_ITER_SECTORS(line->args[0], sect) { sector_t *psec; psec = sectors + sect; @@ -7334,7 +7408,7 @@ void T_Scroll(scroll_t *s) if (!is3dblock) continue; - TAG_ITER_SECTORS(0, Tag_FGet(&line->tags), sect) + TAG_ITER_SECTORS(line->args[0], sect) { sector_t *psec; psec = sectors + sect; @@ -7417,12 +7491,33 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3 s->accel = accel; s->exclusive = exclusive; s->vdx = s->vdy = 0; - if ((s->control = control) != -1) + s->control = control; + if (s->control != -1) s->last_height = sectors[control].floorheight + sectors[control].ceilingheight; s->affectee = affectee; + if (type == sc_carry || type == sc_carry_ceiling) + sectors[affectee].specialflags |= SSF_CONVEYOR; P_AddThinker(THINK_MAIN, &s->thinker); } +static void P_SpawnPlaneScroller(line_t *l, fixed_t dx, fixed_t dy, INT32 control, INT32 affectee, INT32 accel, INT32 exclusive) +{ + if (l->args[1] != TMP_CEILING) + { + if (l->args[2] != TMS_SCROLLONLY) + Add_Scroller(sc_carry, FixedMul(dx, CARRYFACTOR), FixedMul(dy, CARRYFACTOR), control, affectee, accel, exclusive); + if (l->args[2] != TMS_CARRYONLY) + Add_Scroller(sc_floor, -dx, dy, control, affectee, accel, exclusive); + } + if (l->args[1] != TMP_FLOOR) + { + if (l->args[2] != TMS_SCROLLONLY) + Add_Scroller(sc_carry_ceiling, FixedMul(dx, CARRYFACTOR), FixedMul(dy, CARRYFACTOR), control, affectee, accel, exclusive); + if (l->args[2] != TMS_CARRYONLY) + Add_Scroller(sc_ceiling, -dx, dy, control, affectee, accel, exclusive); + } +} + /** Initializes the scrollers. * * \todo Get rid of all the magic numbers. @@ -7432,141 +7527,65 @@ static void P_SpawnScrollers(void) { size_t i; line_t *l = lines; - mtag_t tag; for (i = 0; i < numlines; i++, l++) { - fixed_t dx = l->dx >> SCROLL_SHIFT; // direction and speed of scrolling - fixed_t dy = l->dy >> SCROLL_SHIFT; INT32 control = -1, accel = 0; // no control sector or acceleration - INT32 special = l->special; - tag = Tag_FGet(&l->tags); - - // These types are same as the ones they get set to except that the - // first side's sector's heights cause scrolling when they change, and - // this linedef controls the direction and speed of the scrolling. The - // most complicated linedef since donuts, but powerful :) - - if (special == 515 || special == 512 || special == 522 || special == 532 || special == 504) // displacement scrollers + if (l->special == 502 || l->special == 510) { - special -= 2; - control = (INT32)(sides[*l->sidenum].sector - sectors); - } - else if (special == 514 || special == 511 || special == 521 || special == 531 || special == 503) // accelerative scrollers - { - special--; - accel = 1; - control = (INT32)(sides[*l->sidenum].sector - sectors); - } - else if (special == 535 || special == 525) // displacement scrollers - { - special -= 2; - control = (INT32)(sides[*l->sidenum].sector - sectors); - } - else if (special == 534 || special == 524) // accelerative scrollers - { - accel = 1; - special--; - control = (INT32)(sides[*l->sidenum].sector - sectors); + if ((l->args[4] & TMST_TYPEMASK) != TMST_REGULAR) + control = (INT32)(sides[*l->sidenum].sector - sectors); + if ((l->args[4] & TMST_TYPEMASK) == TMST_ACCELERATIVE) + accel = 1; } - switch (special) + switch (l->special) { register INT32 s; - TAG_ITER_DECLARECOUNTER(0); - case 513: // scroll effect ceiling - case 533: // scroll and carry objects on ceiling - TAG_ITER_SECTORS(0, tag, s) - Add_Scroller(sc_ceiling, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); - if (special != 533) - break; - /* FALLTHRU */ + case 510: // plane scroller + { + fixed_t length = R_PointToDist2(l->v2->x, l->v2->y, l->v1->x, l->v1->y); + fixed_t speed = l->args[3] << FRACBITS; + fixed_t dx = FixedMul(FixedDiv(l->dx, length), speed) >> SCROLL_SHIFT; + fixed_t dy = FixedMul(FixedDiv(l->dy, length), speed) >> SCROLL_SHIFT; - case 523: // carry objects on ceiling - dx = FixedMul(dx, CARRYFACTOR); - dy = FixedMul(dy, CARRYFACTOR); - TAG_ITER_SECTORS(0, tag, s) - Add_Scroller(sc_carry_ceiling, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); - break; - - case 510: // scroll effect floor - case 530: // scroll and carry objects on floor - TAG_ITER_SECTORS(0, tag, s) - Add_Scroller(sc_floor, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); - if (special != 530) - break; - /* FALLTHRU */ - - case 520: // carry objects on floor - dx = FixedMul(dx, CARRYFACTOR); - dy = FixedMul(dy, CARRYFACTOR); - TAG_ITER_SECTORS(0, tag, s) - Add_Scroller(sc_carry, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); + if (l->args[0] == 0) + P_SpawnPlaneScroller(l, dx, dy, control, (INT32)(l->frontsector - sectors), accel, l->args[4] & TMST_NONEXCLUSIVE); + else + { + TAG_ITER_SECTORS(l->args[0], s) + P_SpawnPlaneScroller(l, dx, dy, control, s, accel, l->args[4] & TMST_NONEXCLUSIVE); + } break; + } // scroll wall according to linedef // (same direction and speed as scrolling floors) case 502: { - TAG_ITER_LINES(0, tag, s) + TAG_ITER_LINES(l->args[0], s) if (s != (INT32)i) { - if (l->flags & ML_EFFECT2) // use texture offsets instead - { - dx = sides[l->sidenum[0]].textureoffset; - dy = sides[l->sidenum[0]].rowoffset; - } - if (l->flags & ML_EFFECT3) - { - if (lines[s].sidenum[1] != 0xffff) - Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[1], accel, 0); - } - else - Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[0], accel, 0); + if (l->args[1] != TMSD_BACK) + Add_Scroller(sc_side, l->args[2] << (FRACBITS - SCROLL_SHIFT), l->args[3] << (FRACBITS - SCROLL_SHIFT), control, lines[s].sidenum[0], accel, 0); + if (l->args[1] != TMSD_FRONT && lines[s].sidenum[1] != 0xffff) + Add_Scroller(sc_side, l->args[2] << (FRACBITS - SCROLL_SHIFT), l->args[3] << (FRACBITS - SCROLL_SHIFT), control, lines[s].sidenum[1], accel, 0); } break; } - case 505: - s = lines[i].sidenum[0]; - Add_Scroller(sc_side, -sides[s].textureoffset, sides[s].rowoffset, -1, s, accel, 0); - break; - - case 506: - s = lines[i].sidenum[1]; - - if (s != 0xffff) - Add_Scroller(sc_side, -sides[s].textureoffset, sides[s].rowoffset, -1, lines[i].sidenum[0], accel, 0); - else - CONS_Debug(DBG_GAMELOGIC, "Line special 506 (line #%s) missing back side!\n", sizeu1(i)); - break; - - case 507: - s = lines[i].sidenum[0]; - - if (lines[i].sidenum[1] != 0xffff) - Add_Scroller(sc_side, -sides[s].textureoffset, sides[s].rowoffset, -1, lines[i].sidenum[1], accel, 0); - else - CONS_Debug(DBG_GAMELOGIC, "Line special 507 (line #%s) missing back side!\n", sizeu1(i)); - break; - - case 508: - s = lines[i].sidenum[1]; - - if (s != 0xffff) - Add_Scroller(sc_side, -sides[s].textureoffset, sides[s].rowoffset, -1, s, accel, 0); - else - CONS_Debug(DBG_GAMELOGIC, "Line special 508 (line #%s) missing back side!\n", sizeu1(i)); - break; - - case 500: // scroll first side - Add_Scroller(sc_side, FRACUNIT, 0, -1, lines[i].sidenum[0], accel, 0); - break; - - case 501: // jff 1/30/98 2-way scroll - Add_Scroller(sc_side, -FRACUNIT, 0, -1, lines[i].sidenum[0], accel, 0); + case 500: + if (l->args[0] != TMSD_BACK) + Add_Scroller(sc_side, -l->args[1] << FRACBITS, l->args[2] << FRACBITS, -1, l->sidenum[0], accel, 0); + if (l->args[0] != TMSD_FRONT) + { + if (l->sidenum[1] != 0xffff) + Add_Scroller(sc_side, -l->args[1] << FRACBITS, l->args[2] << FRACBITS, -1, l->sidenum[1], accel, 0); + else + CONS_Debug(DBG_GAMELOGIC, "Line special 500 (line #%s) missing back side!\n", sizeu1(i)); + } break; } } @@ -7611,10 +7630,9 @@ void T_Disappear(disappear_t *d) { ffloor_t *rover; register INT32 s; - mtag_t afftag = Tag_FGet(&lines[d->affectee].tags); - TAG_ITER_DECLARECOUNTER(0); + mtag_t afftag = lines[d->affectee].args[0]; - TAG_ITER_SECTORS(0, afftag, s) + TAG_ITER_SECTORS(afftag, s) { for (rover = sectors[s].ffloors; rover; rover = rover->next) { @@ -7627,7 +7645,7 @@ void T_Disappear(disappear_t *d) { rover->flags |= FF_EXISTS; - if (!(lines[d->sourceline].flags & ML_NOCLIMB)) + if (!(lines[d->sourceline].args[5])) { sectors[s].soundorg.z = P_GetFFloorTopZAt(rover, sectors[s].soundorg.x, sectors[s].soundorg.y); S_StartSound(§ors[s].soundorg, sfx_appear); @@ -8110,7 +8128,7 @@ static void P_ResetColormapFader(sector_t *sector) // The thinker is the first member in all the action structs, // so just let the thinker get freed, and that will free the whole // structure. - P_RemoveThinker(&((elevator_t *)sector->fadecolormapdata)->thinker); + P_RemoveThinker(&((thinkerdata_t *)sector->fadecolormapdata)->thinker); sector->fadecolormapdata = NULL; } } @@ -8339,41 +8357,32 @@ void T_Friction(friction_t *f) static void P_SpawnFriction(void) { size_t i; - line_t *l = lines; - mtag_t tag; - register INT32 s; - fixed_t strength; // frontside texture offset controls magnitude + sector_t *s = sectors; + fixed_t friction; // friction value to be applied during movement INT32 movefactor; // applied to each player move to simulate inertia - TAG_ITER_DECLARECOUNTER(0); - for (i = 0; i < numlines; i++, l++) - if (l->special == 540) - { - tag = Tag_FGet(&l->tags); - strength = sides[l->sidenum[0]].textureoffset>>FRACBITS; - if (strength > 0) // sludge - strength = strength*2; // otherwise, the maximum sludginess value is +967... + for (i = 0; i < numsectors; i++, s++) + { + if (s->friction == ORIG_FRICTION) + continue; - // The following might seem odd. At the time of movement, - // the move distance is multiplied by 'friction/0x10000', so a - // higher friction value actually means 'less friction'. - friction = ORIG_FRICTION - (0x1EB8*strength)/0x80; // ORIG_FRICTION is 0xE800 + friction = s->friction; - if (friction > FRACUNIT) - friction = FRACUNIT; - if (friction < 0) - friction = 0; + if (friction > FRACUNIT) + friction = FRACUNIT; + if (friction < 0) + friction = 0; - movefactor = FixedDiv(ORIG_FRICTION, friction); - if (movefactor < FRACUNIT) - movefactor = 8*movefactor - 7*FRACUNIT; - else - movefactor = FRACUNIT; + movefactor = FixedDiv(ORIG_FRICTION, friction); + if (movefactor < FRACUNIT) + movefactor = 8*movefactor - 7*FRACUNIT; + else + movefactor = FRACUNIT; - TAG_ITER_SECTORS(0, tag, s) - Add_Friction(friction, movefactor, s, -1); - } + Add_Friction(friction, movefactor, (INT32)(s-sectors), -1); + + } } /* @@ -8392,20 +8401,20 @@ static void P_SpawnFriction(void) * \param type Type of push/pull effect. * \param x_mag X magnitude. * \param y_mag Y magnitude. - * \param source For a point pusher/puller, the source object. + * \param z_mag Z magnitude. * \param affectee Target sector. * \param referrer What sector set it * \sa T_Pusher, P_GetPushThing, P_SpawnPushers */ -static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *source, INT32 affectee, INT32 referrer, INT32 exclusive, INT32 slider) +static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, fixed_t z_mag, INT32 affectee, INT32 referrer, INT32 exclusive, INT32 slider) { pusher_t *p = Z_Calloc(sizeof *p, PU_LEVSPEC, NULL); p->thinker.function.acp1 = (actionf_p1)T_Pusher; - p->source = source; p->type = type; - p->x_mag = x_mag>>FRACBITS; - p->y_mag = y_mag>>FRACBITS; + p->x_mag = x_mag; + p->y_mag = y_mag; + p->z_mag = z_mag; p->exclusive = exclusive; p->slider = slider; @@ -8413,182 +8422,18 @@ static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t * { p->roverpusher = true; p->referrer = referrer; + sectors[referrer].specialflags |= SSF_WINDCURRENT; } else - p->roverpusher = false; - - // "The right triangle of the square of the length of the hypotenuse is equal to the sum of the squares of the lengths of the other two sides." - // "Bah! Stupid brains! Don't you know anything besides the Pythagorean Theorem?" - Earthworm Jim - if (type == p_downcurrent || type == p_upcurrent || type == p_upwind || type == p_downwind) - p->magnitude = P_AproxDistance(p->x_mag,p->y_mag)<<(FRACBITS-PUSH_FACTOR); - else - p->magnitude = P_AproxDistance(p->x_mag,p->y_mag); - if (source) // point source exist? { - // where force goes to zero - if (type == p_push) - p->radius = AngleFixed(source->angle); - else - p->radius = (p->magnitude)<<(FRACBITS+1); - - p->x = p->source->x; - p->y = p->source->y; - p->z = p->source->z; + p->roverpusher = false; + sectors[affectee].specialflags |= SSF_WINDCURRENT; } + p->affectee = affectee; P_AddThinker(THINK_MAIN, &p->thinker); } - -// PIT_PushThing determines the angle and magnitude of the effect. -// The object's x and y momentum values are changed. -static pusher_t *tmpusher; // pusher structure for blockmap searches - -/** Applies a point pusher/puller to a thing. - * - * \param thing Thing to be pushed. - * \return True if the thing was pushed. - * \todo Make a more robust P_BlockThingsIterator() so the hidden parameter - * ::tmpusher won't need to be used. - * \sa T_Pusher - */ -static inline boolean PIT_PushThing(mobj_t *thing) -{ - if (thing->eflags & MFE_PUSHED) - return false; - - if (thing->player && thing->player->powers[pw_carry] == CR_ROPEHANG) - return false; - - // Allow this to affect pushable objects at some point? - if (thing->player && (!(thing->flags & (MF_NOGRAVITY | MF_NOCLIP)) || thing->player->powers[pw_carry] == CR_NIGHTSMODE)) - { - INT32 dist; - INT32 speed; - INT32 sx, sy, sz; - - sx = tmpusher->x; - sy = tmpusher->y; - sz = tmpusher->z; - - // don't fade wrt Z if health & 2 (mapthing has multi flag) - if (tmpusher->source->health & 2) - dist = P_AproxDistance(thing->x - sx,thing->y - sy); - else - { - // Make sure the Z is in range - if (thing->z < sz - tmpusher->radius || thing->z > sz + tmpusher->radius) - return false; - - dist = P_AproxDistance(P_AproxDistance(thing->x - sx, thing->y - sy), - thing->z - sz); - } - - speed = (tmpusher->magnitude - ((dist>>FRACBITS)>>1))<<(FRACBITS - PUSH_FACTOR - 1); - - // If speed <= 0, you're outside the effective radius. You also have - // to be able to see the push/pull source point. - - // Written with bits and pieces of P_HomingAttack - if ((speed > 0) && (P_CheckSight(thing, tmpusher->source))) - { - if (thing->player->powers[pw_carry] != CR_NIGHTSMODE) - { - // only push wrt Z if health & 1 (mapthing has ambush flag) - if (tmpusher->source->health & 1) - { - fixed_t tmpmomx, tmpmomy, tmpmomz; - - tmpmomx = FixedMul(FixedDiv(sx - thing->x, dist), speed); - tmpmomy = FixedMul(FixedDiv(sy - thing->y, dist), speed); - tmpmomz = FixedMul(FixedDiv(sz - thing->z, dist), speed); - if (tmpusher->source->type == MT_PUSH) // away! - { - tmpmomx *= -1; - tmpmomy *= -1; - tmpmomz *= -1; - } - - thing->momx += tmpmomx; - thing->momy += tmpmomy; - thing->momz += tmpmomz; - - if (thing->player) - { - thing->player->cmomx += tmpmomx; - thing->player->cmomy += tmpmomy; - thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); - thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); - } - } - else - { - angle_t pushangle; - - pushangle = R_PointToAngle2(thing->x, thing->y, sx, sy); - if (tmpusher->source->type == MT_PUSH) - pushangle += ANGLE_180; // away - pushangle >>= ANGLETOFINESHIFT; - thing->momx += FixedMul(speed, FINECOSINE(pushangle)); - thing->momy += FixedMul(speed, FINESINE(pushangle)); - - if (thing->player) - { - thing->player->cmomx += FixedMul(speed, FINECOSINE(pushangle)); - thing->player->cmomy += FixedMul(speed, FINESINE(pushangle)); - thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); - thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); - } - } - } - else - { - //NiGHTS-specific handling. - //By default, pushes and pulls only affect the Z-axis. - //By having the ambush flag, it affects the X-axis. - //By having the object special flag, it affects the Y-axis. - fixed_t tmpmomx, tmpmomy, tmpmomz; - - if (tmpusher->source->health & 1) - tmpmomx = FixedMul(FixedDiv(sx - thing->x, dist), speed); - else - tmpmomx = 0; - - if (tmpusher->source->health & 2) - tmpmomy = FixedMul(FixedDiv(sy - thing->y, dist), speed); - else - tmpmomy = 0; - - tmpmomz = FixedMul(FixedDiv(sz - thing->z, dist), speed); - - if (tmpusher->source->type == MT_PUSH) // away! - { - tmpmomx *= -1; - tmpmomy *= -1; - tmpmomz *= -1; - } - - thing->momx += tmpmomx; - thing->momy += tmpmomy; - thing->momz += tmpmomz; - - if (thing->player) - { - thing->player->cmomx += tmpmomx; - thing->player->cmomy += tmpmomy; - thing->player->cmomx = FixedMul(thing->player->cmomx, 0xe800); - thing->player->cmomy = FixedMul(thing->player->cmomy, 0xe800); - } - } - } - } - - if (tmpusher->exclusive) - thing->eflags |= MFE_PUSHED; - - return true; -} - /** Applies a pusher to all affected objects. * * \param p Thinker for the pusher effect. @@ -8600,30 +8445,19 @@ void T_Pusher(pusher_t *p) sector_t *sec, *referrer = NULL; mobj_t *thing; msecnode_t *node; - INT32 xspeed = 0,yspeed = 0; - INT32 xl, xh, yl, yh, bx, by; - INT32 radius; - //INT32 ht = 0; + fixed_t x_mag, y_mag, z_mag; + fixed_t xspeed = 0, yspeed = 0, zspeed = 0; boolean inFOF; boolean touching; boolean moved; - xspeed = yspeed = 0; + x_mag = p->x_mag >> PUSH_FACTOR; + y_mag = p->y_mag >> PUSH_FACTOR; + z_mag = p->z_mag >> PUSH_FACTOR; sec = sectors + p->affectee; - - // Be sure the special sector type is still turned on. If so, proceed. - // Else, bail out; the sector type has been changed on us. - if (p->roverpusher) - { - referrer = §ors[p->referrer]; - - if (GETSECSPECIAL(referrer->special, 3) != 2) - return; - } - else if (GETSECSPECIAL(sec->special, 3) != 2) - return; + referrer = sectors + p->referrer; // For constant pushers (wind/current) there are 3 situations: // @@ -8643,29 +8477,6 @@ void T_Pusher(pusher_t *p) // // In Phase II, you can apply these effects to Things other than players. - if (p->type == p_push) - { - - // Seek out all pushable things within the force radius of this - // point pusher. Crosses sectors, so use blockmap. - - tmpusher = p; // MT_PUSH/MT_PULL point source - radius = p->radius; // where force goes to zero - tmbbox[BOXTOP] = p->y + radius; - tmbbox[BOXBOTTOM] = p->y - radius; - tmbbox[BOXRIGHT] = p->x + radius; - tmbbox[BOXLEFT] = p->x - radius; - - xl = (unsigned)(tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; - for (bx = xl; bx <= xh; bx++) - for (by = yl; by <= yh; by++) - P_BlockThingsIterator(bx,by, PIT_PushThing); - return; - } - // constant pushers p_wind and p_current node = sec->touching_thinglist; // things touching this sector for (; node; node = node->m_thinglist_next) @@ -8740,84 +8551,36 @@ void T_Pusher(pusher_t *p) if (!touching && !inFOF) // Object is out of range of effect continue; - if (p->type == p_wind) + if (inFOF || (p->type == p_current && touching)) { - if (touching) // on ground - { - xspeed = (p->x_mag)>>1; // half force - yspeed = (p->y_mag)>>1; - moved = true; - } - else if (inFOF) - { - xspeed = (p->x_mag); // full force - yspeed = (p->y_mag); - moved = true; - } + xspeed = x_mag; // full force + yspeed = y_mag; + zspeed = z_mag; + moved = true; } - else if (p->type == p_upwind) + else if (p->type == p_wind && touching) { - if (touching) // on ground - { - thing->momz += (p->magnitude)>>1; - moved = true; - } - else if (inFOF) - { - thing->momz += p->magnitude; - moved = true; - } - } - else if (p->type == p_downwind) - { - if (touching) // on ground - { - thing->momz -= (p->magnitude)>>1; - moved = true; - } - else if (inFOF) - { - thing->momz -= p->magnitude; - moved = true; - } - } - else // p_current - { - if (!touching && !inFOF) // Not in water at all - xspeed = yspeed = 0; // no force - else // underwater / touching water - { - if (p->type == p_upcurrent) - thing->momz += p->magnitude; - else if (p->type == p_downcurrent) - thing->momz -= p->magnitude; - else - { - xspeed = p->x_mag; // full force - yspeed = p->y_mag; - } - moved = true; - } + xspeed = x_mag>>1; // half force + yspeed = y_mag>>1; + zspeed = z_mag>>1; + moved = true; } - if (p->type != p_downcurrent && p->type != p_upcurrent - && p->type != p_upwind && p->type != p_downwind) + thing->momx += xspeed; + thing->momy += yspeed; + thing->momz += zspeed; + if (thing->player) { - thing->momx += xspeed<<(FRACBITS-PUSH_FACTOR); - thing->momy += yspeed<<(FRACBITS-PUSH_FACTOR); - if (thing->player) - { - thing->player->cmomx += xspeed<<(FRACBITS-PUSH_FACTOR); - thing->player->cmomy += yspeed<<(FRACBITS-PUSH_FACTOR); - thing->player->cmomx = FixedMul(thing->player->cmomx, ORIG_FRICTION); - thing->player->cmomy = FixedMul(thing->player->cmomy, ORIG_FRICTION); - } - - // Tumbleweeds bounce a bit... - if (thing->type == MT_LITTLETUMBLEWEED || thing->type == MT_BIGTUMBLEWEED) - thing->momz += P_AproxDistance(xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR)) >> 2; + thing->player->cmomx += xspeed; + thing->player->cmomy += yspeed; + thing->player->cmomx = FixedMul(thing->player->cmomx, ORIG_FRICTION); + thing->player->cmomy = FixedMul(thing->player->cmomy, ORIG_FRICTION); } + // Tumbleweeds bounce a bit... + if (thing->type == MT_LITTLETUMBLEWEED || thing->type == MT_BIGTUMBLEWEED) + thing->momz += P_AproxDistance(xspeed, yspeed) >> 2; + if (moved) { if (p->slider && thing->player) @@ -8829,7 +8592,7 @@ void T_Pusher(pusher_t *p) thing->player->pflags |= jumped; thing->player->pflags |= PF_SLIDING; - thing->angle = R_PointToAngle2 (0, 0, xspeed<<(FRACBITS-PUSH_FACTOR), yspeed<<(FRACBITS-PUSH_FACTOR)); + thing->angle = R_PointToAngle2(0, 0, xspeed, yspeed); if (!demoplayback || P_ControlStyle(thing->player) == CS_LMAOGALOG) { @@ -8848,87 +8611,33 @@ void T_Pusher(pusher_t *p) } } - -/** Gets a push/pull object. - * - * \param s Sector number to look in. - * \return Pointer to the first ::MT_PUSH or ::MT_PULL object found in the - * sector. - * \sa P_GetTeleportDestThing, P_GetStarpostThing, P_GetAltViewThing - */ -mobj_t *P_GetPushThing(UINT32 s) -{ - mobj_t *thing; - sector_t *sec; - - sec = sectors + s; - thing = sec->thinglist; - while (thing) - { - switch (thing->type) - { - case MT_PUSH: - case MT_PULL: - return thing; - default: - break; - } - thing = thing->snext; - } - return NULL; -} - /** Spawns pushers. * - * \todo Remove magic numbers. * \sa P_SpawnSpecials, Add_Pusher */ static void P_SpawnPushers(void) { size_t i; line_t *l = lines; - mtag_t tag; register INT32 s; - mobj_t *thing; - TAG_ITER_DECLARECOUNTER(0); + fixed_t length, hspeed, dx, dy; for (i = 0; i < numlines; i++, l++) { - tag = Tag_FGet(&l->tags); - switch (l->special) + if (l->special != 541) + continue; + + length = R_PointToDist2(l->v2->x, l->v2->y, l->v1->x, l->v1->y); + hspeed = l->args[1] << FRACBITS; + dx = FixedMul(FixedDiv(l->dx, length), hspeed); + dy = FixedMul(FixedDiv(l->dy, length), hspeed); + + if (l->args[0] == 0) + Add_Pusher(l->args[3], dx, dy, l->args[2] << FRACBITS, (INT32)(l->frontsector - sectors), -1, !(l->args[4] & TMPF_NONEXCLUSIVE), !!(l->args[4] & TMPF_SLIDE)); + else { - case 541: // wind - TAG_ITER_SECTORS(0, tag, s) - Add_Pusher(p_wind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); - break; - case 544: // current - TAG_ITER_SECTORS(0, tag, s) - Add_Pusher(p_current, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); - break; - case 547: // push/pull - TAG_ITER_SECTORS(0, tag, s) - { - thing = P_GetPushThing(s); - if (thing) // No MT_P* means no effect - Add_Pusher(p_push, l->dx, l->dy, thing, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); - } - break; - case 545: // current up - TAG_ITER_SECTORS(0, tag, s) - Add_Pusher(p_upcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); - break; - case 546: // current down - TAG_ITER_SECTORS(0, tag, s) - Add_Pusher(p_downcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); - break; - case 542: // wind up - TAG_ITER_SECTORS(0, tag, s) - Add_Pusher(p_upwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); - break; - case 543: // wind down - TAG_ITER_SECTORS(0, tag, s) - Add_Pusher(p_downwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); - break; + TAG_ITER_SECTORS(l->args[0], s) + Add_Pusher(l->args[3], dx, dy, l->args[2] << FRACBITS, s, -1, !(l->args[4] & TMPF_NONEXCLUSIVE), !!(l->args[4] & TMPF_SLIDE)); } } } diff --git a/src/p_spec.h b/src/p_spec.h index bba7c4a40..33d18d63e 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -21,6 +21,450 @@ extern mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpo extern mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs +// Amount (dx, dy) vector linedef is shifted right to get scroll amount +#define SCROLL_SHIFT 5 + +typedef enum +{ + TMM_DOUBLESIZE = 1, + TMM_SILENT = 1<<1, + TMM_ALLOWYAWCONTROL = 1<<2, + TMM_SWING = 1<<3, + TMM_MACELINKS = 1<<4, + TMM_CENTERLINK = 1<<5, + TMM_CLIP = 1<<6, + TMM_ALWAYSTHINK = 1<<7, +} textmapmaceflags_t; + +typedef enum +{ + TMDA_BOTTOMOFFSET = 1, + TMDA_BOTTOM = 1<<1, + TMDA_MIDDLE = 1<<2, + TMDA_TOP = 1<<3, +} textmapdronealignment_t; + +typedef enum +{ + TMSF_RETRACTED = 1, + TMSF_INTANGIBLE = 1<<1, +} textmapspikeflags_t; + +typedef enum +{ + TMFF_AIMLESS = 1, + TMFF_STATIONARY = 1<<1, + TMFF_HOP = 1<<2, +} textmapflickyflags_t; + +typedef enum +{ + TMFH_NOFLAME = 1, + TMFH_CORONA = 1<<1, +} textmapflameholderflags_t; + +typedef enum +{ + TMDS_NOGRAVITY = 1, + TMDS_ROTATEEXTRA = 1<<1, +} textmapdiagonalspringflags_t; + +typedef enum +{ + TMF_INVISIBLE = 1, + TMF_NODISTANCECHECK = 1<<1, +} textmapfanflags_t; + +typedef enum +{ + TMGD_BACK = 0, + TMGD_RIGHT = 1, + TMGD_LEFT = 2, +} textmapguarddirection_t; + +typedef enum +{ + TMNI_BONUSONLY = 1, + TMNI_REVEAL = 1<<1, +} textmapnightsitem_t; + +typedef enum +{ + TMP_NORMAL = 0, + TMP_SLIDE = 1, + TMP_IMMOVABLE = 2, + TMP_CLASSIC = 3, +} textmappushabletype_t; + +typedef enum +{ + TMED_NONE = 0, + TMED_RIGHT = 1, + TMED_LEFT = 2, +} textmapeggrobodirection_t; + +typedef enum +{ + TMMR_SAME = 0, + TMMR_WEAK = 1, + TMMR_STRONG = 2, +} textmapmonitorrespawn_t; + +typedef enum +{ + TMF_GRAYSCALE = 1, + TMF_SKIPINTRO = 1<<1, +} textmapfangflags_t; + +typedef enum +{ + TMB_NODEATHFLING = 1, + TMB_BARRIER = 1<<1, +} textmapbrakflags_t; + +typedef enum +{ + TMEF_SKIPTALLY = 1, + TMEF_EMERALDCHECK = 1<<1, +} textmapexitflags_t; + +typedef enum +{ + TMSP_NOTELEPORT = 1, + TMSP_FORCESPIN = 1<<1, +} textmapspeedpadflags_t; + +//FOF flags +typedef enum +{ + TMFA_NOPLANES = 1, + TMFA_NOSIDES = 1<<1, + TMFA_INSIDES = 1<<2, + TMFA_ONLYINSIDES = 1<<3, + TMFA_NOSHADE = 1<<4, + TMFA_SPLAT = 1<<5, +} textmapfofappearance_t; + +typedef enum +{ + TMFT_INTANGIBLETOP = 1, + TMFT_INTANGIBLEBOTTOM = 1<<1, + TMFT_DONTBLOCKPLAYER = 1<<2, + TMFT_VISIBLEFROMINSIDE = (TMFT_INTANGIBLETOP|TMFT_INTANGIBLEBOTTOM|TMFT_DONTBLOCKPLAYER), + TMFT_DONTBLOCKOTHERS = 1<<3, + TMFT_INTANGIBLE = (TMFT_DONTBLOCKPLAYER|TMFT_DONTBLOCKOTHERS), +} textmapfoftangibility_t; + +typedef enum +{ + TMFW_NOSIDES = 1, + TMFW_DOUBLESHADOW = 1<<1, + TMFW_COLORMAPONLY = 1<<2, + TMFW_NORIPPLE = 1<<3, + TMFW_GOOWATER = 1<<4, + TMFW_SPLAT = 1<<5, +} textmapfofwater_t; + +typedef enum +{ + TMFB_REVERSE = 1, + TMFB_SPINDASH = 1<<1, + TMFB_DYNAMIC = 1<<2, +} textmapfofbobbing_t; + +typedef enum +{ + TMFC_NOSHADE = 1, + TMFC_NORETURN = 1<<1, + TMFC_AIRBOB = 1<<2, + TMFC_FLOATBOB = 1<<3, + TMFC_SPLAT = 1<<4, +} textmapfofcrumbling_t; + +typedef enum +{ + TMFR_REVERSE = 1, + TMFR_SPINDASH = 1<<1, +} textmapfofrising_t; + +typedef enum +{ + TMFM_BRICK = 1, + TMFM_INVISIBLE = 1<<1, +} textmapfofmario_t; + +typedef enum +{ + TMFB_TOUCH, + TMFB_SPIN, + TMFB_REGULAR, + TMFB_STRONG, +} textmapfofbusttype_t; + +typedef enum +{ + TMFB_PUSHABLES = 1, + TMFB_EXECUTOR = 1<<1, + TMFB_ONLYBOTTOM = 1<<2, + TMFB_SPLAT = 1<<3, +} textmapfofbustflags_t; + +typedef enum +{ + TMFL_NOBOSSES = 1, + TMFL_SPLAT = 1<<1, +} textmapfoflaserflags_t; + +typedef enum +{ + TMT_CONTINUOUS = 0, + TMT_ONCE = 1, + TMT_EACHTIMEMASK = TMT_ONCE, + TMT_EACHTIMEENTER = 2, + TMT_EACHTIMEENTERANDEXIT = 3, +} textmaptriggertype_t; + +typedef enum +{ + TMXT_CONTINUOUS = 0, + TMXT_EACHTIMEMASK = TMXT_CONTINUOUS, + TMXT_EACHTIMEENTER = 1, + TMXT_EACHTIMEENTERANDEXIT = 2, +} textmapxtriggertype_t; + +typedef enum +{ + TMF_HASALL = 0, + TMF_HASANY = 1, + TMF_HASEXACTLY = 2, + TMF_DOESNTHAVEALL = 3, + TMF_DOESNTHAVEANY = 4, +} textmapflagcheck_t; + +typedef enum +{ + TMT_RED = 0, + TMT_BLUE = 1, +} textmapteam_t; + +typedef enum +{ + TMC_EQUAL = 0, + TMC_LTE = 1, + TMC_GTE = 2, +} textmapcomparison_t; + +typedef enum +{ + TMNP_FASTEST = 0, + TMNP_SLOWEST = 1, + TMNP_TRIGGERER = 2, +} textmapnightsplayer_t; + +typedef enum +{ + TMN_ALWAYS = 0, + TMN_FROMNONIGHTS = 1, + TMN_FROMNIGHTS = 2, +} textmapnighterizeoptions_t; + +typedef enum +{ + TMN_BONUSLAPS = 1, + TMN_LEVELCOMPLETION = 1<<2, +} textmapnightserizeflags_t; + +typedef enum +{ + TMD_ALWAYS = 0, + TMD_NOBODYNIGHTS = 1, + TMD_SOMEBODYNIGHTS = 2, +} textmapdenighterizeoptions_t; + +typedef enum +{ + TMS_IFENOUGH = 0, + TMS_IFNOTENOUGH = 1, + TMS_ALWAYS = 2, +} textmapspherescheck_t; + +typedef enum +{ + TMI_BONUSLAPS = 1, + TMI_ENTER = 1<<2, +} textmapideyacaptureflags_t; + +typedef enum +{ + TMP_FLOOR = 0, + TMP_CEILING = 1, + TMP_BOTH = 2, +} textmapplanes_t; + +typedef enum +{ + TMT_ADD = 0, + TMT_REMOVE = 1, + TMT_REPLACEFIRST = 2, + TMT_TRIGGERTAG = 3, +} textmaptagoptions_t; + +typedef enum +{ + TMT_SILENT = 1, + TMT_KEEPANGLE = 1<<1, + TMT_KEEPMOMENTUM = 1<<2, + TMT_RELATIVE = 1<<3, +} textmapteleportflags_t; + +typedef enum +{ + TMM_ALLPLAYERS = 1, + TMM_OFFSET = 1<<1, + TMM_FADE = 1<<2, + TMM_NORELOAD = 1<<3, + TMM_FORCERESET = 1<<4, + TMM_NOLOOP = 1<<5, +} textmapmusicflags_t; + +typedef enum +{ + TMSS_TRIGGERMOBJ = 0, + TMSS_TRIGGERSECTOR = 1, + TMSS_NOWHERE = 2, + TMSS_TAGGEDSECTOR = 3, +} textmapsoundsource_t; + +typedef enum +{ + TMSL_EVERYONE = 0, + TMSL_TRIGGERER = 1, + TMSL_TAGGEDSECTOR = 2, +} textmapsoundlistener_t; + +typedef enum +{ + TML_SECTOR = 0, + TML_FLOOR = 1, + TML_CEILING = 2, +} textmaplightareas_t; + +typedef enum +{ + TMLC_NOSECTOR = 1, + TMLC_NOFLOOR = 1<<1, + TMLC_NOCEILING = 1<<2, +} textmaplightcopyflags_t; + +typedef enum +{ + TMF_RELATIVE = 1, + TMF_OVERRIDE = 1<<1, + TMF_TICBASED = 1<<2, +} textmapfadeflags_t; + +typedef enum +{ + TMB_USETARGET = 1, + TMB_SYNC = 1<<1, +} textmapblinkinglightflags_t; + +typedef enum +{ + TMFR_NORETURN = 1, + TMFR_CHECKFLAG = 1<<1, +} textmapfofrespawnflags_t; + +typedef enum +{ + TMST_RELATIVE = 1, + TMST_DONTDOTRANSLUCENT = 1<<1, +} textmapsettranslucencyflags_t; + +typedef enum +{ + TMFT_RELATIVE = 1, + TMFT_OVERRIDE = 1<<1, + TMFT_TICBASED = 1<<2, + TMFT_IGNORECOLLISION = 1<<3, + TMFT_GHOSTFADE = 1<<4, + TMFT_DONTDOTRANSLUCENT = 1<<5, + TMFT_DONTDOEXISTS = 1<<6, + TMFT_DONTDOLIGHTING = 1<<7, + TMFT_DONTDOCOLORMAP = 1<<8, + TMFT_USEEXACTALPHA = 1<<9, +} textmapfadetranslucencyflags_t; + +typedef enum +{ + TMS_VIEWPOINT = 0, + TMS_CENTERPOINT = 1, + TMS_BOTH = 2, +} textmapskybox_t; + +typedef enum +{ + TMP_CLOSE = 1, + TMP_RUNPOSTEXEC = 1<<1, + TMP_CALLBYNAME = 1<<2, + TMP_KEEPCONTROLS = 1<<3, + TMP_KEEPREALTIME = 1<<4, + //TMP_ALLPLAYERS = 1<<5, + //TMP_FREEZETHINKERS = 1<<6, +} textmappromptflags_t; + +typedef enum +{ + TMF_NOCHANGE = 0, + TMF_ADD = 1, + TMF_REMOVE = 2, +} textmapsetflagflags_t; + +typedef enum +{ + TMSD_FRONT = 0, + TMSD_BACK = 1, + TMSD_FRONTBACK = 2, +} textmapsides_t; + +typedef enum +{ + TMS_SCROLLCARRY = 0, + TMS_SCROLLONLY = 1, + TMS_CARRYONLY = 2, +} textmapscroll_t; + +typedef enum +{ + TMST_REGULAR = 0, + TMST_ACCELERATIVE = 1, + TMST_DISPLACEMENT = 2, + TMST_TYPEMASK = 3, + TMST_NONEXCLUSIVE = 4, +} textmapscrolltype_t; + +typedef enum +{ + TMPF_SLIDE = 1, + TMPF_NONEXCLUSIVE = 1<<1, +} textmappusherflags_t; + +typedef enum +{ + TMPP_NOZFADE = 1, + TMPP_PUSHZ = 1<<1, + TMPP_NONEXCLUSIVE = 1<<2, +} textmappointpushflags_t; + +typedef enum +{ + TMB_TRANSLUCENT = 0, + TMB_ADD = 1, + TMB_SUBTRACT = 2, + TMB_REVERSESUBTRACT = 3, + TMB_MODULATE = 4, +} textmapblendmodes_t; + // GETSECSPECIAL (specialval, section) // // Pulls out the special # from a particular section. @@ -38,12 +482,21 @@ void P_SetupLevelFlatAnims(void); // at map load void P_InitSpecials(void); +void P_ApplyFlatAlignment(sector_t* sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs, boolean floor, boolean ceiling); +fixed_t P_GetSectorGravityFactor(sector_t *sec); void P_SpawnSpecials(boolean fromnetsave); // every tic void P_UpdateSpecials(void); +sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number); +sector_t *P_MobjTouchingSectorSpecialFlag(mobj_t *mo, sectorspecialflags_t flag); sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 number); +sector_t *P_PlayerTouchingSectorSpecialFlag(player_t *player, sectorspecialflags_t flag); void P_PlayerInSpecialSector(player_t *player); +void P_CheckMobjTrigger(mobj_t *mobj, boolean pushable); +sector_t *P_FindPlayerTrigger(player_t *player, line_t *sourceline); +boolean P_IsPlayerValid(size_t playernum); +boolean P_CanPlayerTrigger(size_t playernum); void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *roversector); fixed_t P_FindLowestFloorSurrounding(sector_t *sec); @@ -60,6 +513,10 @@ INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max); void P_SetupSignExit(player_t *player); boolean P_IsFlagAtBase(mobjtype_t flag); +boolean P_IsMobjTouchingSectorPlane(mobj_t *mo, sector_t *sec); +boolean P_IsMobjTouching3DFloor(mobj_t *mo, ffloor_t *ffloor, sector_t *sec); +boolean P_IsMobjTouchingPolyobj(mobj_t *mo, polyobj_t *po, sector_t *polysec); + void P_SwitchWeather(INT32 weathernum); boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller); @@ -72,6 +529,12 @@ void P_RunNightsCapsuleTouchExecutors(mobj_t *actor, boolean entering, boolean e UINT16 P_GetFFloorID(ffloor_t *fflr); ffloor_t *P_GetFFloorByID(sector_t *sec, UINT16 id); +// Use this when you don't know the type of your thinker data struct but need to access its thinker. +typedef struct +{ + thinker_t thinker; +} thinkerdata_t; + // // P_LIGHTS // @@ -83,8 +546,8 @@ typedef struct sector_t *sector; ///< The sector where action is taking place. INT32 count; INT32 resetcount; - INT32 maxlight; ///< The brightest light level to use. - INT32 minlight; ///< The darkest light level to use. + INT16 maxlight; ///< The brightest light level to use. + INT16 minlight; ///< The darkest light level to use. } fireflicker_t; typedef struct @@ -112,8 +575,8 @@ typedef struct thinker_t thinker; ///< The thinker in use for the effect. sector_t *sector; ///< The sector where the action is taking place. INT32 count; - INT32 minlight; ///< The minimum light level to use. - INT32 maxlight; ///< The maximum light level to use. + INT16 minlight; ///< The minimum light level to use. + INT16 maxlight; ///< The maximum light level to use. INT32 darktime; ///< How INT32 to use minlight. INT32 brighttime; ///< How INT32 to use maxlight. } strobe_t; @@ -122,10 +585,10 @@ typedef struct { thinker_t thinker; sector_t *sector; - INT32 minlight; - INT32 maxlight; - INT32 direction; - INT32 speed; + INT16 minlight; + INT16 maxlight; + INT16 direction; + INT16 speed; } glow_t; /** Thinker struct for fading lights. @@ -151,18 +614,18 @@ typedef struct void P_RemoveLighting(sector_t *sector); void T_FireFlicker(fireflicker_t *flick); -fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *minsector, sector_t *maxsector, INT32 length); +fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *sector, INT16 lighta, INT16 lightb, INT32 length); void T_LightningFlash(lightflash_t *flash); void T_StrobeFlash(strobe_t *flash); void P_SpawnLightningFlash(sector_t *sector); -strobe_t * P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector, INT32 darktime, INT32 brighttime, boolean inSync); +strobe_t * P_SpawnAdjustableStrobeFlash(sector_t *sector, INT16 lighta, INT16 lightb, INT32 darktime, INT32 brighttime, boolean inSync); void T_Glow(glow_t *g); -glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector, INT32 length); +glow_t *P_SpawnAdjustableGlowingLight(sector_t *sector, INT16 lighta, INT16 lightb, INT32 length); void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean ticbased); -void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, boolean force); +void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, boolean force, boolean relative); void T_LightFade(lightlevel_t *ll); typedef enum @@ -178,22 +641,19 @@ typedef enum typedef enum { raiseToHighest, - lowerToLowest, - raiseToLowest, lowerToLowestFast, instantRaise, // instant-move for ceilings - lowerAndCrush, crushAndRaise, - fastCrushAndRaise, + raiseAndCrush, crushCeilOnce, crushBothOnce, moveCeilingByFrontSector, instantMoveCeilingByFrontSector, - moveCeilingByFrontTexture, + moveCeilingByDistance, bounceCeiling, bounceCeilingCrush, @@ -209,7 +669,6 @@ typedef struct fixed_t bottomheight; ///< The lowest height to move to. fixed_t topheight; ///< The highest height to move to. fixed_t speed; ///< Ceiling speed. - fixed_t oldspeed; fixed_t delay; fixed_t delaytimer; UINT8 crush; ///< Whether to crush things or not. @@ -218,17 +677,16 @@ typedef struct INT32 direction; ///< 1 = up, 0 = waiting, -1 = down. // ID - INT32 tag; - INT32 olddirection; + INT16 tag; ///< Tag of linedef executor to run when movement is done. fixed_t origspeed; ///< The original, "real" speed. INT32 sourceline; ///< Index of the source linedef } ceiling_t; #define CEILSPEED (FRACUNIT) -INT32 EV_DoCeiling(line_t *line, ceiling_e type); +INT32 EV_DoCeiling(mtag_t tag, line_t *line, ceiling_e type); -INT32 EV_DoCrush(line_t *line, ceiling_e type); +INT32 EV_DoCrush(mtag_t tag, line_t *line, ceiling_e type); void T_CrushCeiling(ceiling_t *ceiling); void T_MoveCeiling(ceiling_t *ceiling); @@ -238,9 +696,6 @@ void T_MoveCeiling(ceiling_t *ceiling); // typedef enum { - // lower floor to lowest surrounding floor - lowerFloorToLowest, - // raise floor to next highest surrounding floor raiseFloorToNearestFast, @@ -250,7 +705,7 @@ typedef enum moveFloorByFrontSector, instantMoveFloorByFrontSector, - moveFloorByFrontTexture, + moveFloorByDistance, bounceFloor, bounceFloorCrush, @@ -262,7 +717,6 @@ typedef enum { elevateUp, elevateDown, - elevateCurrent, elevateContinuous, elevateBounce, elevateHighest, @@ -282,6 +736,8 @@ typedef struct fixed_t origspeed; fixed_t delay; fixed_t delaytimer; + INT16 tag; + INT32 sourceline; } floormove_t; typedef struct @@ -403,7 +859,6 @@ typedef struct thinker_t thinker; line_t *sourceline; // Source line of the thinker boolean playersInArea[MAXPLAYERS]; - boolean playersOnArea[MAXPLAYERS]; boolean triggerOnExit; } eachtime_t; @@ -439,8 +894,8 @@ typedef enum result_e T_MovePlane(sector_t *sector, fixed_t speed, fixed_t dest, boolean crush, boolean ceiling, INT32 direction); -void EV_DoFloor(line_t *line, floor_e floortype); -void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed); +void EV_DoFloor(mtag_t tag, line_t *line, floor_e floortype); +void EV_DoElevator(mtag_t tag, line_t *line, elevator_e elevtype); void EV_CrumbleChain(sector_t *sec, ffloor_t *rover); void EV_BounceSector(sector_t *sector, fixed_t momz, line_t *sourceline); @@ -525,30 +980,20 @@ void T_Friction(friction_t *f); typedef enum { - p_push, ///< Point pusher or puller. p_wind, ///< Wind. p_current, ///< Current. - p_upcurrent, ///< Upwards current. - p_downcurrent, ///< Downwards current. - p_upwind, ///< Upwards wind. - p_downwind ///< Downwards wind. } pushertype_e; // Model for pushers for push/pull effects typedef struct { - thinker_t thinker; ///< Thinker structure for push/pull effect. - /** Types of push/pull effects. - */ - pushertype_e type; ///< Type of push/pull effect. - mobj_t *source; ///< Point source if point pusher/puller. - INT32 x_mag; ///< X strength. - INT32 y_mag; ///< Y strength. - INT32 magnitude; ///< Vector strength for point pusher/puller. - INT32 radius; ///< Effective radius for point pusher/puller. - INT32 x, y, z; ///< Point source if point pusher/puller. + thinker_t thinker; ///< Thinker structure for pusher effect. + pushertype_e type; ///< Type of pusher effect. + fixed_t x_mag; ///< X strength. + fixed_t y_mag; ///< Y strength. + fixed_t z_mag; ///< Z strength. INT32 affectee; ///< Number of affected sector. - UINT8 roverpusher; ///< flag for whether pusher originated from a FOF or not + UINT8 roverpusher; ///< flag for whether pusher originated from a FOF or not INT32 referrer; ///< If roverpusher == true, then this will contain the sector # of the control sector where the effect was applied. INT32 exclusive; /// < Once this affect has been applied to a mobj, no other pushers may affect it. INT32 slider; /// < Should the player go into an uncontrollable slide? @@ -610,9 +1055,8 @@ typedef struct void T_FadeColormap(fadecolormap_t *d); -// Prototype functions for pushers +// Prototype function for pushers void T_Pusher(pusher_t *p); -mobj_t *P_GetPushThing(UINT32 s); // Plane displacement typedef struct @@ -637,6 +1081,4 @@ void T_PlaneDisplace(planedisplace_t *pd); void P_CalcHeight(player_t *player); -sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo); - #endif diff --git a/src/p_telept.c b/src/p_telept.c index f6feddf4b..cbbd0ff6b 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_tick.c b/src/p_tick.c index c0a1c5700..28ace9288 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -323,7 +323,7 @@ static inline void P_RunThinkers(void) size_t i; for (i = 0; i < NUM_THINKERLISTS; i++) { - ps_thlist_times[i] = I_GetPreciseTime(); + PS_START_TIMING(ps_thlist_times[i]); for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next) { #ifdef PARANOIA @@ -331,7 +331,7 @@ static inline void P_RunThinkers(void) #endif currentthinker->function.acp1(currentthinker); } - ps_thlist_times[i] = I_GetPreciseTime() - ps_thlist_times[i]; + PS_STOP_TIMING(ps_thlist_times[i]); } } @@ -487,7 +487,7 @@ static inline void P_DoSpecialStageStuff(void) continue; // If in water, deplete timer 6x as fast. - if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & SH_PROTECTWATER)) + if (players[i].mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(players[i].powers[pw_shield] & ((players[i].mo->eflags & MFE_TOUCHLAVA) ? SH_PROTECTFIRE : SH_PROTECTWATER))) players[i].nightstime -= 5; if (--players[i].nightstime > 6) { @@ -653,16 +653,16 @@ void P_Ticker(boolean run) } } - ps_lua_mobjhooks = 0; - ps_checkposition_calls = 0; + ps_lua_mobjhooks.value.i = 0; + ps_checkposition_calls.value.i = 0; - LUAh_PreThinkFrame(); + LUA_HOOK(PreThinkFrame); - ps_playerthink_time = I_GetPreciseTime(); + PS_START_TIMING(ps_playerthink_time); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerThink(&players[i]); - ps_playerthink_time = I_GetPreciseTime() - ps_playerthink_time; + PS_STOP_TIMING(ps_playerthink_time); } // Keep track of how long they've been playing! @@ -677,18 +677,18 @@ void P_Ticker(boolean run) if (run) { - ps_thinkertime = I_GetPreciseTime(); + PS_START_TIMING(ps_thinkertime); P_RunThinkers(); - ps_thinkertime = I_GetPreciseTime() - ps_thinkertime; + PS_STOP_TIMING(ps_thinkertime); // Run any "after all the other thinkers" stuff for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); - ps_lua_thinkframe_time = I_GetPreciseTime(); - LUAh_ThinkFrame(); - ps_lua_thinkframe_time = I_GetPreciseTime() - ps_lua_thinkframe_time; + PS_START_TIMING(ps_lua_thinkframe_time); + LUA_HookThinkFrame(); + PS_STOP_TIMING(ps_lua_thinkframe_time); } // Run shield positioning @@ -760,7 +760,7 @@ void P_Ticker(boolean run) if (modeattacking) G_GhostTicker(); - LUAh_PostThinkFrame(); + LUA_HOOK(PostThinkFrame); } P_MapEnd(); @@ -783,7 +783,7 @@ void P_PreTicker(INT32 frames) { P_MapStart(); - LUAh_PreThinkFrame(); + LUA_HOOK(PreThinkFrame); for (i = 0; i < MAXPLAYERS; i++) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) @@ -810,7 +810,7 @@ void P_PreTicker(INT32 frames) if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo)) P_PlayerAfterThink(&players[i]); - LUAh_ThinkFrame(); + LUA_HookThinkFrame(); // Run shield positioning P_RunShields(); @@ -819,7 +819,7 @@ void P_PreTicker(INT32 frames) P_UpdateSpecials(); P_RespawnSpecials(); - LUAh_PostThinkFrame(); + LUA_HOOK(PostThinkFrame); P_MapEnd(); } diff --git a/src/p_tick.h b/src/p_tick.h index 1fb88f3f2..d355bc6d7 100644 --- a/src/p_tick.h +++ b/src/p_tick.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/p_user.c b/src/p_user.c index f0172ce6b..8d4e39a72 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -190,7 +190,7 @@ fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move) boolean P_AutoPause(void) { // Don't pause even on menu-up or focus-lost in netgames or record attack - if (netgame || modeattacking || gamestate == GS_TITLESCREEN) + if (netgame || modeattacking || gamestate == GS_TITLESCREEN || (marathonmode && gamestate == GS_INTERMISSION)) return false; return (menuactive || ( window_notinfocus && cv_pauseifunfocused.value )); @@ -706,8 +706,7 @@ static void P_DeNightserizePlayer(player_t *player) // If you screwed up, kiss your score and ring bonus goodbye. // But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground. - player->marescore = player->spheres =\ - player->rings = 0; + player->marescore = player->spheres = player->rings = 0; } // Check to see if the player should be killed. @@ -717,13 +716,12 @@ static void P_DeNightserizePlayer(player_t *player) continue; mo2 = (mobj_t *)th; - if (!(mo2->type == MT_NIGHTSDRONE)) + if (mo2->type != MT_NIGHTSDRONE) continue; if (mo2->flags2 & MF2_AMBUSH) { - player->marescore = player->spheres =\ - player->rings = 0; + player->marescore = player->spheres = player->rings = 0; P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); // Reset music to beginning if MIXNIGHTSCOUNTDOWN @@ -1045,7 +1043,8 @@ void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor) fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale); } - player->drawangle = ang + ANGLE_180; + if (player->pflags & PF_DIRECTIONCHAR) + player->drawangle = ang + ANGLE_180; P_InstaThrust(player->mo, ang, fallbackspeed); } @@ -1111,7 +1110,7 @@ boolean P_PlayerCanDamage(player_t *player, mobj_t *thing) return false; { - UINT8 shouldCollide = LUAh_PlayerCanDamage(player, thing); + UINT8 shouldCollide = LUA_HookPlayerCanDamage(player, thing); if (P_MobjWasRemoved(thing)) return false; // removed??? if (shouldCollide == 1) @@ -1189,8 +1188,8 @@ 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; @@ -1367,8 +1366,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) @@ -1594,7 +1593,7 @@ boolean P_EvaluateMusicStatus(UINT16 status, const char *musname) break; case JT_OTHER: // Other state - result = LUAh_ShouldJingleContinue(&players[i], musname); + result = LUA_HookShouldJingleContinue(&players[i], musname); break; case JT_NONE: // Null state @@ -1728,89 +1727,6 @@ boolean P_IsObjectOnGround(mobj_t *mo) return false; } -// -// P_IsObjectOnGroundIn -// -// Returns true if the player is -// on the ground in a specific sector. Takes reverse -// gravity and FOFs into account. -// -boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec) -{ - ffloor_t *rover; - - // Is the object in reverse gravity? - if (mo->eflags & MFE_VERTICALFLIP) - { - // Detect if the player is on the ceiling. - if (mo->z+mo->height >= P_GetSpecialTopZ(mo, sec, sec)) - return true; - // Otherwise, detect if the player is on the bottom of a FOF. - else - { - for (rover = sec->ffloors; rover; rover = rover->next) - { - // If the FOF doesn't exist, continue. - if (!(rover->flags & FF_EXISTS)) - continue; - - // If the FOF is configured to let the object through, continue. - if (!((rover->flags & FF_BLOCKPLAYER && mo->player) - || (rover->flags & FF_BLOCKOTHERS && !mo->player))) - continue; - - // If the the platform is intangible from below, continue. - if (rover->flags & FF_PLATFORM) - continue; - - // If the FOF is a water block, continue. (Unnecessary check?) - if (rover->flags & FF_SWIMMABLE) - continue; - - // Actually check if the player is on the suitable FOF. - if (mo->z+mo->height == P_GetSpecialBottomZ(mo, sectors + rover->secnum, sec)) - return true; - } - } - } - // Nope! - else - { - // Detect if the player is on the floor. - if (mo->z <= P_GetSpecialBottomZ(mo, sec, sec)) - return true; - // Otherwise, detect if the player is on the top of a FOF. - else - { - for (rover = sec->ffloors; rover; rover = rover->next) - { - // If the FOF doesn't exist, continue. - if (!(rover->flags & FF_EXISTS)) - continue; - - // If the FOF is configured to let the object through, continue. - if (!((rover->flags & FF_BLOCKPLAYER && mo->player) - || (rover->flags & FF_BLOCKOTHERS && !mo->player))) - continue; - - // If the the platform is intangible from above, continue. - if (rover->flags & FF_REVERSEPLATFORM) - continue; - - // If the FOF is a water block, continue. (Unnecessary check?) - if (rover->flags & FF_SWIMMABLE) - continue; - - // Actually check if the player is on the suitable FOF. - if (mo->z == P_GetSpecialTopZ(mo, sectors + rover->secnum, sec)) - return true; - } - } - } - - return false; -} - // // P_SetObjectMomZ // @@ -1860,7 +1776,7 @@ void P_SpawnShieldOrb(player_t *player) I_Error("P_SpawnShieldOrb: player->mo is NULL!\n"); #endif - if (LUAh_ShieldSpawn(player)) + if (LUA_HookPlayer(player, HOOK(ShieldSpawn))) return; if (player->powers[pw_shield] & SH_FORCE) @@ -2007,6 +1923,24 @@ void P_SwitchShield(player_t *player, UINT16 shieldtype) } } +// +// P_SetPower +// +// Sets a power and spawns a shield orb if required. +// +void P_SetPower(player_t *player, powertype_t power, UINT16 value) +{ + boolean spawnshield = false; + + if (power == pw_shield && player->powers[pw_shield] != value) + spawnshield = true; + + player->powers[power] = value; + + if (spawnshield) //workaround for a bug + P_SpawnShieldOrb(player); +} + // // P_SpawnGhostMobj // @@ -2016,6 +1950,8 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) { mobj_t *ghost = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_GHOST); + P_SetTarget(&ghost->target, mobj); + P_SetScale(ghost, mobj->scale); ghost->destscale = mobj->scale; @@ -2030,12 +1966,22 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle); ghost->rollangle = mobj->rollangle; + ghost->sprite = mobj->sprite; ghost->sprite2 = mobj->sprite2; ghost->frame = mobj->frame; ghost->tics = -1; ghost->frame &= ~FF_TRANSMASK; ghost->frame |= tr_trans50<renderflags = mobj->renderflags; + ghost->blendmode = mobj->blendmode; + + ghost->spritexscale = mobj->spritexscale; + ghost->spriteyscale = mobj->spriteyscale; + ghost->spritexoffset = mobj->spritexoffset; + ghost->spriteyoffset = mobj->spriteyoffset; + ghost->fuse = ghost->info->damage; ghost->skin = mobj->skin; @@ -2249,13 +2195,12 @@ void P_DoPlayerExit(player_t *player) P_RestoreMusic(player); } -#define SPACESPECIAL 12 boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space { sector_t *sector = mo->subsector->sector; fixed_t topheight, bottomheight; - if (GETSECSPECIAL(sector->special, 1) == SPACESPECIAL) + if (sector->specialflags & SSF_OUTERSPACE) return true; if (sector->ffloors) @@ -2267,7 +2212,7 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space if (!(rover->flags & FF_EXISTS)) continue; - if (GETSECSPECIAL(rover->master->frontsector->special, 1) != SPACESPECIAL) + if (!(rover->master->frontsector->specialflags & SSF_OUTERSPACE)) continue; topheight = P_GetFFloorTopZAt (rover, mo->x, mo->y); bottomheight = P_GetFFloorBottomZAt(rover, mo->x, mo->y); @@ -2550,58 +2495,60 @@ static boolean P_PlayerCanBust(player_t *player, ffloor_t *rover) /*if (rover->master->frontsector->crumblestate != CRUMBLE_NONE) return false;*/ - // If it's an FF_SHATTER, you can break it just by touching it. - if (rover->flags & FF_SHATTER) - return true; - - // If it's an FF_SPINBUST, you can break it if you are in your spinning frames - // (either from jumping or spindashing). - if (rover->flags & FF_SPINBUST) + switch (rover->busttype) { + case BT_TOUCH: // Shatters on contact + return true; + case BT_SPINBUST: // Can be busted by spinning (either from jumping or spindashing) if ((player->pflags & PF_SPINNING) && !(player->pflags & PF_STARTDASH)) return true; if ((player->pflags & PF_JUMPED) && !(player->pflags & PF_NOJUMPDAMAGE)) return true; + + /* FALLTHRU */ + case BT_REGULAR: + // Spinning (and not jumping) + if ((player->pflags & PF_SPINNING) && !(player->pflags & PF_JUMPED)) + return true; + + // Strong abilities can break even FF_STRONGBUST. + if (player->charflags & SF_CANBUSTWALLS) + return true; + + // Super + if (player->powers[pw_super]) + return true; + + // Dashmode + if ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) && player->dashmode >= DASHMODE_THRESHOLD) + return true; + + // NiGHTS drill + if (player->pflags & PF_DRILLING) + return true; + + // Recording for Metal Sonic + if (metalrecording) + return true; + + /* FALLTHRU */ + case BT_STRONG: // Requires a "strong ability" + if (player->charability == CA_GLIDEANDCLIMB) + return true; + + if (player->pflags & PF_BOUNCING) + return true; + + if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) + return true; + + if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) + return true; + + break; } - // Strong abilities can break even FF_STRONGBUST. - if (player->charflags & SF_CANBUSTWALLS) - return true; - - if (player->pflags & PF_BOUNCING) - return true; - - if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY) - return true; - - if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2) - return true; - - // Everyone else is out of luck. - if (rover->flags & FF_STRONGBUST) - return false; - - // Spinning (and not jumping) - if ((player->pflags & PF_SPINNING) && !(player->pflags & PF_JUMPED)) - return true; - - // Super - if (player->powers[pw_super]) - return true; - - // Dashmode - if ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) && player->dashmode >= DASHMODE_THRESHOLD) - return true; - - // NiGHTS drill - if (player->pflags & PF_DRILLING) - return true; - - // Recording for Metal Sonic - if (metalrecording) - return true; - return false; } @@ -2652,7 +2599,7 @@ static void P_CheckBustableBlocks(player_t *player) } // Height checks - if (rover->flags & FF_SHATTERBOTTOM) + if (rover->bustflags & FB_ONLYBOTTOM) { if (player->mo->z + player->mo->momz + player->mo->height < bottomheight) continue; @@ -2660,35 +2607,41 @@ static void P_CheckBustableBlocks(player_t *player) if (player->mo->z + player->mo->height > bottomheight) continue; } - else if (rover->flags & FF_SPINBUST) - { - if (player->mo->z + player->mo->momz > topheight) - continue; - - if (player->mo->z + player->mo->height < bottomheight) - continue; - } - else if (rover->flags & FF_SHATTER) - { - if (player->mo->z + player->mo->momz > topheight) - continue; - - if (player->mo->z + player->mo->momz + player->mo->height < bottomheight) - continue; - } else { - if (player->mo->z >= topheight) - continue; + switch (rover->busttype) + { + case BT_TOUCH: + if (player->mo->z + player->mo->momz > topheight) + continue; - if (player->mo->z + player->mo->height < bottomheight) - continue; + if (player->mo->z + player->mo->momz + player->mo->height < bottomheight) + continue; + + break; + case BT_SPINBUST: + if (player->mo->z + player->mo->momz > topheight) + continue; + + if (player->mo->z + player->mo->height < bottomheight) + continue; + + break; + default: + if (player->mo->z >= topheight) + continue; + + if (player->mo->z + player->mo->height < bottomheight) + continue; + + break; + } } // Impede the player's fall a bit - if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight) + if (((rover->busttype == BT_TOUCH) || (rover->busttype == BT_SPINBUST)) && player->mo->z >= topheight) player->mo->momz >>= 1; - else if (rover->flags & FF_SHATTER) + else if (rover->busttype == BT_TOUCH) { player->mo->momx >>= 1; player->mo->momy >>= 1; @@ -2700,8 +2653,8 @@ static void P_CheckBustableBlocks(player_t *player) EV_CrumbleChain(NULL, rover); // node->m_sector // Run a linedef executor?? - if (rover->master->flags & ML_EFFECT5) - P_LinedefExecute((INT16)(P_AproxDistance(rover->master->dx, rover->master->dy)>>FRACBITS), player->mo, node->m_sector); + if (rover->bustflags & FB_EXECUTOR) + P_LinedefExecute(rover->busttag, player->mo, node->m_sector); goto bustupdone; } @@ -2746,14 +2699,20 @@ static void P_CheckBouncySectors(player_t *player) for (rover = node->m_sector->ffloors; rover; rover = rover->next) { - fixed_t bouncestrength; fixed_t topheight, bottomheight; if (!(rover->flags & FF_EXISTS)) continue; // FOFs should not be bouncy if they don't even "exist" - if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 15) - continue; // this sector type is required for FOFs to be bouncy + // Handle deprecated bouncy FOF sector type + if (!udmf && GETSECSPECIAL(rover->master->frontsector->special, 1) == 15) + { + rover->flags |= FF_BOUNCY; + rover->bouncestrength = P_AproxDistance(rover->master->dx, rover->master->dy)/100; + } + + if (!(rover->flags & FF_BOUNCY)) + continue; topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL); @@ -2764,24 +2723,14 @@ static void P_CheckBouncySectors(player_t *player) if (player->mo->z + player->mo->height < bottomheight) continue; - bouncestrength = P_AproxDistance(rover->master->dx, rover->master->dy)/100; - if (oldz < P_GetFOFTopZ(player->mo, node->m_sector, rover, oldx, oldy, NULL) && oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)) { - player->mo->momx = -FixedMul(player->mo->momx,bouncestrength); - player->mo->momy = -FixedMul(player->mo->momy,bouncestrength); - - if (player->pflags & PF_SPINNING) - { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); - player->pflags |= PF_THOKKED; - } + player->mo->momx = -FixedMul(player->mo->momx,rover->bouncestrength); + player->mo->momy = -FixedMul(player->mo->momy,rover->bouncestrength); } else { - fixed_t newmom; pslope_t *slope = (abs(oldz - topheight) < abs(oldz + player->mo->height - bottomheight)) ? *rover->t_slope : *rover->b_slope; momentum.x = player->mo->momx; @@ -2791,53 +2740,28 @@ static void P_CheckBouncySectors(player_t *player) if (slope) P_ReverseQuantizeMomentumToSlope(&momentum, slope); - newmom = momentum.z = -FixedMul(momentum.z,bouncestrength)/2; + momentum.z = -FixedMul(momentum.z,rover->bouncestrength)/2; - if (abs(newmom) < (bouncestrength*2)) + if (abs(momentum.z) < (rover->bouncestrength*2)) goto bouncydone; - if (!(rover->master->flags & ML_BOUNCY)) - { - if (newmom > 0) - { - if (newmom < 8*FRACUNIT) - newmom = 8*FRACUNIT; - } - else if (newmom < 0) - { - if (newmom > -8*FRACUNIT) - newmom = -8*FRACUNIT; - } - } - - if (newmom > P_GetPlayerHeight(player)/2) - newmom = P_GetPlayerHeight(player)/2; - else if (newmom < -P_GetPlayerHeight(player)/2) - newmom = -P_GetPlayerHeight(player)/2; - - momentum.z = newmom*2; + if (momentum.z > FixedMul(24*FRACUNIT, player->mo->scale)) //half of the default player height + momentum.z = FixedMul(24*FRACUNIT, player->mo->scale); + else if (momentum.z < -FixedMul(24*FRACUNIT, player->mo->scale)) + momentum.z = -FixedMul(24*FRACUNIT, player->mo->scale); if (slope) P_QuantizeMomentumToSlope(&momentum, slope); player->mo->momx = momentum.x; player->mo->momy = momentum.y; - player->mo->momz = momentum.z/2; + player->mo->momz = momentum.z; if (player->pflags & PF_SPINNING) { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); player->pflags |= PF_THOKKED; } } - - if ((player->pflags & PF_SPINNING) && player->speed < FixedMul(1<mo->scale) && player->mo->momz) - { - player->pflags &= ~PF_SPINNING; - player->pflags |= P_GetJumpFlags(player); - } - goto bouncydone; } } @@ -2852,7 +2776,7 @@ bouncydone: static void P_CheckQuicksand(player_t *player) { ffloor_t *rover; - fixed_t sinkspeed, friction; + fixed_t sinkspeed; fixed_t topheight, bottomheight; if (!(player->mo->subsector->sector->ffloors && player->mo->momz <= 0)) @@ -2870,9 +2794,7 @@ static void P_CheckQuicksand(player_t *player) if (topheight >= player->mo->z && bottomheight < player->mo->z + player->mo->height) { - sinkspeed = abs(rover->master->v1->x - rover->master->v2->x)>>1; - - sinkspeed = FixedDiv(sinkspeed,TICRATE*FRACUNIT); + sinkspeed = FixedDiv(rover->sinkspeed,TICRATE*FRACUNIT); if (player->mo->eflags & MFE_VERTICALFLIP) { @@ -2899,10 +2821,8 @@ static void P_CheckQuicksand(player_t *player) P_PlayerHitFloor(player, false); } - friction = abs(rover->master->v1->y - rover->master->v2->y)>>6; - - player->mo->momx = FixedMul(player->mo->momx, friction); - player->mo->momy = FixedMul(player->mo->momy, friction); + player->mo->momx = FixedMul(player->mo->momx, rover->friction); + player->mo->momy = FixedMul(player->mo->momy, rover->friction); } } } @@ -4499,7 +4419,7 @@ void P_DoJump(player_t *player, boolean soundandstate) if (twodlevel || (player->mo->flags2 & MF2_TWOD)) factor += player->jumpfactor / 10; - if (player->charflags & SF_MULTIABILITY && player->charability == CA_DOUBLEJUMP) + if (player->charflags & SF_MULTIABILITY && player->charability == CA_DOUBLEJUMP && (player->actionspd >> FRACBITS) != -1) factor -= max(0, player->secondjump * player->jumpfactor / ((player->actionspd >> FRACBITS) + 1)); // Reduce the jump height each time //if (maptol & TOL_NIGHTS) @@ -4581,7 +4501,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) if (cmd->buttons & BT_SPIN) { - if (LUAh_SpinSpecial(player)) + if (LUA_HookPlayer(player, HOOK(SpinSpecial))) return; } @@ -4786,7 +4706,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH) && player->speed < 5*player->mo->scale && canstand) { - if (GETSECSPECIAL(player->mo->subsector->sector->special, 4) == 7 || (player->mo->ceilingz - player->mo->floorz < P_GetPlayerHeight(player))) + if ((player->mo->subsector->sector->specialflags & SSF_FORCESPIN) || (player->mo->ceilingz - player->mo->floorz < P_GetPlayerHeight(player))) P_InstaThrust(player->mo, player->mo->angle, 10*player->mo->scale); else { @@ -4880,22 +4800,28 @@ void P_DoBubbleBounce(player_t *player) // void P_DoAbilityBounce(player_t *player, boolean changemomz) { - fixed_t prevmomz; if (player->mo->state-states == S_PLAY_BOUNCE_LANDING) return; + if (changemomz) { - fixed_t minmomz; - prevmomz = player->mo->momz; + fixed_t prevmomz = player->mo->momz, minmomz; + if (P_MobjFlip(player->mo)*prevmomz < 0) prevmomz = 0; else if (player->mo->eflags & MFE_UNDERWATER) prevmomz /= 2; + P_DoJump(player, false); player->pflags &= ~(PF_STARTJUMP|PF_JUMPED); minmomz = FixedMul(player->mo->momz, 3*FRACUNIT/2); - player->mo->momz = max(minmomz, (minmomz + prevmomz)/2); + + if (player->mo->eflags & MFE_VERTICALFLIP) // Use "min" or "max" depending on if the player is flipped + player->mo->momz = min(minmomz, (minmomz + prevmomz)/2); + else + player->mo->momz = max(minmomz, (minmomz + prevmomz)/2); } + S_StartSound(player->mo, sfx_boingf); P_SetPlayerMobjState(player->mo, S_PLAY_BOUNCE_LANDING); player->pflags |= PF_BOUNCING|PF_THOKKED; @@ -5024,7 +4950,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock if ((player->powers[pw_shield] & SH_NOSTACK) && !player->powers[pw_super] && !(player->pflags & PF_SPINDOWN) && ((!(player->pflags & PF_THOKKED) || (((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP || (player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) && player->secondjump == UINT8_MAX) ))) // thokked is optional if you're bubblewrapped / 3dblasted { - if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT) + if ((player->powers[pw_shield] & SH_NOSTACK) == SH_ATTRACT && !(player->charflags & SF_NOSHIELDABILITY)) { if ((lockonshield = P_LookForEnemies(player, false, false))) { @@ -5047,7 +4973,7 @@ static boolean P_PlayerShieldThink(player_t *player, ticcmd_t *cmd, mobj_t *lock } } } - if (cmd->buttons & BT_SPIN && !LUAh_ShieldSpecial(player)) // Spin button effects + if ((!(player->charflags & SF_NOSHIELDABILITY)) && (cmd->buttons & BT_SPIN && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) // Spin button effects { // Force stop if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE) @@ -5171,7 +5097,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) // and you don't have a shield, do it! P_DoSuperTransformation(player, false); } - else if (!LUAh_JumpSpinSpecial(player)) + else if (!LUA_HookPlayer(player, HOOK(JumpSpinSpecial))) switch (player->charability) { case CA_THOK: @@ -5244,7 +5170,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (cmd->buttons & BT_JUMP && !player->exiting && !P_PlayerInPain(player)) { - if (LUAh_JumpSpecial(player)) + if (LUA_HookPlayer(player, HOOK(JumpSpecial))) ; // all situations below this require jump button not to be pressed already else if (player->pflags & PF_JUMPDOWN) @@ -5279,7 +5205,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) }*/ else if (player->pflags & PF_JUMPED) { - if (!LUAh_AbilitySpecial(player)) + if (!LUA_HookPlayer(player, HOOK(AbilitySpecial))) switch (player->charability) { case CA_THOK: @@ -5293,7 +5219,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) fixed_t actionspd = player->actionspd; if (player->charflags & SF_DASHMODE) - actionspd = max(player->normalspeed, FixedDiv(player->speed, player->mo->scale)); + actionspd = max(player->actionspd, FixedDiv(player->speed, player->mo->scale)); if (player->mo->eflags & MFE_UNDERWATER) actionspd >>= 1; @@ -5349,9 +5275,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); }*/ } @@ -5370,7 +5296,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); @@ -5472,7 +5398,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) } else if (player->pflags & PF_THOKKED) { - if (!LUAh_AbilitySpecial(player)) + if (!LUA_HookPlayer(player, HOOK(AbilitySpecial))) switch (player->charability) { case CA_FLY: @@ -5495,7 +5421,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) break; } } - else if ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super]) + else if ((!(player->charflags & SF_NOSHIELDABILITY)) && ((player->powers[pw_shield] & SH_NOSTACK) == SH_WHIRLWIND && !player->powers[pw_super] && !LUA_HookPlayer(player, HOOK(ShieldSpecial)))) P_DoJumpShield(player); } @@ -5616,16 +5542,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; @@ -5641,17 +5561,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); } @@ -5682,6 +5600,22 @@ INT32 P_GetPlayerControlDirection(player_t *player) return 1; // Controls pointing in player's general direction } +static boolean P_ShouldResetConveyorMomentum(player_t *player) +{ + switch (player->onconveyor) + { + case 1: + return false; + case 2: // Wind/Current + return !(player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)); + case 3: + default: + return true; + case 4: // Actual conveyor belt + return !P_IsObjectOnGround(player->mo); + } +} + // Control scheme for 2d levels. static void P_2dMovement(player_t *player) { @@ -5716,16 +5650,7 @@ static void P_2dMovement(player_t *player) } } - // cmomx/cmomy stands for the conveyor belt speed. - if (player->onconveyor == 2) // Wind/Current - { - //if (player->mo->z > player->mo->watertop || player->mo->z + player->mo->height < player->mo->waterbottom) - if (!(player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) - player->cmomx = player->cmomy = 0; - } - else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt - player->cmomx = player->cmomy = 0; - else if (player->onconveyor != 2 && player->onconveyor != 4 && player->onconveyor != 1) + if (P_ShouldResetConveyorMomentum(player)) player->cmomx = player->cmomy = 0; player->rmomx = player->mo->momx - player->cmomx; @@ -5908,23 +5833,14 @@ static void P_3dMovement(player_t *player) } movepushsideangle = movepushangle-ANGLE_90; - // cmomx/cmomy stands for the conveyor belt speed. - if (player->onconveyor == 2) // Wind/Current - { - //if (player->mo->z > player->mo->watertop || player->mo->z + player->mo->height < player->mo->waterbottom) - if (!(player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) - player->cmomx = player->cmomy = 0; - } - else if (player->onconveyor == 4 && !P_IsObjectOnGround(player->mo)) // Actual conveyor belt - player->cmomx = player->cmomy = 0; - else if (player->onconveyor != 2 && player->onconveyor != 4 && player->onconveyor != 1) + if (P_ShouldResetConveyorMomentum(player)) player->cmomx = player->cmomy = 0; player->rmomx = player->mo->momx - player->cmomx; player->rmomy = player->mo->momy - player->cmomy; // Calculates player's speed based on distance-of-a-line formula - player->speed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); + player->speed = P_AproxDistance(player->rmomx, player->rmomy); // Monster Iestyn - 04-11-13 // Quadrants are stupid, excessive and broken, let's do this a much simpler way! @@ -5957,22 +5873,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]) @@ -6325,18 +6225,11 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad if (player->exiting) return; + if (!P_CheckMove(player->mo, + player->mo->x + player->mo->momx, + player->mo->y + player->mo->momy, true)) { - boolean notallowed; - mobj_t *hack = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_NULL); - hack->flags = MF_NOGRAVITY; - hack->radius = player->mo->radius; - hack->height = player->mo->height; - hack->z = player->mo->z; - P_SetThingPosition(hack); - notallowed = (!(P_TryMove(hack, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, true))); - P_RemoveMobj(hack); - if (notallowed) - return; + return; } { @@ -6728,7 +6621,7 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad // static void P_DoNiGHTSCapsule(player_t *player) { - INT32 i, spherecount, totalduration, popduration, deductinterval, deductquantity, sphereresult, firstpoptic, startingspheres; + INT32 i, spherecount, totalduration, popduration, deductinterval, deductquantity, sphereresult, firstpoptic; INT32 tictimer = ++player->capsule->extravalue2; if (abs(player->mo->x-player->capsule->x) <= 3*FRACUNIT) @@ -6851,15 +6744,20 @@ static void P_DoNiGHTSCapsule(player_t *player) if (player->capsule->health > sphereresult && player->spheres > 0) { + // If spherecount isn't a multiple of deductquantity, the final deduction might steal too many spheres from the player + // E.g. with 80 capsule health, deductquantity is 3, 3*26 is 78, 78+3=81, and then it'll have stolen more than the 80 that it was meant to! + // So let's adjust deductquantity accordingly for the final deduction + deductquantity = min(deductquantity, player->capsule->health - sphereresult); + player->spheres -= deductquantity; player->capsule->health -= deductquantity; + + if (player->spheres < 0) // This can't happen... without Lua, setrings, et cetera + player->spheres = 0; + + //if (player->capsule->health < sphereresult) // This can't happen + //player->capsule->health = sphereresult; } - - if (player->spheres < 0) - player->spheres = 0; - - if (player->capsule->health < sphereresult) - player->capsule->health = sphereresult; } // Spawn a 'pop' for every 2 tics @@ -6880,9 +6778,8 @@ static void P_DoNiGHTSCapsule(player_t *player) } else { - startingspheres = player->spheres - player->capsule->health; + player->spheres -= player->capsule->health; player->capsule->health = 0; - player->spheres = startingspheres; } } @@ -7649,8 +7546,8 @@ static void P_NiGHTSMovement(player_t *player) } } - if (objectplacing) - OP_NightsObjectplace(player); + //if (objectplacing) + // OP_NightsObjectplace(player); } // May be used in future for CTF @@ -7756,6 +7653,11 @@ void P_ElementalFire(player_t *player, boolean cropcircle) flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); P_InstaThrust(flame, flame->angle, FixedMul(3*FRACUNIT, flame->scale)); P_SetObjectMomZ(flame, 3*FRACUNIT, false); + if (!(gametyperules & GTR_FRIENDLY)) + { + P_SetMobjState(flame, S_TEAM_SPINFIRE1); + flame->color = player->mo->color; + } } #undef limitangle #undef numangles @@ -7783,6 +7685,11 @@ void P_ElementalFire(player_t *player, boolean cropcircle) flame->destscale = player->mo->scale; P_SetScale(flame, player->mo->scale); flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); + if (!(gametyperules & GTR_FRIENDLY)) + { + P_SetMobjState(flame, S_TEAM_SPINFIRE1); + flame->color = player->mo->color; + } flame->momx = 8; // this is a hack which is used to ensure it still behaves as a missile and can damage others P_XYMovement(flame); @@ -8635,14 +8542,16 @@ void P_MovePlayer(player_t *player) { boolean atspinheight = false; fixed_t oldheight = player->mo->height; + fixed_t luaheight = LUA_HookPlayerHeight(player); + if (luaheight != -1) + { + player->mo->height = luaheight; + if (luaheight <= P_GetPlayerSpinHeight(player)) + atspinheight = true; // spinning will not save you from being crushed + } // Less height while spinning. Good for spinning under things...? - if ((player->mo->state == &states[player->mo->info->painstate]) - || ((player->pflags & PF_JUMPED) && !(player->pflags & PF_NOJUMPDAMAGE)) - || (player->pflags & PF_SPINNING) - || player->powers[pw_tailsfly] || player->pflags & PF_GLIDING - || (player->charability == CA_GLIDEANDCLIMB && player->mo->state-states == S_PLAY_GLIDE_LANDING) - || (player->charability == CA_FLY && player->mo->state-states == S_PLAY_FLY_TIRED)) + else if (P_PlayerShouldUseSpinHeight(player)) { player->mo->height = P_GetPlayerSpinHeight(player); atspinheight = true; @@ -8699,7 +8608,7 @@ void P_MovePlayer(player_t *player) #endif // Look for blocks to bust up - // Because of FF_SHATTER, we should look for blocks constantly, + // Because of BT_TOUCH, we should look for blocks constantly, // not just when spinning or playing as Knuckles if (CheckForBustableBlocks) P_CheckBustableBlocks(player); @@ -8999,8 +8908,11 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) if (mo->type == MT_MINUS && !(mo->flags & (MF_SPECIAL|MF_SHOOTABLE))) mo->flags = (mo->flags & ~MF_NOCLIPTHING)|MF_SPECIAL|MF_SHOOTABLE; - if (mo->type == MT_EGGGUARD && mo->tracer) //nuke Egg Guard's shield! + if (mo->type == MT_EGGGUARD && mo->tracer) // Egg Guard's shield needs to be removed if it has one! + { P_KillMobj(mo->tracer, inflictor, source, DMG_NUKE); + P_KillMobj(mo, inflictor, source, DMG_NUKE); + } if (mo->flags & MF_BOSS || mo->type == MT_PLAYER) //don't OHKO bosses nor players! P_DamageMobj(mo, inflictor, source, 1, DMG_NUKE); @@ -9487,11 +9399,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(); @@ -9654,7 +9566,7 @@ consvar_t cv_cam_still = CVAR_INIT ("cam_still", "Off", 0, CV_OnOff, NULL); consvar_t cv_cam_speed = CVAR_INIT ("cam_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL); consvar_t cv_cam_rotate = CVAR_INIT ("cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange); consvar_t cv_cam_rotspeed = CVAR_INIT ("cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL); -consvar_t cv_cam_turnmultiplier = CVAR_INIT ("cam_turnmultiplier", "1.0", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL); +consvar_t cv_cam_turnmultiplier = CVAR_INIT ("cam_turnmultiplier", "0.75", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL); consvar_t cv_cam_orbit = CVAR_INIT ("cam_orbit", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_cam_adjust = CVAR_INIT ("cam_adjust", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_cam2_dist = CVAR_INIT ("cam2_curdist", "160", CV_FLOAT, NULL, NULL); @@ -9663,30 +9575,30 @@ consvar_t cv_cam2_still = CVAR_INIT ("cam2_still", "Off", 0, CV_OnOff, NULL); consvar_t cv_cam2_speed = CVAR_INIT ("cam2_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL); consvar_t cv_cam2_rotate = CVAR_INIT ("cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange); consvar_t cv_cam2_rotspeed = CVAR_INIT ("cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL); -consvar_t cv_cam2_turnmultiplier = CVAR_INIT ("cam2_turnmultiplier", "1.0", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL); +consvar_t cv_cam2_turnmultiplier = CVAR_INIT ("cam2_turnmultiplier", "0.75", CV_FLOAT|CV_SAVE, multiplier_cons_t, NULL); consvar_t cv_cam2_orbit = CVAR_INIT ("cam2_orbit", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_cam2_adjust = CVAR_INIT ("cam2_adjust", "On", CV_SAVE, CV_OnOff, NULL); // [standard vs simple][p1 or p2] consvar_t cv_cam_savedist[2][2] = { { // standard - CVAR_INIT ("cam_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), - CVAR_INIT ("cam2_dist", "160", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), + CVAR_INIT ("cam_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), + CVAR_INIT ("cam2_dist", "192", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), }, { // simple - CVAR_INIT ("cam_simpledist", "224", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), - CVAR_INIT ("cam2_simpledist", "224", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), + CVAR_INIT ("cam_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), + CVAR_INIT ("cam2_simpledist", "256", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), } }; consvar_t cv_cam_saveheight[2][2] = { { // standard - CVAR_INIT ("cam_height", "25", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), - CVAR_INIT ("cam2_height", "25", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), + CVAR_INIT ("cam_height", "40", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), + CVAR_INIT ("cam2_height", "40", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), }, { // simple - CVAR_INIT ("cam_simpleheight", "48", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), - CVAR_INIT ("cam2_simpleheight", "48", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), + CVAR_INIT ("cam_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCamDist), + CVAR_INIT ("cam2_simpleheight", "60", CV_FLOAT|CV_SAVE|CV_CALL, NULL, CV_UpdateCam2Dist), } }; @@ -9868,17 +9780,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (P_CameraThinker(player, thiscam, resetcalled)) return true; - if (tutorialmode) - { - // force defaults because we have a camera look section - camspeed = (INT32)(atof(cv_cam_speed.defaultvalue) * FRACUNIT); - camstill = (!stricmp(cv_cam_still.defaultvalue, "off")) ? false : true; - camorbit = (!stricmp(cv_cam_orbit.defaultvalue, "off")) ? false : true; - camrotate = atoi(cv_cam_rotate.defaultvalue); - camdist = FixedMul((INT32)(atof(cv_cam_dist.defaultvalue) * FRACUNIT), mo->scale); - camheight = FixedMul((INT32)(atof(cv_cam_height.defaultvalue) * FRACUNIT), mo->scale); - } - else if (thiscam == &camera) + if (thiscam == &camera) { camspeed = cv_cam_speed.value; camstill = cv_cam_still.value; @@ -10170,7 +10072,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall for (rover = newsubsec->sector->ffloors; rover; rover = rover->next) { fixed_t topheight, bottomheight; - if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12) + if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || (rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) continue; topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL); @@ -10234,7 +10136,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall // We're inside it! Yess... polysec = po->lines[0]->backsector; - if (GETSECSPECIAL(polysec->special, 4) == 12) + if (polysec->flags & MSF_NOCLIPCAMERA) { // Camera noclip polyobj. plink = (polymaplink_t *)(plink->link.next); continue; @@ -10296,7 +10198,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall for (rover = newsubsec->sector->ffloors; rover; rover = rover->next) { fixed_t topheight, bottomheight; - if ((rover->flags & FF_BLOCKOTHERS) && (rover->flags & FF_RENDERALL) && (rover->flags & FF_EXISTS) && GETSECSPECIAL(rover->master->frontsector->special, 4) != 12) + if ((rover->flags & FF_BLOCKOTHERS) && (rover->flags & FF_RENDERALL) && (rover->flags & FF_EXISTS) && !(rover->master->frontsector->flags & MSF_NOCLIPCAMERA)) { topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL); bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL); @@ -10372,7 +10274,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall thiscam->momx = FixedMul(x - thiscam->x, camspeed); thiscam->momy = FixedMul(y - thiscam->y, camspeed); - if (GETSECSPECIAL(thiscam->subsector->sector->special, 1) == 6 + if (thiscam->subsector->sector->damagetype == SD_DEATHPITTILT && thiscam->z < thiscam->subsector->sector->floorheight + 256*FRACUNIT && FixedMul(z - thiscam->z, camspeed) < 0) { @@ -10492,7 +10394,7 @@ boolean P_SpectatorJoinGame(player_t *player) else changeto = (P_RandomFixed() & 1) + 1; - if (!LUAh_TeamSwitch(player, changeto, true, false, false)) + if (!LUA_HookTeamSwitch(player, changeto, true, false, false)) return false; if (player->mo) @@ -10509,7 +10411,7 @@ boolean P_SpectatorJoinGame(player_t *player) { // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(player, &players[consoleplayer], true); + LUA_HookViewpointSwitch(player, &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -10527,7 +10429,7 @@ boolean P_SpectatorJoinGame(player_t *player) // respawn in place and sit there for the rest of the round. if (!((gametyperules & GTR_HIDEFROZEN) && leveltime > (hidetime * TICRATE))) { - if (!LUAh_TeamSwitch(player, 3, true, false, false)) + if (!LUA_HookTeamSwitch(player, 3, true, false, false)) return false; if (player->mo) { @@ -10554,7 +10456,7 @@ boolean P_SpectatorJoinGame(player_t *player) { // Call ViewpointSwitch hooks here. // The viewpoint was forcibly changed. - LUAh_ViewpointSwitch(player, &players[consoleplayer], true); + LUA_HookViewpointSwitch(player, &players[consoleplayer], true); displayplayer = consoleplayer; } @@ -10579,7 +10481,6 @@ static void P_CalcPostImg(player_t *player) postimg_t *type; INT32 *param; fixed_t pviewheight; - size_t i; if (player->mo->eflags & MFE_VERTICALFLIP) pviewheight = player->mo->z + player->mo->height - player->viewheight; @@ -10604,45 +10505,30 @@ static void P_CalcPostImg(player_t *player) } // see if we are in heat (no, not THAT kind of heat...) - for (i = 0; i < sector->tags.count; i++) + if (sector->flags & MSF_HEATWAVE) + *type = postimg_heat; + else if (sector->ffloors) { - if (Tag_FindLineSpecial(13, sector->tags.tags[i]) != -1) - { - *type = postimg_heat; - break; - } - else if (sector->ffloors) - { - ffloor_t *rover; - fixed_t topheight; - fixed_t bottomheight; - boolean gotres = false; + ffloor_t *rover; + fixed_t topheight; + fixed_t bottomheight; - for (rover = sector->ffloors; rover; rover = rover->next) + for (rover = sector->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + continue; + + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); + + if (pviewheight >= topheight || pviewheight <= bottomheight) + continue; + + if (rover->master->frontsector->flags & MSF_HEATWAVE) { - size_t j; - - if (!(rover->flags & FF_EXISTS)) - continue; - - topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); - bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); - - if (pviewheight >= topheight || pviewheight <= bottomheight) - continue; - - for (j = 0; j < rover->master->frontsector->tags.count; j++) - { - if (Tag_FindLineSpecial(13, rover->master->frontsector->tags.tags[j]) != -1) - { - *type = postimg_heat; - gotres = true; - break; - } - } - } - if (gotres) + *type = postimg_heat; break; + } } } @@ -10881,7 +10767,7 @@ static mobj_t *P_LookForRails(mobj_t* mobj, fixed_t c, fixed_t s, angle_t target fixed_t nx, ny; angle_t nang, dummy, angdiff; mobj_t *mark; - mobj_t *snax = P_GetAxis(sides[lines[lline].sidenum[0]].textureoffset >> FRACBITS); + mobj_t *snax = P_GetAxis(lines[lline].args[0]); if (!snax) return NULL; P_GetAxisPosition(x, y, snax, &nx, &ny, &nang, &dummy); @@ -10983,7 +10869,7 @@ static void P_MinecartThink(player_t *player) // Update axis if the cart is standing on a rail. if (sec && lnum != -1) { - mobj_t *axis = P_GetAxis(sides[lines[lnum].sidenum[0]].textureoffset >> FRACBITS); + mobj_t *axis = P_GetAxis(lines[lnum].args[0]); fixed_t newx, newy; angle_t targetangle, grind; angle_t prevangle, angdiff; @@ -11345,8 +11231,9 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) mobj_t *mo = player->mo; angle_t angle = player->drawangle; fixed_t dist; + fixed_t heightoffset = ((mo->eflags & MFE_VERTICALFLIP) ? mo->height - (P_GetPlayerHeight(player) >> 1) : (P_GetPlayerHeight(player) >> 1)); panim_t panim = player->panim; - tic_t dashmode = player->dashmode; + tic_t dashmode = min(player->dashmode, DASHMODE_MAX); boolean underwater = mo->eflags & MFE_UNDERWATER; statenum_t stat = fume->state-states; @@ -11378,7 +11265,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) offsetV = i*P_ReturnThrustY(fume, fume->movedir, radiusV); x = mo->x + radiusX + FixedMul(offsetH, factorX); y = mo->y + radiusY + FixedMul(offsetH, factorY); - z = mo->z + (mo->height >> 1) + offsetV; + z = mo->z + heightoffset + offsetV; P_SpawnMobj(x, y, z, MT_SMALLBUBBLE)->scale = mo->scale >> 1; } @@ -11441,7 +11328,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) P_UnsetThingPosition(fume); fume->x = mo->x + P_ReturnThrustX(fume, angle, dist); fume->y = mo->y + P_ReturnThrustY(fume, angle, dist); - fume->z = mo->z + ((mo->height - fume->height) >> 1); + fume->z = mo->z + heightoffset - (fume->height >> 1); P_SetThingPosition(fume); // If dashmode is high enough, spawn a trail @@ -11463,6 +11350,9 @@ void P_PlayerThink(player_t *player) I_Error("p_playerthink: players[%s].mo == NULL", sizeu1(playeri)); #endif + // Reset terrain blocked status for this frame + player->blocked = false; + // todo: Figure out what is actually causing these problems in the first place... if (player->mo->health <= 0 && player->playerstate == PST_LIVE) //you should be DEAD! { @@ -11470,16 +11360,18 @@ 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) { if (B_CheckRespawn(player)) player->playerstate = PST_REBORN; + else + B_HandleFlightIndicator(player); } if (player->playerstate == PST_REBORN) { - LUAh_PlayerThink(player); + LUA_HookPlayer(player, HOOK(PlayerThink)); return; } } @@ -11581,7 +11473,7 @@ void P_PlayerThink(player_t *player) if (player->playerstate == PST_DEAD) { - LUAh_PlayerThink(player); + LUA_HookPlayer(player, HOOK(PlayerThink)); return; } } @@ -11702,7 +11594,7 @@ void P_PlayerThink(player_t *player) { player->mo->flags2 &= ~MF2_SHADOW; P_DeathThink(player); - LUAh_PlayerThink(player); + LUA_HookPlayer(player, HOOK(PlayerThink)); return; } @@ -11744,7 +11636,7 @@ void P_PlayerThink(player_t *player) { if (P_SpectatorJoinGame(player)) { - LUAh_PlayerThink(player); + LUA_HookPlayer(player, HOOK(PlayerThink)); return; // player->mo was removed. } } @@ -11849,7 +11741,7 @@ void P_PlayerThink(player_t *player) if (!player->mo) { - LUAh_PlayerThink(player); + LUA_HookPlayer(player, HOOK(PlayerThink)); return; // P_MovePlayer removed player->mo. } @@ -12023,7 +11915,7 @@ void P_PlayerThink(player_t *player) if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... acceleration = FixedMul(acceleration<mo->movefactor)>>FRACBITS; - P_Thrust(player->mo, moveAngle, -acceleration); + P_Thrust(player->mo, moveAngle, FixedMul(-acceleration, player->mo->scale)); } if (!(player->pflags & PF_AUTOBRAKE) @@ -12232,7 +12124,7 @@ void P_PlayerThink(player_t *player) player->losstime--; // Flash player after being hit. - if (player->powers[pw_flashing] > 0 && player->powers[pw_flashing] < flashingtics && (leveltime & 1)) + if (player->powers[pw_flashing] > 0 && player->powers[pw_flashing] < flashingtics && (leveltime & 1) && player->playerstate == PST_LIVE) player->mo->flags2 |= MF2_DONTDRAW; else player->mo->flags2 &= ~MF2_DONTDRAW; @@ -12303,7 +12195,7 @@ void P_PlayerThink(player_t *player) } #undef dashmode - LUAh_PlayerThink(player); + LUA_HookPlayer(player, HOOK(PlayerThink)); /* // Colormap verification @@ -12356,7 +12248,10 @@ static boolean P_MobjAboveLava(mobj_t *mobj) for (rover = sector->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || GETSECSPECIAL(rover->master->frontsector->special, 1) != 3) + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE)) + continue; + + if (rover->master->frontsector->damagetype != SD_FIRE && rover->master->frontsector->damagetype != SD_LAVA) continue; if (mobj->eflags & MFE_VERTICALFLIP) @@ -12587,7 +12482,7 @@ void P_PlayerAfterThink(player_t *player) player->mo->momz = tails->momz; } - if (G_CoopGametype() && tails->player && tails->player->bot != 1) + if (G_CoopGametype() && tails->player && tails->player->bot != BOT_2PAI) { player->mo->angle = tails->angle; @@ -12598,14 +12493,14 @@ void P_PlayerAfterThink(player_t *player) if (P_AproxDistance(player->mo->x - tails->x, player->mo->y - tails->y) > player->mo->radius) player->powers[pw_carry] = CR_NONE; - if (player->powers[pw_carry] != CR_NONE) + if (player->powers[pw_carry] == CR_PLAYER) { if (player->mo->state-states != S_PLAY_RIDE) P_SetPlayerMobjState(player->mo, S_PLAY_RIDE); if (tails->player && (tails->skin && ((skin_t *)(tails->skin))->sprites[SPR2_SWIM].numframes) && (tails->eflags & MFE_UNDERWATER)) tails->player->powers[pw_tailsfly] = 0; } - else + else if (player->powers[pw_carry] == CR_NONE) P_SetTarget(&player->mo->tracer, NULL); if (player-players == consoleplayer && botingame) @@ -12731,9 +12626,15 @@ void P_PlayerAfterThink(player_t *player) if (player->cmd.forwardmove || player->cmd.sidemove) { - rock->movedir = (player->cmd.angleturn << FRACBITS) + R_PointToAngle2(0, 0, player->cmd.forwardmove << FRACBITS, -player->cmd.sidemove << FRACBITS); + rock->flags2 |= MF2_STRONGBOX; // signifies the rock should not slow to a halt + if (twodlevel || (mo->flags2 & MF2_TWOD)) + rock->movedir = mo->angle; + else + rock->movedir = (player->cmd.angleturn << FRACBITS) + R_PointToAngle2(0, 0, player->cmd.forwardmove << FRACBITS, -player->cmd.sidemove << FRACBITS); P_Thrust(rock, rock->movedir, rock->scale >> 1); } + else + rock->flags2 &= ~MF2_STRONGBOX; mo->momx = rock->momx; mo->momy = rock->momy; @@ -12749,7 +12650,7 @@ void P_PlayerAfterThink(player_t *player) mo->tics = walktics; } - P_TeleportMove(player->mo, rock->x, rock->y, rock->z + rock->height); + P_TeleportMove(player->mo, rock->x, rock->y, rock->z + ((mo->eflags & MFE_VERTICALFLIP) ? -mo->height : rock->height)); break; } case CR_PTERABYTE: // being carried by a Pterabyte @@ -12787,12 +12688,12 @@ void P_PlayerAfterThink(player_t *player) if (!ptera->movefactor) goto dropoff; - if (ptera->cusval >= 50) + if (ptera->cusval >= 30) { player->powers[pw_carry] = CR_NONE; P_SetTarget(&player->mo->tracer, NULL); P_KillMobj(ptera, player->mo, player->mo, 0); - player->mo->momz = 9*FRACUNIT; + P_SetObjectMomZ(player->mo, 12*FRACUNIT, false); player->pflags |= PF_APPLYAUTOBRAKE|PF_JUMPED|PF_THOKKED; P_SetMobjState(player->mo, S_PLAY_ROLL); break; @@ -12889,7 +12790,7 @@ void P_PlayerAfterThink(player_t *player) if (player->followmobj) { - if (LUAh_FollowMobj(player, player->followmobj) || P_MobjWasRemoved(player->followmobj)) + if (LUA_HookFollowMobj(player, player->followmobj) || P_MobjWasRemoved(player->followmobj)) {;} else { @@ -12960,3 +12861,37 @@ boolean P_PlayerFullbright(player_t *player) || !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1] && player->mo->state < &states[S_PLAY_NIGHTS_TRANS6])))); // Note the < instead of <= } + +#define JUMPCURLED(player) ((player->pflags & PF_JUMPED)\ + && (!(player->charflags & SF_NOJUMPSPIN))\ + && (player->panim == PA_JUMP || player->panim == PA_ROLL))\ + +// returns true if the player can enter a sector that they could not if standing at their skin's full height +boolean P_PlayerCanEnterSpinGaps(player_t *player) +{ + UINT8 canEnter = LUA_HookPlayerCanEnterSpinGaps(player); + if (canEnter == 1) + return true; + else if (canEnter == 2) + return false; + + return ((player->pflags & (PF_SPINNING|PF_SLIDING|PF_GLIDING)) // players who are spinning, sliding, or gliding + || (player->charability == CA_GLIDEANDCLIMB && player->mo->state-states == S_PLAY_GLIDE_LANDING) // players who are landing from a glide + || ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) + && player->dashmode >= DASHMODE_THRESHOLD && player->mo->state-states == S_PLAY_DASH) // machine players in dashmode + || JUMPCURLED(player)); // players who are jumpcurled, but only if they would normally jump that way +} + +// returns true if the player should use their skin's spinheight instead of their skin's height +boolean P_PlayerShouldUseSpinHeight(player_t *player) +{ + return ((player->pflags & (PF_SPINNING|PF_SLIDING|PF_GLIDING)) + || (player->mo->state == &states[player->mo->info->painstate]) + || (player->panim == PA_ROLL) + || ((player->powers[pw_tailsfly] || (player->charability == CA_FLY && player->mo->state-states == S_PLAY_FLY_TIRED)) + && !(player->charflags & SF_NOJUMPSPIN)) + || (player->charability == CA_GLIDEANDCLIMB && player->mo->state-states == S_PLAY_GLIDE_LANDING) + || ((player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE) + && player->dashmode >= DASHMODE_THRESHOLD && player->mo->state-states == S_PLAY_DASH) + || JUMPCURLED(player)); +} diff --git a/src/r_bsp.c b/src/r_bsp.c index 6f2a90d2d..f0a761d7b 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -238,11 +238,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, { if (floorlightlevel) *floorlightlevel = sec->floorlightsec == -1 ? - sec->lightlevel : sectors[sec->floorlightsec].lightlevel; + (sec->floorlightabsolute ? sec->floorlightlevel : max(0, min(255, sec->lightlevel + sec->floorlightlevel))) : sectors[sec->floorlightsec].lightlevel; if (ceilinglightlevel) *ceilinglightlevel = sec->ceilinglightsec == -1 ? - sec->lightlevel : sectors[sec->ceilinglightsec].lightlevel; + (sec->ceilinglightabsolute ? sec->ceilinglightlevel : max(0, min(255, sec->lightlevel + sec->ceilinglightlevel))) : sectors[sec->ceilinglightsec].lightlevel; // if (sec->midmap != -1) // mapnum = sec->midmap; @@ -301,11 +301,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, tempsec->lightlevel = s->lightlevel; if (floorlightlevel) - *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel + *floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel))) : sectors[s->floorlightsec].lightlevel; if (ceilinglightlevel) - *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel + *ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel))) : sectors[s->ceilinglightsec].lightlevel; } else if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight @@ -339,12 +339,12 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel, tempsec->lightlevel = s->lightlevel; if (floorlightlevel) - *floorlightlevel = s->floorlightsec == -1 ? s->lightlevel : - sectors[s->floorlightsec].lightlevel; + *floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel))) + : sectors[s->floorlightsec].lightlevel; if (ceilinglightlevel) - *ceilinglightlevel = s->ceilinglightsec == -1 ? s->lightlevel : - sectors[s->ceilinglightsec].lightlevel; + *ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel))) + : sectors[s->ceilinglightsec].lightlevel; } sec = tempsec; } @@ -370,6 +370,10 @@ boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back) && back->ceiling_yoffs == front->ceiling_yoffs && back->ceilingpic_angle == front->ceilingpic_angle // Consider altered lighting. + && back->floorlightlevel == front->floorlightlevel + && back->floorlightabsolute == front->floorlightabsolute + && back->ceilinglightlevel == front->ceilinglightlevel + && back->ceilinglightabsolute == front->ceilinglightabsolute && back->floorlightsec == front->floorlightsec && back->ceilinglightsec == front->ceilinglightsec // Consider colormaps @@ -804,7 +808,7 @@ static void R_AddPolyObjects(subsector_t *sub) } // for render stats - ps_numpolyobjects += numpolys; + ps_numpolyobjects.value.i += numpolys; // sort polyobjects R_SortPolyObjects(sub); @@ -872,12 +876,12 @@ static void R_Subsector(size_t num) } light = R_GetPlaneLight(frontsector, floorcenterz, false); - if (frontsector->floorlightsec == -1) - floorlightlevel = *frontsector->lightlist[light].lightlevel; + if (frontsector->floorlightsec == -1 && !frontsector->floorlightabsolute) + floorlightlevel = max(0, min(255, *frontsector->lightlist[light].lightlevel + frontsector->floorlightlevel)); floorcolormap = *frontsector->lightlist[light].extra_colormap; light = R_GetPlaneLight(frontsector, ceilingcenterz, false); - if (frontsector->ceilinglightsec == -1) - ceilinglightlevel = *frontsector->lightlist[light].lightlevel; + if (frontsector->ceilinglightsec == -1 && !frontsector->ceilinglightabsolute) + ceilinglightlevel = max(0, min(255, *frontsector->lightlist[light].lightlevel + frontsector->ceilinglightlevel)); ceilingcolormap = *frontsector->lightlist[light].extra_colormap; } @@ -1239,7 +1243,7 @@ void R_RenderBSPNode(INT32 bspnum) node_t *bsp; INT32 side; - ps_numbspcalls++; + ps_numbspcalls.value.i++; while (!(bspnum & NF_SUBSECTOR)) // Found a subsector? { diff --git a/src/r_bsp.h b/src/r_bsp.h index e2da8ebaf..88757cf4b 100644 --- a/src/r_bsp.h +++ b/src/r_bsp.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_data.c b/src/r_data.c index af672f6dc..51ed15dd6 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -30,10 +30,6 @@ #include "byteptr.h" #include "dehacked.h" -#ifdef _WIN32 -#include // alloca(sizeof) -#endif - // // Graphics. // SRB2 graphics for walls and sprites diff --git a/src/r_data.h b/src/r_data.h index aec52b54b..63772e7b0 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -30,9 +30,6 @@ typedef struct size_t numlumps; } lumplist_t; -// Possible alpha types for a patch. -enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; - UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT8 alpha); diff --git a/src/r_defs.h b/src/r_defs.h index 9c649fbc4..9788e6b58 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -139,21 +139,34 @@ typedef enum FF_FLOATBOB = 0x40000, ///< Floats on water and bobs if you step on it. FF_NORETURN = 0x80000, ///< Used with ::FF_CRUMBLE. Will not return to its original position after falling. FF_CRUMBLE = 0x100000, ///< Falls 2 seconds after being stepped on, and randomly brings all touching crumbling 3dfloors down with it, providing their master sectors share the same tag (allows crumble platforms above or below, to also exist). - FF_SHATTERBOTTOM = 0x200000, ///< Used with ::FF_BUSTUP. Like FF_SHATTER, but only breaks from the bottom. Good for springing up through rubble. + FF_GOOWATER = 0x200000, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. FF_MARIO = 0x400000, ///< Acts like a question block when hit from underneath. Goodie spawned at top is determined by master sector. FF_BUSTUP = 0x800000, ///< You can spin through/punch this block and it will crumble! FF_QUICKSAND = 0x1000000, ///< Quicksand! FF_PLATFORM = 0x2000000, ///< You can jump up through this to the top. FF_REVERSEPLATFORM = 0x4000000, ///< A fall-through floor in normal gravity, a platform in reverse gravity. FF_INTANGIBLEFLATS = 0x6000000, ///< Both flats are intangible, but the sides are still solid. - FF_SHATTER = 0x8000000, ///< Used with ::FF_BUSTUP. Bustable on mere touch. - FF_SPINBUST = 0x10000000, ///< Used with ::FF_BUSTUP. Also bustable if you're in your spinning frames. - FF_STRONGBUST = 0x20000000, ///< Used with ::FF_BUSTUP. Only bustable by "strong" characters (Knuckles) and abilities (bouncing, twinspin, melee). - FF_RIPPLE = 0x40000000, ///< Ripple the flats - FF_COLORMAPONLY = 0x80000000, ///< Only copy the colormap, not the lightlevel - FF_GOOWATER = FF_SHATTERBOTTOM, ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop. + FF_RIPPLE = 0x8000000, ///< Ripple the flats + FF_COLORMAPONLY = 0x10000000, ///< Only copy the colormap, not the lightlevel + FF_BOUNCY = 0x20000000, ///< Bounces players + FF_SPLAT = 0x40000000, ///< Use splat flat renderer (treat cyan pixels as invisible) } ffloortype_e; +typedef enum +{ + FB_PUSHABLES = 0x1, // Bustable by pushables + FB_EXECUTOR = 0x2, // Trigger linedef executor + FB_ONLYBOTTOM = 0x4, // Only bustable from below +} ffloorbustflags_e; + +typedef enum +{ + BT_TOUCH, + BT_SPINBUST, + BT_REGULAR, + BT_STRONG, +} busttype_e; + typedef struct ffloor_s { fixed_t *topheight; @@ -184,8 +197,21 @@ typedef struct ffloor_s INT32 lastlight; INT32 alpha; + UINT8 blend; // blendmode tic_t norender; // for culling + // Only relevant for FF_BUSTUP + ffloorbustflags_e bustflags; + UINT8 busttype; + INT16 busttag; + + // Only relevant for FF_QUICKSAND + fixed_t sinkspeed; + fixed_t friction; + + // Only relevant for FF_BOUNCY + fixed_t bouncestrength; + // these are saved for netgames, so do not let Lua touch these! ffloortype_e spawnflags; // flags the 3D floor spawned with INT32 spawnalpha; // alpha the 3D floor spawned with @@ -251,16 +277,68 @@ typedef struct pslope_s typedef enum { // flipspecial - planes with effect - SF_FLIPSPECIAL_FLOOR = 1, - SF_FLIPSPECIAL_CEILING = 1<<1, - SF_FLIPSPECIAL_BOTH = (SF_FLIPSPECIAL_FLOOR|SF_FLIPSPECIAL_CEILING), + MSF_FLIPSPECIAL_FLOOR = 1, + MSF_FLIPSPECIAL_CEILING = 1<<1, + MSF_FLIPSPECIAL_BOTH = (MSF_FLIPSPECIAL_FLOOR|MSF_FLIPSPECIAL_CEILING), // triggerspecial - conditions under which plane touch causes effect - SF_TRIGGERSPECIAL_TOUCH = 1<<2, - SF_TRIGGERSPECIAL_HEADBUMP = 1<<3, + MSF_TRIGGERSPECIAL_TOUCH = 1<<2, + MSF_TRIGGERSPECIAL_HEADBUMP = 1<<3, + // triggerline - conditions for linedef executor triggering + MSF_TRIGGERLINE_PLANE = 1<<4, // require plane touch + MSF_TRIGGERLINE_MOBJ = 1<<5, // allow non-pushable mobjs to trigger // invertprecip - inverts presence of precipitation - SF_INVERTPRECIP = 1<<4, + MSF_INVERTPRECIP = 1<<6, + MSF_GRAVITYFLIP = 1<<7, + MSF_HEATWAVE = 1<<8, + MSF_NOCLIPCAMERA = 1<<9, } sectorflags_t; +typedef enum +{ + SSF_OUTERSPACE = 1, + SSF_DOUBLESTEPUP = 1<<1, + SSF_NOSTEPDOWN = 1<<2, + SSF_WINDCURRENT = 1<<3, + SSF_CONVEYOR = 1<<4, + SSF_SPEEDPAD = 1<<5, + SSF_STARPOSTACTIVATOR = 1<<6, + SSF_EXIT = 1<<7, + SSF_SPECIALSTAGEPIT = 1<<8, + SSF_RETURNFLAG = 1<<9, + SSF_REDTEAMBASE = 1<<10, + SSF_BLUETEAMBASE = 1<<11, + SSF_FAN = 1<<12, + SSF_SUPERTRANSFORM = 1<<13, + SSF_FORCESPIN = 1<<14, + SSF_ZOOMTUBESTART = 1<<15, + SSF_ZOOMTUBEEND = 1<<16, + SSF_FINISHLINE = 1<<17, + SSF_ROPEHANG = 1<<18, +} sectorspecialflags_t; + +typedef enum +{ + SD_NONE = 0, + SD_GENERIC = 1, + SD_WATER = 2, + SD_FIRE = 3, + SD_LAVA = 4, + SD_ELECTRIC = 5, + SD_SPIKE = 6, + SD_DEATHPITTILT = 7, + SD_DEATHPITNOTILT = 8, + SD_INSTAKILL = 9, + SD_SPECIALSTAGE = 10, +} sectordamage_t; + +typedef enum +{ + TO_PLAYER = 0, + TO_ALLPLAYERS = 1, + TO_MOBJ = 2, + TO_PLAYEREMERALDS = 3, // only for binary backwards compatibility: check player emeralds + TO_PLAYERNIGHTS = 4, // only for binary backwards compatibility: check NiGHTS mare +} triggerobject_t; typedef enum { @@ -312,7 +390,11 @@ typedef struct sector_s INT32 heightsec; // other sector, or -1 if no other sector INT32 camsec; // used for camera clipping - INT32 floorlightsec, ceilinglightsec; + // floor and ceiling lighting + INT16 floorlightlevel, ceilinglightlevel; + boolean floorlightabsolute, ceilinglightabsolute; // absolute or relative to sector's light level? + INT32 floorlightsec, ceilinglightsec; // take floor/ceiling light level from another sector + INT32 crumblestate; // used for crumbling and bobbing // list of mobjs that are at least partially in the sector @@ -336,10 +418,18 @@ typedef struct sector_s extracolormap_t *extra_colormap; boolean colormap_protected; - // This points to the master's floorheight, so it can be changed in realtime! - fixed_t *gravity; // per-sector gravity - boolean verticalflip; // If gravity < 0, then allow flipped physics + fixed_t gravity; // per-sector gravity factor + fixed_t *gravityptr; // For binary format: Read gravity from floor height of master sector + sectorflags_t flags; + sectorspecialflags_t specialflags; + UINT8 damagetype; + + // Linedef executor triggering + mtag_t triggertag; // tag to call upon triggering + UINT8 triggerer; // who can trigger? + + fixed_t friction; // Sprite culling feature struct line_s *cullheight; @@ -376,7 +466,7 @@ typedef enum #define HORIZONSPECIAL 41 -#define NUMLINEARGS 6 +#define NUMLINEARGS 10 #define NUMLINESTRINGARGS 2 typedef struct line_s @@ -386,6 +476,7 @@ typedef struct line_s vertex_t *v2; fixed_t dx, dy; // Precalculated v2 - v1 for side checking. + angle_t angle; // Precalculated angle between dx and dy // Animation related. INT16 flags; @@ -397,6 +488,7 @@ typedef struct line_s // Visual appearance: sidedefs. UINT16 sidenum[2]; // sidenum[1] will be 0xffff if one-sided fixed_t alpha; // translucency + UINT8 blendmode; // blendmode INT32 executordelay; fixed_t bbox[4]; // bounding box for the extent of the linedef @@ -713,6 +805,9 @@ typedef struct #pragma pack() #endif +// Possible alpha types for a patch. +enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY, AST_FOG}; + typedef enum { RF_HORIZONTALFLIP = 0x0001, // Flip sprite horizontally @@ -726,17 +821,19 @@ typedef enum RF_NOSPLATBILLBOARD = 0x0040, // Don't billboard floor sprites (faces forward from the view angle) RF_NOSPLATROLLANGLE = 0x0080, // Don't rotate floor sprites by the object's rollangle (uses rotated patches instead) - RF_BLENDMASK = 0x0F00, // --Blending modes - RF_FULLBRIGHT = 0x0100, // Sprite is drawn at full brightness - RF_FULLDARK = 0x0200, // Sprite is drawn completely dark - RF_NOCOLORMAPS = 0x0400, // Sprite is not drawn with colormaps + RF_BRIGHTMASK = 0x00000300, // --Bright modes + RF_FULLBRIGHT = 0x00000100, // Sprite is drawn at full brightness + RF_FULLDARK = 0x00000200, // Sprite is drawn completely dark + RF_SEMIBRIGHT = (RF_FULLBRIGHT | RF_FULLDARK), // between sector bright and full bright - RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types - RF_PAPERSPRITE = 0x1000, // Paper sprite - RF_FLOORSPRITE = 0x2000, // Floor sprite + RF_NOCOLORMAPS = 0x00000400, // Sprite is not drawn with colormaps - RF_SHADOWDRAW = 0x10000, // Stretches and skews the sprite like a shadow. - RF_SHADOWEFFECTS = 0x20000, // Scales and becomes transparent like a shadow. + RF_SPRITETYPEMASK = 0x00003000, // --Different sprite types + RF_PAPERSPRITE = 0x00001000, // Paper sprite + RF_FLOORSPRITE = 0x00002000, // Floor sprite + + RF_SHADOWDRAW = 0x00004000, // Stretches and skews the sprite like a shadow. + RF_SHADOWEFFECTS = 0x00008000, // Scales and becomes transparent like a shadow. RF_DROPSHADOW = (RF_SHADOWDRAW | RF_SHADOWEFFECTS | RF_FULLDARK), } renderflags_t; diff --git a/src/r_draw.c b/src/r_draw.c index d9ea942a2..e12d7ebdd 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -25,6 +25,7 @@ #include "w_wad.h" #include "z_zone.h" #include "console.h" // Until buffering gets finished +#include "libdivide.h" // used by NPO2 tilted span functions #ifdef HWRENDER #include "hardware/hw_main.h" @@ -134,19 +135,51 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; #define DEFAULT_STARTTRANSCOLOR 96 #define NUM_PALETTE_ENTRIES 256 -static UINT8** translationtablecache[MAXSKINS + 7] = {NULL}; +static UINT8 **translationtablecache[MAXSKINS + 7] = {NULL}; UINT8 skincolor_modified[MAXSKINCOLORS]; -CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; +static INT32 SkinToCacheIndex(INT32 skinnum) +{ + switch (skinnum) + { + case TC_DEFAULT: return DEFAULT_TT_CACHE_INDEX; + case TC_BOSS: return BOSS_TT_CACHE_INDEX; + case TC_METALSONIC: return METALSONIC_TT_CACHE_INDEX; + case TC_ALLWHITE: return ALLWHITE_TT_CACHE_INDEX; + case TC_RAINBOW: return RAINBOW_TT_CACHE_INDEX; + case TC_BLINK: return BLINK_TT_CACHE_INDEX; + case TC_DASHMODE: return DASHMODE_TT_CACHE_INDEX; + default: break; + } -#define TRANSTAB_AMTMUL10 (256.0f / 10.0f) + return skinnum; +} + +static INT32 CacheIndexToSkin(INT32 ttc) +{ + switch (ttc) + { + case DEFAULT_TT_CACHE_INDEX: return TC_DEFAULT; + case BOSS_TT_CACHE_INDEX: return TC_BOSS; + case METALSONIC_TT_CACHE_INDEX: return TC_METALSONIC; + case ALLWHITE_TT_CACHE_INDEX: return TC_ALLWHITE; + case RAINBOW_TT_CACHE_INDEX: return TC_RAINBOW; + case BLINK_TT_CACHE_INDEX: return TC_BLINK; + case DASHMODE_TT_CACHE_INDEX: return TC_DASHMODE; + default: break; + } + + return ttc; +} + +CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; /** \brief Initializes the translucency tables used by the Software renderer. */ void R_InitTranslucencyTables(void) { - // Load here the transparency lookup tables 'TINTTAB' - // NOTE: the TINTTAB resource MUST BE aligned on 64k for the asm + // Load here the transparency lookup tables 'TRANSx0' + // NOTE: the TRANSx0 resources MUST BE aligned on 64k for the asm // optimised code (in other words, transtables pointer low word is 0) transtables = Z_MallocAlign(NUMTRANSTABLES*0x10000, PU_STATIC, NULL, 16); @@ -164,42 +197,14 @@ void R_InitTranslucencyTables(void) R_GenerateBlendTables(); } -void R_GenerateBlendTables(void) -{ - INT32 i; - - for (i = 0; i < NUMBLENDMAPS; i++) - { - if (i == blendtab_modulate) - continue; - blendtables[i] = Z_MallocAlign((NUMTRANSTABLES + 1) * 0x10000, PU_STATIC, NULL, 16); - } - - for (i = 0; i <= 9; i++) - { - const size_t offs = (0x10000 * i); - const UINT8 alpha = TRANSTAB_AMTMUL10 * i; - - R_GenerateTranslucencyTable(blendtables[blendtab_add] + offs, AST_ADD, alpha); - R_GenerateTranslucencyTable(blendtables[blendtab_subtract] + offs, AST_SUBTRACT, alpha); - R_GenerateTranslucencyTable(blendtables[blendtab_reversesubtract] + offs, AST_REVERSESUBTRACT, alpha); - } - - // Modulation blending only requires a single table - blendtables[blendtab_modulate] = Z_MallocAlign(0x10000, PU_STATIC, NULL, 16); - R_GenerateTranslucencyTable(blendtables[blendtab_modulate], AST_MODULATE, 0); -} - static colorlookup_t transtab_lut; -void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt) +static void BlendTab_Translucent(UINT8 *table, int style, UINT8 blendamt) { INT16 bg, fg; if (table == NULL) - I_Error("R_GenerateTranslucencyTable: input table was NULL!"); - - InitColorLUT(&transtab_lut, pMasterPalette, false); + I_Error("BlendTab_Translucent: input table was NULL!"); for (bg = 0; bg < 0xFF; bg++) { @@ -209,12 +214,126 @@ void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt) RGBA_t frontrgba = V_GetMasterColor(fg); RGBA_t result; - result.rgba = ASTBlendPixel(backrgba, frontrgba, style, blendamt); + result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF); + result.rgba = ASTBlendPixel(result, frontrgba, AST_TRANSLUCENT, blendamt); + table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue); } } } +static void BlendTab_Subtractive(UINT8 *table, int style, UINT8 blendamt) +{ + INT16 bg, fg; + + if (table == NULL) + I_Error("BlendTab_Subtractive: input table was NULL!"); + + if (blendamt == 0xFF) + { + memset(table, GetColorLUT(&transtab_lut, 0, 0, 0), 0x10000); + return; + } + + for (bg = 0; bg < 0xFF; bg++) + { + for (fg = 0; fg < 0xFF; fg++) + { + RGBA_t backrgba = V_GetMasterColor(bg); + RGBA_t frontrgba = V_GetMasterColor(fg); + RGBA_t result; + + result.rgba = ASTBlendPixel(backrgba, frontrgba, style, 0xFF); + result.s.red = max(0, result.s.red - blendamt); + result.s.green = max(0, result.s.green - blendamt); + result.s.blue = max(0, result.s.blue - blendamt); + + //probably incorrect, but does look better at lower opacity... + //result.rgba = ASTBlendPixel(result, frontrgba, AST_TRANSLUCENT, blendamt); + + table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue); + } + } +} + +static void BlendTab_Modulative(UINT8 *table) +{ + INT16 bg, fg; + + if (table == NULL) + I_Error("BlendTab_Modulative: input table was NULL!"); + + for (bg = 0; bg < 0xFF; bg++) + { + for (fg = 0; fg < 0xFF; fg++) + { + RGBA_t backrgba = V_GetMasterColor(bg); + RGBA_t frontrgba = V_GetMasterColor(fg); + RGBA_t result; + result.rgba = ASTBlendPixel(backrgba, frontrgba, AST_MODULATE, 0); + table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue); + } + } +} + +static INT32 BlendTab_Count[NUMBLENDMAPS] = +{ + NUMTRANSTABLES+1, // blendtab_add + NUMTRANSTABLES+1, // blendtab_subtract + NUMTRANSTABLES+1, // blendtab_reversesubtract + 1 // blendtab_modulate +}; + +static INT32 BlendTab_FromStyle[] = +{ + 0, // AST_COPY + 0, // AST_TRANSLUCENT + blendtab_add, // AST_ADD + blendtab_subtract, // AST_SUBTRACT + blendtab_reversesubtract, // AST_REVERSESUBTRACT + blendtab_modulate, // AST_MODULATE + 0 // AST_OVERLAY +}; + +static void BlendTab_GenerateMaps(INT32 tab, INT32 style, void (*genfunc)(UINT8 *, int, UINT8)) +{ + INT32 i = 0, num = BlendTab_Count[tab]; + const float amtmul = (256.0f / (float)(NUMTRANSTABLES + 1)); + for (; i < num; i++) + { + const size_t offs = (0x10000 * i); + const UINT16 alpha = min(amtmul * i, 0xFF); + genfunc(blendtables[tab] + offs, style, alpha); + } +} + +void R_GenerateBlendTables(void) +{ + INT32 i; + + for (i = 0; i < NUMBLENDMAPS; i++) + blendtables[i] = Z_MallocAlign(BlendTab_Count[i] * 0x10000, PU_STATIC, NULL, 16); + + InitColorLUT(&transtab_lut, pMasterPalette, false); + + // Additive + BlendTab_GenerateMaps(blendtab_add, AST_ADD, BlendTab_Translucent); + + // Subtractive +#if 1 + BlendTab_GenerateMaps(blendtab_subtract, AST_SUBTRACT, BlendTab_Subtractive); +#else + BlendTab_GenerateMaps(blendtab_subtract, AST_SUBTRACT, BlendTab_Translucent); +#endif + + // Reverse subtractive + BlendTab_GenerateMaps(blendtab_reversesubtract, AST_REVERSESUBTRACT, BlendTab_Translucent); + + // Modulative blending only requires a single table + BlendTab_Modulative(blendtables[blendtab_modulate]); +} + +#define ClipBlendLevel(style, trans) max(min((trans), BlendTab_Count[BlendTab_FromStyle[style]]-1), 0) #define ClipTransLevel(trans) max(min((trans), NUMTRANSMAPS-2), 0) UINT8 *R_GetTranslucencyTable(INT32 alphalevel) @@ -224,7 +343,12 @@ UINT8 *R_GetTranslucencyTable(INT32 alphalevel) UINT8 *R_GetBlendTable(int style, INT32 alphalevel) { - size_t offs = (ClipTransLevel(alphalevel) << FF_TRANSSHIFT); + size_t offs; + + if (style <= AST_COPY || style >= AST_OVERLAY) + return NULL; + + offs = (ClipBlendLevel(style, alphalevel) << FF_TRANSSHIFT); // Lactozilla: Returns the equivalent to AST_TRANSLUCENT // if no alpha style matches any of the blend tables. @@ -249,6 +373,14 @@ UINT8 *R_GetBlendTable(int style, INT32 alphalevel) return NULL; } +boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel) +{ + if (blendmode <= AST_COPY || blendmode == AST_SUBTRACT || blendmode == AST_MODULATE || blendmode >= AST_OVERLAY) + return true; + + return (alphalevel < BlendTab_Count[BlendTab_FromStyle[blendmode]]); +} + // Define for getting accurate color brightness readings according to how the human eye sees them. // https://en.wikipedia.org/wiki/Relative_luminance // 0.2126 to red @@ -308,7 +440,7 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor) /** \brief Generates a translation colormap. \param dest_colormap colormap to populate - \param skinnum number of skin, TC_DEFAULT or TC_BOSS + \param skinnum skin number, or a translation mode \param color translation color \return void @@ -353,8 +485,12 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U // White! if (skinnum == TC_BOSS) { + UINT8 *originalColormap = R_GetTranslationColormap(TC_DEFAULT, (skincolornum_t)color, GTC_CACHE); for (i = 0; i < 16; i++) + { + dest_colormap[DEFAULT_STARTTRANSCOLOR + i] = originalColormap[DEFAULT_STARTTRANSCOLOR + i]; dest_colormap[31-i] = i; + } } else if (skinnum == TC_METALSONIC) { @@ -412,6 +548,9 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U if (color >= numskincolors) I_Error("Invalid skin color #%hu.", (UINT16)color); + if (skinnum < 0 && skinnum > TC_DEFAULT) + I_Error("Invalid translation colormap index %d.", skinnum); + starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; if (starttranscolor >= NUM_PALETTE_ENTRIES) @@ -448,25 +587,11 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags) { UINT8* ret; - INT32 skintableindex; + INT32 skintableindex = SkinToCacheIndex(skinnum); // Adjust if we want the default colormap INT32 i; - // Adjust if we want the default colormap - switch (skinnum) - { - case TC_DEFAULT: skintableindex = DEFAULT_TT_CACHE_INDEX; break; - case TC_BOSS: skintableindex = BOSS_TT_CACHE_INDEX; break; - case TC_METALSONIC: skintableindex = METALSONIC_TT_CACHE_INDEX; break; - case TC_ALLWHITE: skintableindex = ALLWHITE_TT_CACHE_INDEX; break; - case TC_RAINBOW: skintableindex = RAINBOW_TT_CACHE_INDEX; break; - case TC_BLINK: skintableindex = BLINK_TT_CACHE_INDEX; break; - case TC_DASHMODE: skintableindex = DASHMODE_TT_CACHE_INDEX; break; - default: skintableindex = skinnum; break; - } - if (flags & GTC_CACHE) { - // Allocate table for skin if necessary if (!translationtablecache[skintableindex]) translationtablecache[skintableindex] = Z_Calloc(MAXSKINCOLORS * sizeof(UINT8**), PU_STATIC, NULL); @@ -479,7 +604,8 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags { for (i = 0; i < (INT32)(sizeof(translationtablecache) / sizeof(translationtablecache[0])); i++) if (translationtablecache[i] && translationtablecache[i][color]) - R_GenerateTranslationColormap(translationtablecache[i][color], i>=MAXSKINS ? MAXSKINS-i-1 : i, color); + R_GenerateTranslationColormap(translationtablecache[i][color], CacheIndexToSkin(i), color); + skincolor_modified[color] = false; } } diff --git a/src/r_draw.h b/src/r_draw.h index d1eb83033..c96b29e30 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -140,11 +140,12 @@ extern UINT8 *blendtables[NUMBLENDMAPS]; void R_InitTranslucencyTables(void); void R_GenerateBlendTables(void); -void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt); UINT8 *R_GetTranslucencyTable(INT32 alphalevel); UINT8 *R_GetBlendTable(int style, INT32 alphalevel); +boolean R_BlendLevelVisible(INT32 blendmode, INT32 alphalevel); + // Color ramp modification should force a recache extern UINT8 skincolor_modified[]; @@ -169,6 +170,7 @@ void R_DrawViewBorder(void); void R_DrawColumn_8(void); void R_DrawShadeColumn_8(void); void R_DrawTranslucentColumn_8(void); +void R_DrawDropShadowColumn_8(void); void R_DrawTranslatedColumn_8(void); void R_DrawTranslatedTranslucentColumn_8(void); void R_Draw2sMultiPatchColumn_8(void); @@ -176,7 +178,7 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void); void R_DrawFogColumn_8(void); void R_DrawColumnShadowed_8(void); -#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) +#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / zeroheight / 21.0f * FIXED_TO_FLOAT(fovtan)) void R_DrawSpan_8(void); void R_DrawTranslucentSpan_8(void); diff --git a/src/r_draw16.c b/src/r_draw16.c index 8b1d29e8d..763fd1631 100644 --- a/src/r_draw16.c +++ b/src/r_draw16.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_draw8.c b/src/r_draw8.c index e78ba8a6c..c9a9e9575 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -416,6 +416,39 @@ void R_DrawTranslucentColumn_8(void) } } +// Hack: A cut-down copy of R_DrawTranslucentColumn_8 that does not read texture +// data since something about calculating the texture reading address for drop shadows is broken. +// dc_texturemid and dc_iscale get wrong values for drop shadows, however those are not strictly +// needed for the current design of the shadows, so this function bypasses the issue +// by not using those variables at all. +void R_DrawDropShadowColumn_8(void) +{ + register INT32 count; + register UINT8 *dest; + + count = dc_yh - dc_yl + 1; + + if (count <= 0) // Zero length, column does not exceed a pixel. + return; + + dest = &topleft[dc_yl*vid.width + dc_x]; + + { +#define DSCOLOR 31 // palette index for the color of the shadow + register const UINT8 *transmap_offset = dc_transmap + (dc_colormap[DSCOLOR] << 8); +#undef DSCOLOR + while ((count -= 2) >= 0) + { + *dest = *(transmap_offset + (*dest)); + dest += vid.width; + *dest = *(transmap_offset + (*dest)); + dest += vid.width; + } + if (count & 1) + *dest = *(transmap_offset + (*dest)); + } +} + /** \brief The R_DrawTranslatedTranslucentColumn_8 function Spiffy function. Not only does it colormap a sprite, but does translucency as well. Uber-kudos to Cyan Helkaraxe @@ -693,8 +726,8 @@ void R_DrawTiltedSpan_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); @@ -726,8 +759,8 @@ void R_DrawTiltedSpan_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { @@ -763,8 +796,8 @@ void R_DrawTiltedSpan_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { @@ -826,8 +859,8 @@ void R_DrawTiltedTranslucentSpan_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dest); @@ -858,8 +891,8 @@ void R_DrawTiltedTranslucentSpan_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { @@ -895,8 +928,8 @@ void R_DrawTiltedTranslucentSpan_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { @@ -960,8 +993,8 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); *dest = *(ds_transmap + (colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]] << 8) + *dsrc++); @@ -992,8 +1025,8 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { @@ -1029,8 +1062,8 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { @@ -1091,8 +1124,8 @@ void R_DrawTiltedSplat_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); @@ -1127,8 +1160,8 @@ void R_DrawTiltedSplat_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { @@ -1168,8 +1201,8 @@ void R_DrawTiltedSplat_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { @@ -1227,8 +1260,9 @@ void R_DrawSplat_8 (void) // need! // // 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) + // Why decimal? 0x3FFFFF == 4194303... ~Golden val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[0] = colormap[val]; @@ -1236,7 +1270,7 @@ void R_DrawSplat_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[1] = colormap[val]; @@ -1244,7 +1278,7 @@ void R_DrawSplat_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[2] = colormap[val]; @@ -1252,7 +1286,7 @@ void R_DrawSplat_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[3] = colormap[val]; @@ -1260,7 +1294,7 @@ void R_DrawSplat_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[4] = colormap[val]; @@ -1268,7 +1302,7 @@ void R_DrawSplat_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[5] = colormap[val]; @@ -1276,7 +1310,7 @@ void R_DrawSplat_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[6] = colormap[val]; @@ -1284,7 +1318,7 @@ void R_DrawSplat_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; + val &= 0x3FFFFF; val = source[val]; if (val != TRANSPARENTPIXEL) dest[7] = colormap[val]; @@ -1447,10 +1481,7 @@ void R_DrawFloorSprite_8 (void) // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't // have the uber complicated math to calculate it now, so that was a memory write we didn't // need! - // - // 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[0] = colormap[translation[val & 0xFF]]; @@ -1458,7 +1489,6 @@ void R_DrawFloorSprite_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[1] = colormap[translation[val & 0xFF]]; @@ -1466,7 +1496,6 @@ void R_DrawFloorSprite_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[2] = colormap[translation[val & 0xFF]]; @@ -1474,7 +1503,6 @@ void R_DrawFloorSprite_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[3] = colormap[translation[val & 0xFF]]; @@ -1482,7 +1510,6 @@ void R_DrawFloorSprite_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[4] = colormap[translation[val & 0xFF]]; @@ -1490,7 +1517,6 @@ void R_DrawFloorSprite_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[5] = colormap[translation[val & 0xFF]]; @@ -1498,7 +1524,6 @@ void R_DrawFloorSprite_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[6] = colormap[translation[val & 0xFF]]; @@ -1506,7 +1531,6 @@ void R_DrawFloorSprite_8 (void) yposition += ystep; val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); - val &= 4194303; val = source[val]; if (val & 0xFF00) dest[7] = colormap[translation[val & 0xFF]]; @@ -1682,8 +1706,8 @@ void R_DrawTiltedFloorSprite_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { @@ -1722,8 +1746,8 @@ void R_DrawTiltedFloorSprite_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { @@ -1791,8 +1815,8 @@ void R_DrawTiltedTranslucentFloorSprite_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { @@ -1831,8 +1855,8 @@ void R_DrawTiltedTranslucentFloorSprite_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index a34a20e9a..49ec28dd8 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -106,6 +106,9 @@ void R_DrawTiltedSpan_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); // Lighting is simple. It's just linear interpolation from start to end @@ -133,24 +136,25 @@ void R_DrawTiltedSpan_NPO2_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = colormap[source[((y * ds_flatwidth) + x)]]; } @@ -181,25 +185,26 @@ void R_DrawTiltedSpan_NPO2_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = colormap[source[((y * ds_flatwidth) + x)]]; } @@ -220,17 +225,18 @@ void R_DrawTiltedSpan_NPO2_8(void) colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = colormap[source[((y * ds_flatwidth) + x)]]; } @@ -248,25 +254,26 @@ void R_DrawTiltedSpan_NPO2_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = colormap[source[((y * ds_flatwidth) + x)]]; } @@ -299,6 +306,9 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); // Lighting is simple. It's just linear interpolation from start to end @@ -326,23 +336,24 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); } @@ -373,25 +384,26 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); } @@ -412,17 +424,18 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); } @@ -440,25 +453,26 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dest); } @@ -490,6 +504,9 @@ void R_DrawTiltedSplat_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); // Lighting is simple. It's just linear interpolation from start to end @@ -517,24 +534,25 @@ void R_DrawTiltedSplat_NPO2_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; } @@ -569,25 +587,26 @@ void R_DrawTiltedSplat_NPO2_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; } @@ -610,17 +629,18 @@ void R_DrawTiltedSplat_NPO2_8(void) colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; } @@ -640,26 +660,26 @@ void R_DrawTiltedSplat_NPO2_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); - val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; } @@ -972,6 +992,9 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); @@ -1002,23 +1025,24 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { // Lactozilla: Non-powers-of-two - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1040,17 +1064,18 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) v = (INT64)(startv); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1070,23 +1095,24 @@ void R_DrawTiltedFloorSprite_NPO2_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { // Lactozilla: Non-powers-of-two - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1122,6 +1148,9 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); @@ -1152,23 +1181,24 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { // Lactozilla: Non-powers-of-two - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1190,17 +1220,18 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) v = (INT64)(startv); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1220,23 +1251,24 @@ void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { // Lactozilla: Non-powers-of-two - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; val = source[((y * ds_flatwidth) + x)]; if (val & 0xFF00) @@ -1401,6 +1433,9 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) double endz, endu, endv; UINT32 stepu, stepv; + struct libdivide_u32_t x_divider = libdivide_u32_gen(ds_flatwidth); + struct libdivide_u32_t y_divider = libdivide_u32_gen(ds_flatheight); + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); // Lighting is simple. It's just linear interpolation from start to end @@ -1429,23 +1464,24 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) do { double z = 1.f/iz; - u = (INT64)(uz*z) + viewx; - v = (INT64)(vz*z) + viewy; + u = (INT64)(uz*z); + v = (INT64)(vz*z); colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++); } @@ -1476,25 +1512,26 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) endv = vz*endz; stepu = (INT64)((endu - startu) * INVSPAN); stepv = (INT64)((endv - startv) * INVSPAN); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (i = SPANSIZE-1; i >= 0; i--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++); } @@ -1515,17 +1552,18 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++); } @@ -1543,25 +1581,26 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) left = 1.f/left; stepu = (INT64)((endu - startu) * left); stepv = (INT64)((endv - startv) * left); - u = (INT64)(startu) + viewx; - v = (INT64)(startv) + viewy; + u = (INT64)(startu); + v = (INT64)(startv); for (; width != 0; width--) { colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps); // Lactozilla: Non-powers-of-two { - fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); - fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + fixed_t x = (((fixed_t)u) >> FRACBITS); + fixed_t y = (((fixed_t)v) >> FRACBITS); // Carefully align all of my Friends. if (x < 0) - x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + x += (libdivide_u32_do((UINT32)(-x-1), &x_divider) + 1) * ds_flatwidth; + else + x -= libdivide_u32_do((UINT32)x, &x_divider) * ds_flatwidth; if (y < 0) - y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); - - x %= ds_flatwidth; - y %= ds_flatheight; + y += (libdivide_u32_do((UINT32)(-y-1), &y_divider) + 1) * ds_flatheight; + else + y -= libdivide_u32_do((UINT32)y, &y_divider) * ds_flatheight; *dest = *(ds_transmap + (colormap[source[((y * ds_flatwidth) + x)]] << 8) + *dsrc++); } diff --git a/src/r_local.h b/src/r_local.h index 4ccb766cf..a5b590e5c 100644 --- a/src/r_local.h +++ b/src/r_local.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_main.c b/src/r_main.c index f82fb589e..f19962d41 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -101,21 +101,22 @@ extracolormap_t *extra_colormaps = NULL; // Render stats precise_t ps_prevframetime = 0; -precise_t ps_rendercalltime = 0; -precise_t ps_uitime = 0; -precise_t ps_swaptime = 0; +ps_metric_t ps_rendercalltime = {0}; +ps_metric_t ps_otherrendertime = {0}; +ps_metric_t ps_uitime = {0}; +ps_metric_t ps_swaptime = {0}; -precise_t ps_bsptime = 0; +ps_metric_t ps_bsptime = {0}; -precise_t ps_sw_spritecliptime = 0; -precise_t ps_sw_portaltime = 0; -precise_t ps_sw_planetime = 0; -precise_t ps_sw_maskedtime = 0; +ps_metric_t ps_sw_spritecliptime = {0}; +ps_metric_t ps_sw_portaltime = {0}; +ps_metric_t ps_sw_planetime = {0}; +ps_metric_t ps_sw_maskedtime = {0}; -int ps_numbspcalls = 0; -int ps_numsprites = 0; -int ps_numdrawnodes = 0; -int ps_numpolyobjects = 0; +ps_metric_t ps_numbspcalls = {0}; +ps_metric_t ps_numsprites = {0}; +ps_metric_t ps_numdrawnodes = {0}; +ps_metric_t ps_numpolyobjects = {0}; static CV_PossibleValue_t drawdist_cons_t[] = { {256, "256"}, {512, "512"}, {768, "768"}, @@ -444,7 +445,7 @@ fixed_t R_ScaleFromGlobalAngle(angle_t visangle) // R_DoCulling // Checks viewz and top/bottom heights of an item against culling planes // Returns true if the item is to be culled, i.e it shouldn't be drawn! -// if ML_NOCLIMB is set, the camera view is required to be in the same area for culling to occur +// if args[1] is set, the camera view is required to be in the same area for culling to occur boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph) { fixed_t cullplane; @@ -453,7 +454,7 @@ boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixe return false; cullplane = cullheight->frontsector->floorheight; - if (cullheight->flags & ML_NOCLIMB) // Group culling + if (cullheight->args[1]) // Group culling { if (!viewcullheight) return false; @@ -955,7 +956,7 @@ void R_ExecuteSetViewSize(void) j = viewheight*16; for (i = 0; i < j; i++) { - dy = ((i - viewheight*8)<>FRACBITS) * viewwidth/BASEVIDWIDTH; - yslope = &yslopetab[viewheight*8 - (viewheight/2 + dy)]; - } + centeryfrac = (viewheight/2)< size) { UINT16 *src, *dest; diff --git a/src/r_patchrotation.h b/src/r_patchrotation.h index 2744f71d2..e6bee80ed 100644 --- a/src/r_patchrotation.h +++ b/src/r_patchrotation.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// Copyright (C) 2020-2022 by Jaime "Lactozilla" Passos. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_picformats.c b/src/r_picformats.c index 02f1de4ab..6aa4659b9 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -2,8 +2,8 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 2005-2009 by Andrey "entryway" Budko. -// Copyright (C) 2018-2020 by Jaime "Lactozilla" Passos. -// Copyright (C) 2019-2020 by Sonic Team Junior. +// Copyright (C) 2018-2022 by Jaime "Lactozilla" Passos. +// Copyright (C) 2019-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -540,55 +540,60 @@ void *Picture_GetPatchPixel( { fixed_t ofs; column_t *column; - UINT8 *s8 = NULL; - UINT16 *s16 = NULL; - UINT32 *s32 = NULL; + INT32 inbpp = Picture_FormatBPP(informat); softwarepatch_t *doompatch = (softwarepatch_t *)patch; + boolean isdoompatch = Picture_IsDoomPatchFormat(informat); INT16 width; if (patch == NULL) I_Error("Picture_GetPatchPixel: patch == NULL"); - width = (Picture_IsDoomPatchFormat(informat) ? patch->width : SHORT(patch->width)); + width = (isdoompatch ? SHORT(doompatch->width) : patch->width); if (x >= 0 && x < width) { INT32 colx = (flags & PICFLAGS_XFLIP) ? (width-1)-x : x; INT32 topdelta, prevdelta = -1; - INT32 colofs = (Picture_IsDoomPatchFormat(informat) ? LONG(patch->columnofs[colx]) : patch->columnofs[colx]); + INT32 colofs = (isdoompatch ? LONG(doompatch->columnofs[colx]) : patch->columnofs[colx]); - // Column offsets are pointers so no casting required - if (Picture_IsDoomPatchFormat(informat)) + // Column offsets are pointers, so no casting is required. + if (isdoompatch) column = (column_t *)((UINT8 *)doompatch + colofs); else column = (column_t *)((UINT8 *)patch->columns + colofs); while (column->topdelta != 0xff) { + UINT8 *s8 = NULL; + UINT16 *s16 = NULL; + UINT32 *s32 = NULL; + topdelta = column->topdelta; if (topdelta <= prevdelta) topdelta += prevdelta; prevdelta = topdelta; - s8 = (UINT8 *)(column) + 3; - if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) - s32 = (UINT32 *)s8; - else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) - s16 = (UINT16 *)s8; - for (ofs = 0; ofs < column->length; ofs++) + + ofs = (y - topdelta); + + if (y >= topdelta && ofs < column->length) { - if ((topdelta + ofs) == y) + s8 = (UINT8 *)(column) + 3; + switch (inbpp) { - if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) + case PICDEPTH_32BPP: + s32 = (UINT32 *)s8; return &s32[ofs]; - else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) + case PICDEPTH_16BPP: + s16 = (UINT16 *)s8; return &s16[ofs]; - else // PICDEPTH_8BPP + default: // PICDEPTH_8BPP return &s8[ofs]; } } - if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) + + if (inbpp == PICDEPTH_32BPP) column = (column_t *)((UINT32 *)column + column->length); - else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) + else if (inbpp == PICDEPTH_16BPP) column = (column_t *)((UINT16 *)column + column->length); else column = (column_t *)((UINT8 *)column + column->length); @@ -896,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 @@ -978,8 +982,8 @@ static png_bytep *PNG_Read( for (i = 0; i < 256; i++) { - UINT32 rgb = R_PutRgbaRGBA(pal->red, pal->green, pal->blue, 0xFF); - if (rgb != pMasterPalette[i].rgba) + byteColor_t *curpal = &(pMasterPalette[i].s); + if (pal->red != curpal->red || pal->green != curpal->green || pal->blue != curpal->blue) { usepal = false; break; @@ -993,14 +997,14 @@ 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 == 256) + 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 RGB even if + // libpng will transform this image into RGBA even if // the transparent index does not exist in the image, // and there is no way around that. if (trans[i] < 0xFF) diff --git a/src/r_picformats.h b/src/r_picformats.h index 8d3999013..f3080479f 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -1,8 +1,8 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 2018-2020 by Jaime "Lactozilla" Passos. -// Copyright (C) 2019-2020 by Sonic Team Junior. +// Copyright (C) 2018-2022 by Jaime "Lactozilla" Passos. +// Copyright (C) 2019-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -105,6 +105,7 @@ typedef struct } spriteinfo_t; // Portable Network Graphics +#define PNG_HEADER_SIZE (8) boolean Picture_IsLumpPNG(const UINT8 *d, size_t s); #define Picture_ThrowPNGError(lumpname, wadfilename) I_Error("W_Wad: Lump \"%s\" in file \"%s\" is a .png - please convert to either Doom or Flat (raw) image format.", lumpname, wadfilename); // Fears Of LJ Sonic @@ -116,9 +117,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 c54b32382..7ea10f616 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -31,13 +31,6 @@ #include "z_zone.h" #include "p_tick.h" -#ifdef TIMING -#include "p5prof.h" - INT64 mycount; - INT64 mytotal = 0; - UINT32 nombre = 100000; -#endif - // // opening // @@ -96,14 +89,13 @@ 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]; fixed_t cachedystep[MAXVIDHEIGHT]; static fixed_t xoffs, yoffs; +static floatv3_t ds_slope_origin, ds_slope_u, ds_slope_v; // // R_InitPlanes @@ -120,28 +112,27 @@ 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; boolean active; } planeripple; -static void R_CalculatePlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight, boolean calcfrac) +// ripples da water texture +static fixed_t R_CalculateRippleOffset(INT32 y) { - fixed_t distance = FixedMul(plheight, yslope[y]); + fixed_t distance = FixedMul(planeheight, yslope[y]); const INT32 yay = (planeripple.offset + (distance>>9)) & 8191; + return FixedDiv(FINESINE(yay), (1<<12) + (distance>>11)); +} - // ripples da water texture - ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS; - - if (calcfrac) - { - angle_t angle = (plane->viewangle + plane->plangle)>>ANGLETOFINESHIFT; - angle = (angle + 2048) & 8191; // 90 degrees - planeripple.xfrac = FixedMul(FINECOSINE(angle), (ds_bgofs<>= ANGLETOFINESHIFT; + angle = (angle + 2048) & 8191; // 90 degrees + planeripple.xfrac = FixedMul(FINECOSINE(angle), ds_bgofs); + planeripple.yfrac = FixedMul(FINESINE(angle), ds_bgofs); } static void R_UpdatePlaneRipple(void) @@ -150,20 +141,7 @@ static void R_UpdatePlaneRipple(void) planeripple.offset = (leveltime * 140); } -// -// R_MapPlane -// -// Uses global vars: -// basexscale -// baseyscale -// centerx -// viewx -// viewy -// viewsin -// viewcos -// viewheight - -void R_MapPlane(INT32 y, INT32 x1, INT32 x2) +static void R_MapPlane(INT32 y, INT32 x1, INT32 x2) { angle_t angle, planecos, planesin; fixed_t distance = 0, span; @@ -177,60 +155,52 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) if (x1 >= vid.width) x1 = vid.width - 1; - if (!currentplane->slope) + angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; + planecos = FINECOSINE(angle); + planesin = FINESINE(angle); + + if (planeheight != cachedheight[y]) { - angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; - planecos = FINECOSINE(angle); - planesin = FINESINE(angle); + cachedheight[y] = planeheight; + cacheddistance[y] = distance = FixedMul(planeheight, yslope[y]); + span = abs(centery - y); - if (planeheight != cachedheight[y]) + if (span) // Don't divide by zero { - cachedheight[y] = planeheight; - cacheddistance[y] = distance = FixedMul(planeheight, yslope[y]); - span = abs(centery - y); - - 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); - } - - cachedxstep[y] = ds_xstep; - cachedystep[y] = ds_ystep; + ds_xstep = FixedMul(planesin, planeheight) / span; + ds_ystep = FixedMul(planecos, planeheight) / span; } else - { - distance = cacheddistance[y]; - ds_xstep = cachedxstep[y]; - ds_ystep = cachedystep[y]; - } + ds_xstep = ds_ystep = FRACUNIT; - ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; - ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; + cachedxstep[y] = ds_xstep; + cachedystep[y] = ds_ystep; } + else + { + distance = cacheddistance[y]; + ds_xstep = cachedxstep[y]; + ds_ystep = cachedystep[y]; + } + + // [RH] Instead of using the xtoviewangle array, I calculated the fractional values + // at the middle of the screen, then used the calculated ds_xstep and ds_ystep + // to step from those to the proper texture coordinate to start drawing at. + // That way, the texture coordinate is always calculated by its position + // on the screen and not by its position relative to the edge of the visplane. + ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; + ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; // Water ripple effect if (planeripple.active) { - // Needed for ds_bgofs - R_CalculatePlaneRipple(currentplane, y, planeheight, (!currentplane->slope)); + ds_bgofs = R_CalculateRippleOffset(y); - if (currentplane->slope) - { - ds_sup = &ds_su[y]; - ds_svp = &ds_sv[y]; - ds_szp = &ds_sz[y]; - } - else - { - ds_xfrac += planeripple.xfrac; - ds_yfrac += planeripple.yfrac; - } + R_CalculatePlaneRipple(currentplane->viewangle + currentplane->plangle); + + ds_xfrac += planeripple.xfrac; + ds_yfrac += planeripple.yfrac; + ds_bgofs >>= FRACBITS; if ((y + ds_bgofs) >= viewheight) ds_bgofs = viewheight-y-1; @@ -238,16 +208,11 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) ds_bgofs = -y; } - if (currentplane->slope) - ds_colormap = colormaps; - else - { - pindex = distance >> LIGHTZSHIFT; - if (pindex >= MAXLIGHTZ) - pindex = MAXLIGHTZ - 1; - ds_colormap = planezlight[pindex]; - } + pindex = distance >> LIGHTZSHIFT; + if (pindex >= MAXLIGHTZ) + pindex = MAXLIGHTZ - 1; + ds_colormap = planezlight[pindex]; if (currentplane->extra_colormap) ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps); @@ -255,19 +220,46 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) ds_x1 = x1; ds_x2 = x2; - // profile drawer -#ifdef TIMING - ProfZeroTimer(); + spanfunc(); +} + +static void R_MapTiltedPlane(INT32 y, INT32 x1, INT32 x2) +{ +#ifdef RANGECHECK + if (x2 < x1 || x1 < 0 || x2 >= viewwidth || y > viewheight) + I_Error("R_MapTiltedPlane: %d, %d at %d", x1, x2, y); #endif + if (x1 >= vid.width) + x1 = vid.width - 1; + + // Water ripple effect + if (planeripple.active) + { + ds_bgofs = R_CalculateRippleOffset(y); + + ds_sup = &ds_su[y]; + ds_svp = &ds_sv[y]; + ds_szp = &ds_sz[y]; + + ds_bgofs >>= FRACBITS; + + if ((y + ds_bgofs) >= viewheight) + ds_bgofs = viewheight-y-1; + if ((y + ds_bgofs) < 0) + ds_bgofs = -y; + } + + if (currentplane->extra_colormap) + ds_colormap = currentplane->extra_colormap->colormap; + else + ds_colormap = colormaps; + + ds_y = y; + ds_x1 = x1; + ds_x2 = x2; + spanfunc(); - -#ifdef TIMING - RDMSR(0x10, &mycount); - mytotal += mycount; // 64bit add - if (!(nombre--)) - I_Error("spanfunc() CPU Spy reports: 0x%d %d\n", *((INT32 *)&mytotal+1), (INT32)mytotal); -#endif } void R_ClearFFloorClips (void) @@ -294,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++) @@ -320,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) @@ -334,7 +318,7 @@ static visplane_t *new_visplane(unsigned hash) visplane_t *check = freetail; if (!check) { - check = calloc(2, sizeof (*check)); + check = malloc(sizeof (*check)); if (check == NULL) I_Error("%s: Out of memory", "new_visplane"); // FIXME: ugly } else @@ -367,11 +351,11 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, if (plangle != 0) { // Add the view offset, rotated by the plane angle. - fixed_t cosinecomponent = FINECOSINE(plangle>>ANGLETOFINESHIFT); - fixed_t sinecomponent = FINESINE(plangle>>ANGLETOFINESHIFT); - fixed_t oldxoff = xoff; - xoff = FixedMul(xoff,cosinecomponent)+FixedMul(yoff,sinecomponent); - yoff = -FixedMul(oldxoff,sinecomponent)+FixedMul(yoff,cosinecomponent); + float ang = ANG2RAD(plangle); + float x = FixedToFloat(xoff); + float y = FixedToFloat(yoff); + xoff = FloatToFixed(x * cos(ang) + y * sin(ang)); + yoff = FloatToFixed(-x * sin(ang) + y * cos(ang)); } } @@ -379,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 { @@ -529,58 +515,24 @@ 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; -*/ - } -// -// R_MakeSpans -// -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_RenderFloorSplat + // 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; @@ -589,12 +541,12 @@ 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); + mapfunc(b1, spanstart[b1], x - 1); b1--; } @@ -666,69 +618,109 @@ static void R_DrawSkyPlane(visplane_t *pl) } } -// Potentially override other stuff for now cus we're mean. :< But draw a slope plane! -// I copied ZDoom's code and adapted it to SRB2... -Red -void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge) +// Returns the height of the sloped plane at (x, y) as a 32.16 fixed_t +static INT64 R_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y) { - floatv3_t p, m, n; - float ang; - float vx, vy, vz; - float xscale = FIXED_TO_FLOAT(planexscale); - float yscale = FIXED_TO_FLOAT(planeyscale); - // compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly - // use this as a temp var to store P_GetSlopeZAt's return value each time - fixed_t temp; + INT64 x64 = ((INT64)x - (INT64)slope->o.x); + INT64 y64 = ((INT64)y - (INT64)slope->o.y); - vx = FIXED_TO_FLOAT(planeviewx+planexoffset); - vy = FIXED_TO_FLOAT(planeviewy-planeyoffset); - vz = FIXED_TO_FLOAT(planeviewz); + x64 = (x64 * (INT64)slope->d.x) / FRACUNIT; + y64 = (y64 * (INT64)slope->d.y) / FRACUNIT; - temp = P_GetSlopeZAt(slope, planeviewx, planeviewy); - zeroheight = FIXED_TO_FLOAT(temp); + return (INT64)slope->o.z + ((x64 + y64) * (INT64)slope->zdelta) / FRACUNIT; +} + +// Sets the texture origin vector of the sloped plane. +static void R_SetSlopePlaneOrigin(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, fixed_t angle) +{ + floatv3_t *p = &ds_slope_origin; + + INT64 vx = (INT64)xpos + (INT64)xoff; + INT64 vy = (INT64)ypos - (INT64)yoff; + + float vxf = vx / (float)FRACUNIT; + float vyf = vy / (float)FRACUNIT; + float ang = ANG2RAD(ANGLE_270 - angle); // p is the texture origin in view space // Don't add in the offsets at this stage, because doing so can result in // errors if the flat is rotated. - ang = ANG2RAD(ANGLE_270 - planeviewangle); - p.x = vx * cos(ang) - vy * sin(ang); - p.z = vx * sin(ang) + vy * cos(ang); - temp = P_GetSlopeZAt(slope, -planexoffset, planeyoffset); - p.y = FIXED_TO_FLOAT(temp) - vz; + p->x = vxf * cos(ang) - vyf * sin(ang); + p->z = vxf * sin(ang) + vyf * cos(ang); + p->y = (R_GetSlopeZAt(slope, -xoff, yoff) - zpos) / (float)FRACUNIT; +} + +// This function calculates all of the vectors necessary for drawing a sloped plane. +void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle) +{ + // Potentially override other stuff for now cus we're mean. :< But draw a slope plane! + // I copied ZDoom's code and adapted it to SRB2... -Red + floatv3_t *m = &ds_slope_v, *n = &ds_slope_u; + fixed_t height, temp; + float ang; + + R_SetSlopePlaneOrigin(slope, xpos, ypos, zpos, xoff, yoff, angle); + height = P_GetSlopeZAt(slope, xpos, ypos); + zeroheight = FixedToFloat(height - zpos); // m is the v direction vector in view space - ang = ANG2RAD(ANGLE_180 - (planeviewangle + planeangle)); - m.x = yscale * cos(ang); - m.z = yscale * sin(ang); + ang = ANG2RAD(ANGLE_180 - (angle + plangle)); + m->x = cos(ang); + m->z = sin(ang); // n is the u direction vector in view space - n.x = xscale * sin(ang); - n.z = -xscale * cos(ang); + n->x = sin(ang); + n->z = -cos(ang); - ang = ANG2RAD(planeangle); - temp = P_GetSlopeZAt(slope, planeviewx + yscale * FLOAT_TO_FIXED(sin(ang)), planeviewy + yscale * FLOAT_TO_FIXED(cos(ang))); - m.y = FIXED_TO_FLOAT(temp) - zeroheight; - temp = P_GetSlopeZAt(slope, planeviewx + xscale * FLOAT_TO_FIXED(cos(ang)), planeviewy - xscale * FLOAT_TO_FIXED(sin(ang))); - n.y = FIXED_TO_FLOAT(temp) - zeroheight; + plangle >>= ANGLETOFINESHIFT; + temp = P_GetSlopeZAt(slope, xpos + FINESINE(plangle), ypos + FINECOSINE(plangle)); + m->y = FixedToFloat(temp - height); + temp = P_GetSlopeZAt(slope, xpos + FINECOSINE(plangle), ypos - FINESINE(plangle)); + n->y = FixedToFloat(temp - height); +} - if (ds_powersoftwo) - { - m.x /= fudge; - m.y /= fudge; - m.z /= fudge; +// This function calculates all of the vectors necessary for drawing a sloped and scaled plane. +void R_SetScaledSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xs, fixed_t ys, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle) +{ + floatv3_t *m = &ds_slope_v, *n = &ds_slope_u; + fixed_t height, temp; - n.x *= fudge; - n.y *= fudge; - n.z *= fudge; - } + float xscale = FixedToFloat(xs); + float yscale = FixedToFloat(ys); + float ang; + + R_SetSlopePlaneOrigin(slope, xpos, ypos, zpos, xoff, yoff, angle); + height = P_GetSlopeZAt(slope, xpos, ypos); + zeroheight = FixedToFloat(height - zpos); + + // m is the v direction vector in view space + ang = ANG2RAD(ANGLE_180 - (angle + plangle)); + m->x = yscale * cos(ang); + m->z = yscale * sin(ang); + + // n is the u direction vector in view space + n->x = xscale * sin(ang); + n->z = -xscale * cos(ang); + + ang = ANG2RAD(plangle); + temp = P_GetSlopeZAt(slope, xpos + FloatToFixed(yscale * sin(ang)), ypos + FloatToFixed(yscale * cos(ang))); + m->y = FixedToFloat(temp - height); + temp = P_GetSlopeZAt(slope, xpos + FloatToFixed(xscale * cos(ang)), ypos - FloatToFixed(xscale * sin(ang))); + n->y = FixedToFloat(temp - height); +} + +void R_CalculateSlopeVectors(void) +{ + float sfmult = 65536.f; // Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using. #define CROSS(d, v1, v2) \ d->x = (v1.y * v2.z) - (v1.z * v2.y);\ d->y = (v1.z * v2.x) - (v1.x * v2.z);\ d->z = (v1.x * v2.y) - (v1.y * v2.x) - CROSS(ds_sup, p, m); - CROSS(ds_svp, p, n); - CROSS(ds_szp, m, n); + CROSS(ds_sup, ds_slope_origin, ds_slope_v); + CROSS(ds_svp, ds_slope_origin, ds_slope_u); + CROSS(ds_szp, ds_slope_v, ds_slope_u); #undef CROSS ds_sup->z *= focallengthf; @@ -736,27 +728,15 @@ d->z = (v1.x * v2.y) - (v1.y * v2.x) ds_szp->z *= focallengthf; // Premultiply the texture vectors with the scale factors -#define SFMULT 65536.f if (ds_powersoftwo) - { - ds_sup->x *= (SFMULT * (1<y *= (SFMULT * (1<z *= (SFMULT * (1<x *= (SFMULT * (1<y *= (SFMULT * (1<z *= (SFMULT * (1<x *= SFMULT; - ds_sup->y *= SFMULT; - ds_sup->z *= SFMULT; - ds_svp->x *= SFMULT; - ds_svp->y *= SFMULT; - ds_svp->z *= SFMULT; - } -#undef SFMULT + sfmult *= (1 << nflatshiftup); + + ds_sup->x *= sfmult; + ds_sup->y *= sfmult; + ds_sup->z *= sfmult; + ds_svp->x *= sfmult; + ds_svp->y *= sfmult; + ds_svp->z *= sfmult; } void R_SetTiltedSpan(INT32 span) @@ -773,22 +753,50 @@ void R_SetTiltedSpan(INT32 span) ds_szp = &ds_sz[span]; } -static void R_SetSlopePlaneVectors(visplane_t *pl, INT32 y, fixed_t xoff, fixed_t yoff, float fudge) +static void R_SetSlopePlaneVectors(visplane_t *pl, INT32 y, fixed_t xoff, fixed_t yoff) { R_SetTiltedSpan(y); - R_CalculateSlopeVectors(pl->slope, pl->viewx, pl->viewy, pl->viewz, FRACUNIT, FRACUNIT, xoff, yoff, pl->viewangle, pl->plangle, fudge); + R_SetSlopePlane(pl->slope, pl->viewx, pl->viewy, pl->viewz, xoff, yoff, pl->viewangle, pl->plangle); + R_CalculateSlopeVectors(); +} + +static inline void R_AdjustSlopeCoordinates(vector3_t *origin) +{ + const fixed_t modmask = ((1 << (32-nflatshiftup)) - 1); + + fixed_t ox = (origin->x & modmask); + fixed_t oy = -(origin->y & modmask); + + xoffs &= modmask; + yoffs &= modmask; + + xoffs -= (origin->x - ox); + yoffs += (origin->y + oy); +} + +static inline void R_AdjustSlopeCoordinatesNPO2(vector3_t *origin) +{ + const fixed_t modmaskw = (ds_flatwidth << FRACBITS); + const fixed_t modmaskh = (ds_flatheight << FRACBITS); + + fixed_t ox = (origin->x % modmaskw); + fixed_t oy = -(origin->y % modmaskh); + + xoffs %= modmaskw; + yoffs %= modmaskh; + + xoffs -= (origin->x - ox); + yoffs += (origin->y + oy); } void R_DrawSinglePlane(visplane_t *pl) { levelflat_t *levelflat; INT32 light = 0; - INT32 x; - INT32 stop, angle; + INT32 x, stop; ffloor_t *rover; - int type; - int spanfunctype = BASEDRAWFUNC; - angle_t viewang = viewangle; + INT32 type, spanfunctype = BASEDRAWFUNC; + void (*mapfunc)(INT32, INT32, INT32) = R_MapPlane; if (!(pl->minx <= pl->maxx)) return; @@ -844,31 +852,19 @@ void R_DrawSinglePlane(visplane_t *pl) if (pl->ffloor->flags & FF_TRANSLUCENT) { - spanfunctype = (pl->ffloor->master->flags & ML_EFFECT6) ? SPANDRAWFUNC_TRANSSPLAT : SPANDRAWFUNC_TRANS; + spanfunctype = (pl->ffloor->flags & FF_SPLAT) ? SPANDRAWFUNC_TRANSSPLAT : SPANDRAWFUNC_TRANS; // Hacked up support for alpha value in software mode Tails 09-24-2002 - if (pl->ffloor->alpha < 12) - return; // Don't even draw it - else if (pl->ffloor->alpha < 38) - ds_transmap = R_GetTranslucencyTable(tr_trans90); - else if (pl->ffloor->alpha < 64) - ds_transmap = R_GetTranslucencyTable(tr_trans80); - else if (pl->ffloor->alpha < 89) - ds_transmap = R_GetTranslucencyTable(tr_trans70); - else if (pl->ffloor->alpha < 115) - ds_transmap = R_GetTranslucencyTable(tr_trans60); - else if (pl->ffloor->alpha < 140) - ds_transmap = R_GetTranslucencyTable(tr_trans50); - else if (pl->ffloor->alpha < 166) - ds_transmap = R_GetTranslucencyTable(tr_trans40); - else if (pl->ffloor->alpha < 192) - ds_transmap = R_GetTranslucencyTable(tr_trans30); - else if (pl->ffloor->alpha < 217) - ds_transmap = R_GetTranslucencyTable(tr_trans20); - else if (pl->ffloor->alpha < 243) - ds_transmap = R_GetTranslucencyTable(tr_trans10); - else // Opaque, but allow transparent flat pixels - spanfunctype = SPANDRAWFUNC_SPLAT; + // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 + { + INT32 trans = (10*((256+12) - pl->ffloor->alpha))/255; + if (trans >= 10) + return; // Don't even draw it + if (pl->ffloor->blend) // additive, (reverse) subtractive, modulative + ds_transmap = R_GetBlendTable(pl->ffloor->blend, trans); + else if (!(ds_transmap = R_GetTranslucencyTable(trans)) || trans == 0) + spanfunctype = SPANDRAWFUNC_SPLAT; // Opaque, but allow transparent flat pixels + } if ((spanfunctype == SPANDRAWFUNC_SPLAT) || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG))) light = (pl->lightlevel >> LIGHTSEGSHIFT); @@ -940,15 +936,11 @@ 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; } xoffs = pl->xoffs; yoffs = pl->yoffs; - planeheight = abs(pl->height - pl->viewz); if (light >= LIGHTLEVELS) light = LIGHTLEVELS-1; @@ -958,76 +950,31 @@ void R_DrawSinglePlane(visplane_t *pl) if (pl->slope) { - float fudgecanyon = 0; - angle_t hack = (pl->plangle & (ANGLE_90-1)); + mapfunc = R_MapTiltedPlane; - yoffs *= 1; - - if (ds_powersoftwo) + if (!pl->plangle) { - fixed_t temp; - // Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -Red - fudgecanyon = ((1<>ANGLETOFINESHIFT); - const fixed_t sinecomponent = FINESINE(hack>>ANGLETOFINESHIFT); - - const fixed_t modmask = ((1 << (32-nflatshiftup)) - 1); - - fixed_t ox = (FixedMul(pl->slope->o.x,cosinecomponent) & modmask) - (FixedMul(pl->slope->o.y,sinecomponent) & modmask); - fixed_t oy = (-FixedMul(pl->slope->o.x,sinecomponent) & modmask) - (FixedMul(pl->slope->o.y,cosinecomponent) & modmask); - - temp = ox & modmask; - oy &= modmask; - ox = FixedMul(temp,cosinecomponent)+FixedMul(oy,-sinecomponent); // negative sine for opposite direction - oy = -FixedMul(temp,-sinecomponent)+FixedMul(oy,cosinecomponent); - - temp = xoffs; - xoffs = (FixedMul(temp,cosinecomponent) & modmask) + (FixedMul(yoffs,sinecomponent) & modmask); - yoffs = (-FixedMul(temp,sinecomponent) & modmask) + (FixedMul(yoffs,cosinecomponent) & modmask); - - temp = xoffs & modmask; - yoffs &= modmask; - xoffs = FixedMul(temp,cosinecomponent)+FixedMul(yoffs,-sinecomponent); // ditto - yoffs = -FixedMul(temp,-sinecomponent)+FixedMul(yoffs,cosinecomponent); - - xoffs -= (pl->slope->o.x - ox); - yoffs += (pl->slope->o.y + oy); - } + if (ds_powersoftwo) + R_AdjustSlopeCoordinates(&pl->slope->o); else - { - xoffs &= ((1 << (32-nflatshiftup))-1); - yoffs &= ((1 << (32-nflatshiftup))-1); - xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); - yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); - } - - xoffs = (fixed_t)(xoffs*fudgecanyon); - yoffs = (fixed_t)(yoffs/fudgecanyon); + R_AdjustSlopeCoordinatesNPO2(&pl->slope->o); } if (planeripple.active) { - fixed_t plheight = abs(P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); + planeheight = abs(P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); R_PlaneBounds(pl); for (x = pl->high; x < pl->low; x++) { - R_CalculatePlaneRipple(pl, x, plheight, true); - R_SetSlopePlaneVectors(pl, x, (xoffs + planeripple.xfrac), (yoffs + planeripple.yfrac), fudgecanyon); + ds_bgofs = R_CalculateRippleOffset(x); + R_CalculatePlaneRipple(pl->viewangle + pl->plangle); + R_SetSlopePlaneVectors(pl, x, (xoffs + planeripple.xfrac), (yoffs + planeripple.yfrac)); } } else - R_SetSlopePlaneVectors(pl, 0, xoffs, yoffs, fudgecanyon); + R_SetSlopePlaneVectors(pl, 0, xoffs, yoffs); switch (spanfunctype) { @@ -1048,7 +995,10 @@ void R_DrawSinglePlane(visplane_t *pl) planezlight = scalelight[light]; } else + { + planeheight = abs(pl->height - pl->viewz); planezlight = zlight[light]; + } // Use the correct span drawer depending on the powers-of-twoness if (!ds_powersoftwo) @@ -1069,19 +1019,8 @@ void R_DrawSinglePlane(visplane_t *pl) stop = pl->maxx + 1; - if (viewx != pl->viewx || viewy != pl->viewy) - { - viewx = pl->viewx; - viewy = pl->viewy; - } - if (viewz != pl->viewz) - viewz = pl->viewz; - for (x = pl->minx; x <= stop; x++) - { - R_MakeSpans(x, pl->top[x-1], pl->bottom[x-1], - pl->top[x], pl->bottom[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) @@ -1148,13 +1087,11 @@ 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]); } } #endif - - viewangle = viewang; } void R_PlaneBounds(visplane_t *plane) diff --git a/src/r_plane.h b/src/r_plane.h index 0d11c5b72..09648fead 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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; @@ -78,8 +77,6 @@ void R_InitPlanes(void); void R_ClearPlanes(void); void R_ClearFFloorClips (void); -void R_MapPlane(INT32 y, INT32 x1, INT32 x2); -void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2); void R_DrawPlanes(void); visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap, ffloor_t *ffloor, polyobj_t *polyobj, pslope_t *slope); @@ -94,7 +91,9 @@ boolean R_CheckPowersOfTwo(void); void R_DrawSinglePlane(visplane_t *pl); // Calculates the slope vectors needed for tilted span drawing. -void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge); +void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle); +void R_SetScaledSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xs, fixed_t ys, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle); +void R_CalculateSlopeVectors(void); // Sets the slope vector pointers for the current tilted span. void R_SetTiltedSpan(INT32 span); diff --git a/src/r_portal.c b/src/r_portal.c index 1aca145ec..4d4132133 100644 --- a/src/r_portal.c +++ b/src/r_portal.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -132,6 +132,7 @@ static portal_t* Portal_Add (const INT16 x1, const INT16 x2) void Portal_Remove (portal_t* portal) { + portalcullsector = NULL; portal_base = portal->next; Z_Free(portal->ceilingclip); Z_Free(portal->floorclip); diff --git a/src/r_portal.h b/src/r_portal.h index e665a26e6..687ee058f 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_segs.c b/src/r_segs.c index c79071e9b..c9f5f0d7b 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -155,18 +155,25 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (!ldef->alpha) return; - if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) - { - dc_transmap = R_GetTranslucencyTable(R_GetLinedefTransTable(ldef->alpha)); - colfunc = colfuncs[COLDRAWFUNC_FUZZY]; - - } - else if (ldef->special == 909) + if (ldef->blendmode == AST_FOG) { colfunc = colfuncs[COLDRAWFUNC_FOG]; windowtop = frontsector->ceilingheight; windowbottom = frontsector->floorheight; } + else if (ldef->blendmode) + { + if (ldef->alpha == NUMTRANSMAPS || ldef->blendmode == AST_MODULATE) + dc_transmap = R_GetBlendTable(ldef->blendmode, 0); + else + dc_transmap = R_GetBlendTable(ldef->blendmode, R_GetLinedefTransTable(ldef->alpha)); + colfunc = colfuncs[COLDRAWFUNC_FUZZY]; + } + else if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) + { + dc_transmap = R_GetTranslucencyTable(R_GetLinedefTransTable(ldef->alpha)); + colfunc = colfuncs[COLDRAWFUNC_FUZZY]; + } else colfunc = colfuncs[BASEDRAWFUNC]; @@ -294,7 +301,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (ds->curline->sidedef->repeatcnt) repeats = 1 + ds->curline->sidedef->repeatcnt; - else if (ldef->flags & ML_EFFECT5) + else if (ldef->flags & ML_WRAPMIDTEX) { fixed_t high, low; @@ -338,7 +345,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { dc_texturemid = ds->maskedtextureheight[dc_x]; - if (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3)) + if (curline->linedef->flags & ML_MIDPEG) dc_texturemid += (textureheight[texnum])*times + textureheight[texnum]; else dc_texturemid -= (textureheight[texnum])*times; @@ -600,28 +607,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) boolean fuzzy = true; // Hacked up support for alpha value in software mode Tails 09-24-2002 - if (pfloor->alpha < 12) - return; // Don't even draw it - else if (pfloor->alpha < 38) - dc_transmap = R_GetTranslucencyTable(tr_trans90); - else if (pfloor->alpha < 64) - dc_transmap = R_GetTranslucencyTable(tr_trans80); - else if (pfloor->alpha < 89) - dc_transmap = R_GetTranslucencyTable(tr_trans70); - else if (pfloor->alpha < 115) - dc_transmap = R_GetTranslucencyTable(tr_trans60); - else if (pfloor->alpha < 140) - dc_transmap = R_GetTranslucencyTable(tr_trans50); - else if (pfloor->alpha < 166) - dc_transmap = R_GetTranslucencyTable(tr_trans40); - else if (pfloor->alpha < 192) - dc_transmap = R_GetTranslucencyTable(tr_trans30); - else if (pfloor->alpha < 217) - dc_transmap = R_GetTranslucencyTable(tr_trans20); - else if (pfloor->alpha < 243) - dc_transmap = R_GetTranslucencyTable(tr_trans10); - else - fuzzy = false; // Opaque + // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 + { + INT32 trans = (10*((256+12) - pfloor->alpha))/255; + if (trans >= 10) + return; // Don't even draw it + if (pfloor->blend) // additive, (reverse) subtractive, modulative + dc_transmap = R_GetBlendTable(pfloor->blend, trans); + else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0) + fuzzy = false; // Opaque + } if (fuzzy) colfunc = colfuncs[COLDRAWFUNC_FUZZY]; @@ -770,10 +765,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) skewslope = *pfloor->t_slope; // skew using top slope by default if (newline) { - if (newline->flags & ML_DONTPEGTOP) + if (newline->flags & ML_SKEWTD) slopeskew = true; } - else if (pfloor->master->flags & ML_DONTPEGTOP) + else if (pfloor->master->flags & ML_SKEWTD) slopeskew = true; if (slopeskew) @@ -1460,9 +1455,9 @@ static void R_RenderSegLoop (void) maskedtexturecol[rw_x] = (INT16)texturecolumn; if (maskedtextureheight != NULL) { - maskedtextureheight[rw_x] = (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3) ? + maskedtextureheight[rw_x] = (curline->linedef->flags & ML_MIDPEG) ? max(rw_midtexturemid, rw_midtextureback) : - min(rw_midtexturemid, rw_midtextureback)); + min(rw_midtexturemid, rw_midtextureback); } } @@ -1477,10 +1472,18 @@ static void R_RenderSegLoop (void) } for (i = 0; i < numffloors; i++) + { + if (curline->polyseg && (ffloor[i].polyobj != curline->polyseg)) + continue; + ffloor[i].f_frac += ffloor[i].f_step; + } for (i = 0; i < numbackffloors; i++) { + if (curline->polyseg && (ffloor[i].polyobj != curline->polyseg)) + continue; + ffloor[i].f_clip[rw_x] = ffloor[i].c_clip[rw_x] = (INT16)((ffloor[i].b_frac >> HEIGHTBITS) & 0xFFFF); ffloor[i].b_frac += ffloor[i].b_step; } @@ -1649,23 +1652,26 @@ void R_StoreWallRange(INT32 start, INT32 stop) // left temp = xtoviewangle[start]+viewangle; +#define FIXED_TO_DOUBLE(x) (((double)(x)) / ((double)FRACUNIT)) +#define DOUBLE_TO_FIXED(x) (fixed_t)((x) * ((double)FRACUNIT)) + { // Both lines can be written in slope-intercept form, so figure out line intersection - float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... - ///TODO: convert to FPU + double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... + ///TODO: convert to fixed point - a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y); - b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x); - c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y); + a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y); + b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x); + c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y); - a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT)); - b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT)); - c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy); + a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT)); + b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT)); + c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy); det = a1*b2 - a2*b1; - ds_p->leftpos.x = segleft.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det); - ds_p->leftpos.y = segleft.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det); + ds_p->leftpos.x = segleft.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det); + ds_p->leftpos.y = segleft.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det); } // right @@ -1673,22 +1679,26 @@ void R_StoreWallRange(INT32 start, INT32 stop) { // Both lines can be written in slope-intercept form, so figure out line intersection - float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... - ///TODO: convert to FPU + double a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector... + ///TODO: convert to fixed point - a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y); - b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x); - c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y); + a1 = FIXED_TO_DOUBLE(curline->v2->y-curline->v1->y); + b1 = FIXED_TO_DOUBLE(curline->v1->x-curline->v2->x); + c1 = a1*FIXED_TO_DOUBLE(curline->v1->x) + b1*FIXED_TO_DOUBLE(curline->v1->y); - a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT)); - b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT)); - c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy); + a2 = -FIXED_TO_DOUBLE(FINESINE(temp>>ANGLETOFINESHIFT)); + b2 = FIXED_TO_DOUBLE(FINECOSINE(temp>>ANGLETOFINESHIFT)); + c2 = a2*FIXED_TO_DOUBLE(viewx) + b2*FIXED_TO_DOUBLE(viewy); det = a1*b2 - a2*b1; - ds_p->rightpos.x = segright.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det); - ds_p->rightpos.y = segright.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det); + ds_p->rightpos.x = segright.x = DOUBLE_TO_FIXED((b2*c1 - b1*c2)/det); + ds_p->rightpos.y = segright.y = DOUBLE_TO_FIXED((a1*c2 - a2*c1)/det); } + +#undef FIXED_TO_DOUBLE +#undef DOUBLE_TO_FIXED + } @@ -1756,7 +1766,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) texheight = textureheight[midtexture]; // a single sided line is terminal, so it must mark ends markfloor = markceiling = true; - if (linedef->flags & ML_EFFECT2) { + if (linedef->flags & ML_NOSKEW) { if (linedef->flags & ML_DONTPEGBOTTOM) rw_midtexturemid = frontsector->floorheight + texheight - viewz; else @@ -1893,18 +1903,20 @@ void R_StoreWallRange(INT32 start, INT32 stop) else if (worldlow != worldbottom || worldlowslope != worldbottomslope || backsector->f_slope != frontsector->f_slope - || backsector->floorpic != frontsector->floorpic - || backsector->lightlevel != frontsector->lightlevel - //SoM: 3/22/2000: Check floor x and y offsets. - || backsector->floor_xoffs != frontsector->floor_xoffs - || backsector->floor_yoffs != frontsector->floor_yoffs - || backsector->floorpic_angle != frontsector->floorpic_angle - //SoM: 3/22/2000: Prevents bleeding. - || (frontsector->heightsec != -1 && frontsector->floorpic != skyflatnum) - || backsector->floorlightsec != frontsector->floorlightsec - //SoM: 4/3/2000: Check for colormaps - || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) + || backsector->floorpic != frontsector->floorpic + || backsector->lightlevel != frontsector->lightlevel + //SoM: 3/22/2000: Check floor x and y offsets. + || backsector->floor_xoffs != frontsector->floor_xoffs + || backsector->floor_yoffs != frontsector->floor_yoffs + || backsector->floorpic_angle != frontsector->floorpic_angle + //SoM: 3/22/2000: Prevents bleeding. + || (frontsector->heightsec != -1 && frontsector->floorpic != skyflatnum) + || backsector->floorlightlevel != frontsector->floorlightlevel + || backsector->floorlightabsolute != frontsector->floorlightabsolute + || backsector->floorlightsec != frontsector->floorlightsec + //SoM: 4/3/2000: Check for colormaps + || frontsector->extra_colormap != backsector->extra_colormap + || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markfloor = true; } @@ -1924,18 +1936,20 @@ void R_StoreWallRange(INT32 start, INT32 stop) else if (worldhigh != worldtop || worldhighslope != worldtopslope || backsector->c_slope != frontsector->c_slope - || backsector->ceilingpic != frontsector->ceilingpic - || backsector->lightlevel != frontsector->lightlevel - //SoM: 3/22/2000: Check floor x and y offsets. - || backsector->ceiling_xoffs != frontsector->ceiling_xoffs - || backsector->ceiling_yoffs != frontsector->ceiling_yoffs - || backsector->ceilingpic_angle != frontsector->ceilingpic_angle - //SoM: 3/22/2000: Prevents bleeding. - || (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum) - || backsector->ceilinglightsec != frontsector->ceilinglightsec - //SoM: 4/3/2000: Check for colormaps - || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) + || backsector->ceilingpic != frontsector->ceilingpic + || backsector->lightlevel != frontsector->lightlevel + //SoM: 3/22/2000: Check floor x and y offsets. + || backsector->ceiling_xoffs != frontsector->ceiling_xoffs + || backsector->ceiling_yoffs != frontsector->ceiling_yoffs + || backsector->ceilingpic_angle != frontsector->ceilingpic_angle + //SoM: 3/22/2000: Prevents bleeding. + || (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum) + || backsector->ceilinglightlevel != frontsector->ceilinglightlevel + || backsector->ceilinglightabsolute != frontsector->ceilinglightabsolute + || backsector->ceilinglightsec != frontsector->ceilinglightsec + //SoM: 4/3/2000: Check for colormaps + || frontsector->extra_colormap != backsector->extra_colormap + || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markceiling = true; } @@ -1961,23 +1975,10 @@ void R_StoreWallRange(INT32 start, INT32 stop) { fixed_t texheight; // top texture - if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM)) - && linedef->sidenum[1] != 0xffff) - { - // Special case... use offsets from 2nd side but only if it has a texture. - side_t *def = &sides[linedef->sidenum[1]]; - toptexture = R_GetTextureNum(def->toptexture); + toptexture = R_GetTextureNum(sidedef->toptexture); + texheight = textureheight[toptexture]; - if (!toptexture) //Second side has no texture, use the first side's instead. - toptexture = R_GetTextureNum(sidedef->toptexture); - texheight = textureheight[toptexture]; - } - else - { - toptexture = R_GetTextureNum(sidedef->toptexture); - texheight = textureheight[toptexture]; - } - if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked + if (!(linedef->flags & ML_SKEWTD)) { // Ignore slopes for lower/upper textures unless flag is checked if (linedef->flags & ML_DONTPEGTOP) rw_toptexturemid = frontsector->ceilingheight - viewz; else @@ -2002,7 +2003,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) // bottom texture bottomtexture = R_GetTextureNum(sidedef->bottomtexture); - if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked + if (!(linedef->flags & ML_SKEWTD)) { // Ignore slopes for lower/upper textures unless flag is checked if (linedef->flags & ML_DONTPEGBOTTOM) rw_bottomtexturemid = frontsector->floorheight - viewz; else @@ -2233,7 +2234,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (curline->polyseg) { // use REAL front and back floors please, so midtexture rendering isn't mucked up rw_midtextureslide = rw_midtexturebackslide = 0; - if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + if (linedef->flags & ML_MIDPEG) rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz; else rw_midtexturemid = rw_midtextureback = min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz; @@ -2241,16 +2242,16 @@ void R_StoreWallRange(INT32 start, INT32 stop) else { // Set midtexture starting height - if (linedef->flags & ML_EFFECT2) + if (linedef->flags & ML_NOSKEW) { // Ignore slopes when texturing rw_midtextureslide = rw_midtexturebackslide = 0; - if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + if (linedef->flags & ML_MIDPEG) rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz; else rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz; } - else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) + else if (linedef->flags & ML_MIDPEG) { rw_midtexturemid = worldbottom; rw_midtextureslide = floorfrontslide; diff --git a/src/r_segs.h b/src/r_segs.h index ace5711d4..4075cc0bb 100644 --- a/src/r_segs.h +++ b/src/r_segs.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_skins.c b/src/r_skins.c index 522d9236a..cd53128d2 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -148,8 +148,6 @@ static void Sk_SetDefaultValue(skin_t *skin) skin->contspeed = 17; skin->contangle = 0; - skin->availability = 0; - for (i = 0; i < sfx_skinsoundslot0; i++) if (S_sfx[i].skinsound != -1) skin->soundsid[S_sfx[i].skinsound] = i; @@ -176,14 +174,34 @@ void R_InitSkins(void) UINT32 R_GetSkinAvailabilities(void) { - INT32 s; UINT32 response = 0; + UINT32 unlockShift = 0; + INT32 i; - for (s = 0; s < MAXSKINS; s++) + for (i = 0; i < MAXUNLOCKABLES; i++) { - if (skins[s].availability && unlockables[skins[s].availability - 1].unlocked) - response |= (1 << s); + if (unlockables[i].type != SECRET_SKIN) + { + continue; + } + + if (unlockShift >= 32) + { + // This crash is impossible to trigger as is, + // but it could happen if MAXUNLOCKABLES is ever made higher than 32, + // and someone makes a mod that has 33+ unlockable characters. :V + I_Error("Too many unlockable characters\n"); + return 0; + } + + if (unlockables[i].unlocked) + { + response |= (1 << unlockShift); + } + + unlockShift++; } + return response; } @@ -191,14 +209,83 @@ UINT32 R_GetSkinAvailabilities(void) // warning don't use with an invalid skinnum other than -1 which always returns true boolean R_SkinUsable(INT32 playernum, INT32 skinnum) { - return ((skinnum == -1) // Simplifies things elsewhere, since there's already plenty of checks for less-than-0... - || (!skins[skinnum].availability) - || (((netgame || multiplayer) && playernum != -1) ? (players[playernum].availabilities & (1 << skinnum)) : (unlockables[skins[skinnum].availability - 1].unlocked)) - || (modeattacking) // If you have someone else's run you might as well take a look - || (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) // Force 1. - || (netgame && (cv_forceskin.value == skinnum)) // Force 2. - || (metalrecording && skinnum == 5) // Force 3. - ); + INT32 unlockID = -1; + UINT32 unlockShift = 0; + INT32 i; + + if (skinnum == -1) + { + // Simplifies things elsewhere, since there's already plenty of checks for less-than-0... + return true; + } + + if (modeattacking) + { + // If you have someone else's run you might as well take a look + return true; + } + + if (Playing() && (R_SkinAvailable(mapheaderinfo[gamemap-1]->forcecharacter) == skinnum)) + { + // Force 1. + return true; + } + + if (netgame && (cv_forceskin.value == skinnum)) + { + // Force 2. + return true; + } + + if (metalrecording && skinnum == 5) + { + // 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. + + for (i = 0; i < MAXUNLOCKABLES; i++) + { + INT32 unlockSkin = -1; + + if (unlockables[i].type != SECRET_SKIN) + { + continue; + } + + unlockSkin = M_UnlockableSkinNum(&unlockables[i]); + + if (unlockSkin == skinnum) + { + unlockID = i; + break; + } + + unlockShift++; + } + + if (unlockID == -1) + { + // This skin isn't locked at all, we're good. + return true; + } + + if ((netgame || multiplayer) && playernum != -1) + { + // We want to check per-player unlockables. + return (players[playernum].availabilities & (1 << unlockShift)); + } + else + { + // We want to check our global unlockables. + return (unlockables[unlockID].unlocked); + } } // returns true if the skin name is found (loaded from pwad) @@ -216,6 +303,103 @@ INT32 R_SkinAvailable(const char *name) return -1; } +// Auxillary function that actually sets the skin +static void SetSkin(player_t *player, INT32 skinnum) +{ + skin_t *skin = &skins[skinnum]; + UINT16 newcolor = 0; + + player->skin = skinnum; + + player->camerascale = skin->camerascale; + player->shieldscale = skin->shieldscale; + + player->charability = (UINT8)skin->ability; + player->charability2 = (UINT8)skin->ability2; + + player->charflags = (UINT32)skin->flags; + + player->thokitem = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; + player->spinitem = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; + player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; + player->followitem = skin->followitem; + + if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff. + player->powers[pw_shield] &= SH_STACK; + + player->actionspd = skin->actionspd; + player->mindash = skin->mindash; + player->maxdash = skin->maxdash; + + player->normalspeed = skin->normalspeed; + player->runspeed = skin->runspeed; + player->thrustfactor = skin->thrustfactor; + player->accelstart = skin->accelstart; + player->acceleration = skin->acceleration; + + player->jumpfactor = skin->jumpfactor; + + player->height = skin->height; + player->spinheight = skin->spinheight; + + if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) + { + if (player == &players[consoleplayer]) + CV_StealthSetValue(&cv_playercolor, skin->prefcolor); + else if (player == &players[secondarydisplayplayer]) + CV_StealthSetValue(&cv_playercolor2, skin->prefcolor); + player->skincolor = newcolor = skin->prefcolor; + if (player->bot && botingame) + { + botskin = (UINT8)(skinnum + 1); + botcolor = skin->prefcolor; + } + } + + if (player->followmobj) + { + P_RemoveMobj(player->followmobj); + P_SetTarget(&player->followmobj, NULL); + } + + if (player->mo) + { + fixed_t radius = FixedMul(skin->radius, player->mo->scale); + if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin. + { + skin = &skins[DEFAULTNIGHTSSKIN]; + player->followitem = skin->followitem; + if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) + newcolor = skin->prefcolor; // will be updated in thinker to flashing + } + player->mo->skin = skin; + if (newcolor) + player->mo->color = newcolor; + P_SetScale(player->mo, player->mo->scale); + player->mo->radius = radius; + + P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames + } +} + +// Gets the player to the first usuable skin in the game. +// (If your mod locked them all, then you kinda stupid) +INT32 GetPlayerDefaultSkin(INT32 playernum) +{ + INT32 i; + + for (i = 0; i < numskins; i++) + { + if (R_SkinUsable(playernum, i)) + { + return i; + } + } + + I_Error("All characters are locked!"); + return 0; +} + // network code calls this when a 'skin change' is received void SetPlayerSkin(INT32 playernum, const char *skinname) { @@ -224,16 +408,16 @@ void SetPlayerSkin(INT32 playernum, const char *skinname) if ((i != -1) && R_SkinUsable(playernum, i)) { - SetPlayerSkinByNum(playernum, i); + SetSkin(player, i); return; } if (P_IsLocalPlayer(player)) CONS_Alert(CONS_WARNING, M_GetText("Skin '%s' not found.\n"), skinname); - else if(server || IsPlayerAdmin(consoleplayer)) + else if (server || IsPlayerAdmin(consoleplayer)) CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) skin '%s' not found\n"), playernum, player_names[playernum], skinname); - SetPlayerSkinByNum(playernum, 0); + SetSkin(player, GetPlayerDefaultSkin(playernum)); } // Same as SetPlayerSkin, but uses the skin #. @@ -241,90 +425,19 @@ void SetPlayerSkin(INT32 playernum, const char *skinname) void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) { player_t *player = &players[playernum]; - skin_t *skin = &skins[skinnum]; - UINT16 newcolor = 0; if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists! { - player->skin = skinnum; - - player->camerascale = skin->camerascale; - player->shieldscale = skin->shieldscale; - - player->charability = (UINT8)skin->ability; - player->charability2 = (UINT8)skin->ability2; - - player->charflags = (UINT32)skin->flags; - - player->thokitem = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem; - player->spinitem = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem; - player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem; - player->followitem = skin->followitem; - - if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff. - player->powers[pw_shield] &= SH_STACK; - - player->actionspd = skin->actionspd; - player->mindash = skin->mindash; - player->maxdash = skin->maxdash; - - player->normalspeed = skin->normalspeed; - player->runspeed = skin->runspeed; - player->thrustfactor = skin->thrustfactor; - player->accelstart = skin->accelstart; - player->acceleration = skin->acceleration; - - player->jumpfactor = skin->jumpfactor; - - player->height = skin->height; - player->spinheight = skin->spinheight; - - if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) - { - if (playernum == consoleplayer) - CV_StealthSetValue(&cv_playercolor, skin->prefcolor); - else if (playernum == secondarydisplayplayer) - CV_StealthSetValue(&cv_playercolor2, skin->prefcolor); - player->skincolor = newcolor = skin->prefcolor; - if (player->bot && botingame) - { - botskin = (UINT8)(skinnum + 1); - botcolor = skin->prefcolor; - } - } - - if (player->followmobj) - { - P_RemoveMobj(player->followmobj); - P_SetTarget(&player->followmobj, NULL); - } - - if (player->mo) - { - fixed_t radius = FixedMul(skin->radius, player->mo->scale); - if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin. - { - skin = &skins[DEFAULTNIGHTSSKIN]; - player->followitem = skin->followitem; - if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback)) - newcolor = skin->prefcolor; // will be updated in thinker to flashing - } - player->mo->skin = skin; - if (newcolor) - player->mo->color = newcolor; - P_SetScale(player->mo, player->mo->scale); - player->mo->radius = radius; - - P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames - } + SetSkin(player, skinnum); return; } if (P_IsLocalPlayer(player)) CONS_Alert(CONS_WARNING, M_GetText("Requested skin %d not found\n"), skinnum); - else if(server || IsPlayerAdmin(consoleplayer)) + else if (server || IsPlayerAdmin(consoleplayer)) CONS_Alert(CONS_WARNING, "Player %d (%s) skin %d not found\n", playernum, player_names[playernum], skinnum); - SetPlayerSkinByNum(playernum, 0); // not found put the sonic skin + + SetSkin(player, GetPlayerDefaultSkin(playernum)); } // @@ -514,6 +627,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) GETFLAG(NOSUPERSPRITES) GETFLAG(NOSUPERJUMPBOOST) GETFLAG(CANBUSTWALLS) + GETFLAG(NOSHIELDABILITY) #undef GETFLAG else // let's check if it's a sound, otherwise error out @@ -557,7 +671,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) // // Find skin sprites, sounds & optional status bar face, & add them // -void R_AddSkins(UINT16 wadnum) +void R_AddSkins(UINT16 wadnum, boolean mainfile) { UINT16 lump, lastlump = 0; char *buf; @@ -672,12 +786,6 @@ void R_AddSkins(UINT16 wadnum) if (!realname) STRBUFCPY(skin->realname, skin->hudname); } - else if (!stricmp(stoken, "availability")) - { - skin->availability = atoi(value); - if (skin->availability >= MAXUNLOCKABLES) - skin->availability = 0; - } else if (!R_ProcessPatchableFields(skin, stoken, value)) CONS_Debug(DBG_SETUP, "R_AddSkins: Unknown keyword '%s' in S_SKIN lump #%d (WAD %s)\n", stoken, lump, wadfiles[wadnum]->filename); @@ -692,7 +800,7 @@ next_token: R_FlushTranslationColormapCache(); - if (!skin->availability) // Safe to print... + if (mainfile == false) CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); #ifdef SKINVALUES skin_cons_t[numskins].value = numskins; @@ -712,7 +820,7 @@ next_token: // // Patch skin sprites // -void R_PatchSkins(UINT16 wadnum) +void R_PatchSkins(UINT16 wadnum, boolean mainfile) { UINT16 lump, lastlump = 0; char *buf; @@ -825,7 +933,7 @@ next_token: R_FlushTranslationColormapCache(); - if (!skin->availability) // Safe to print... + if (mainfile == false) CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name); } return; diff --git a/src/r_skins.h b/src/r_skins.h index fbbb38743..aeaa9f3e0 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -80,8 +80,6 @@ typedef struct // contains super versions too spritedef_t sprites[NUMPLAYERSPRITES*2]; spriteinfo_t sprinfo[NUMPLAYERSPRITES*2]; - - UINT8 availability; // lock? } skin_t; /// Externs @@ -91,13 +89,14 @@ extern skin_t skins[MAXSKINS]; /// Function prototypes void R_InitSkins(void); +INT32 GetPlayerDefaultSkin(INT32 playernum); void SetPlayerSkin(INT32 playernum,const char *skinname); void SetPlayerSkinByNum(INT32 playernum,INT32 skinnum); // Tails 03-16-2002 boolean R_SkinUsable(INT32 playernum, INT32 skinnum); UINT32 R_GetSkinAvailabilities(void); INT32 R_SkinAvailable(const char *name); -void R_PatchSkins(UINT16 wadnum); -void R_AddSkins(UINT16 wadnum); +void R_AddSkins(UINT16 wadnum, boolean mainfile); +void R_PatchSkins(UINT16 wadnum, boolean mainfile); UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player); diff --git a/src/r_sky.c b/src/r_sky.c index 7cdcfa44d..e21b7cbf1 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_sky.h b/src/r_sky.h index 55d866b86..31c821d22 100644 --- a/src/r_sky.h +++ b/src/r_sky.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_splats.c b/src/r_splats.c index a3fad82d8..0a84a3a33 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -28,11 +28,12 @@ static void prepare_rastertab(void); // FLOOR SPLATS // ========================================================================== +static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis); + #ifdef USEASM void ASMCALL rasterize_segment_tex_asm(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir); #endif -// Lactozilla static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir) { #ifdef USEASM @@ -137,7 +138,7 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 } } -void R_DrawFloorSprite(vissprite_t *spr) +void R_DrawFloorSplat(vissprite_t *spr) { floorsplat_t splat; mobj_t *mobj = spr->mobj; @@ -154,7 +155,6 @@ void R_DrawFloorSprite(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); @@ -187,7 +187,7 @@ void R_DrawFloorSprite(vissprite_t *spr) if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) splatangle = mobj->angle; else - splatangle = viewangle; + splatangle = spr->viewpoint.angle; if (!(spr->cut & SC_ISROTATED)) splatangle += mobj->rollangle; @@ -217,7 +217,7 @@ void R_DrawFloorSprite(vissprite_t *spr) splat.x = x; splat.y = y; splat.z = mobj->z; - splat.tilted = false; + splat.slope = NULL; // Set positions @@ -237,9 +237,9 @@ void R_DrawFloorSprite(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++) @@ -254,37 +254,10 @@ void R_DrawFloorSprite(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) - { - // Lactozilla: Just copy the entire slope LMFAOOOO - 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_DrawFloorSprite(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_DrawFloorSprite(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; @@ -330,7 +308,7 @@ void R_DrawFloorSprite(vissprite_t *spr) v2d[i].y = (centeryfrac + FixedMul(rot_z, yscale))>>FRACBITS; } - R_RenderFloorSplat(&splat, v2d, spr); + R_RasterizeFloorSplat(&splat, v2d, spr); } // -------------------------------------------------------------------------- @@ -338,7 +316,7 @@ void R_DrawFloorSprite(vissprite_t *spr) // fill the polygon with linear interpolation, call span drawer for each // scan line // -------------------------------------------------------------------------- -void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis) +static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis) { // rasterizing INT32 miny = viewheight + 1, maxy = 0; @@ -416,31 +394,32 @@ void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis if (R_CheckPowersOfTwo()) R_CheckFlatLength(ds_flatwidth * ds_flatheight); - // Lactozilla: I don't know what I'm doing - if (pSplat->tilted) + if (pSplat->slope) { R_SetTiltedSpan(0); - R_CalculateSlopeVectors(&pSplat->slope, viewx, viewy, viewz, pSplat->xscale, pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, viewangle, pSplat->angle, 1.0f); + 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 @@ void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis { ds_transmap = vis->transmap; - if (pSplat->tilted) + if (pSplat->slope) spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPRITE; else spanfunctype = SPANDRAWFUNC_TRANSSPRITE; @@ -503,7 +482,7 @@ void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis continue; for (i = x1; i <= x2; i++) - cliptab[i] = (y >= mfloorclip[i]); + cliptab[i] = (y >= mfloorclip[i] || y <= mceilingclip[i]); // clip left while (cliptab[x1]) @@ -528,12 +507,12 @@ void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis if (x2 < x1) continue; - if (!pSplat->tilted) + if (!pSplat->slope) { fixed_t xstep, ystep; fixed_t distance, span; - angle_t angle = (viewangle + pSplat->angle)>>ANGLETOFINESHIFT; + angle_t angle = (vis->viewpoint.angle + pSplat->angle)>>ANGLETOFINESHIFT; angle_t planecos = FINECOSINE(angle); angle_t planesin = FINESINE(angle); @@ -543,17 +522,13 @@ void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); span = abs(centery - y); - if (span) // don't divide by zero + if (span) // Don't divide by zero { xstep = FixedMul(planesin, planeheight) / span; ystep = FixedMul(planecos, planeheight) / span; } else - { - // ah - xstep = FRACUNIT; - ystep = FRACUNIT; - } + xstep = ystep = FRACUNIT; cachedxstep[y] = xstep; cachedystep[y] = ystep; @@ -581,7 +556,7 @@ void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis 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 e1f836f48..ec6885e26 100644 --- a/src/r_splats.h +++ b/src/r_splats.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -34,15 +34,13 @@ 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 mobj_t *mobj; // Mobj it is tied to } floorsplat_t; -void R_DrawFloorSprite(vissprite_t *spr); -void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis); +void R_DrawFloorSplat(vissprite_t *spr); #endif /*__R_SPLATS_H__*/ diff --git a/src/r_state.h b/src/r_state.h index 25aa69702..69989e7ac 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/r_textures.c b/src/r_textures.c index 9de9649e2..03f8f53a5 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -28,11 +28,6 @@ #include "byteptr.h" #include "dehacked.h" -// I don't know what this is even for, but r_data.c had it. -#ifdef _WIN32 -#include // alloca(sizeof) -#endif - #ifdef HWRENDER #include "hardware/hw_glob.h" // HWR_LoadMapTextures #endif @@ -64,6 +59,7 @@ INT32 *texturetranslation; // Painfully simple texture id cacheing to make maps load faster. :3 static struct { char name[9]; + UINT32 hash; INT32 id; } *tidcache = NULL; static INT32 tidcachelen = 0; @@ -604,7 +600,7 @@ void *R_GetLevelFlat(levelflat_t *levelflat) levelflat->height = ds_flatheight = SHORT(patch->height); levelflat->picture = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); - converted = Picture_FlatConvert(PICFMT_DOOMPATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); + converted = Picture_FlatConvert(PICFMT_DOOMPATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, SHORT(patch->topoffset), SHORT(patch->leftoffset), 0); M_Memcpy(levelflat->picture, converted, size); Z_Free(converted); } @@ -626,7 +622,7 @@ void *R_GetLevelFlat(levelflat_t *levelflat) // // R_CheckPowersOfTwo // -// Self-explanatory? +// Sets ds_powersoftwo true if the flat's dimensions are powers of two, and returns that. // boolean R_CheckPowersOfTwo(void) { @@ -730,9 +726,10 @@ Rloadflats (INT32 i, INT32 w) UINT16 texstart, texend; texture_t *texture; texpatch_t *patch; + UINT8 header[PNG_HEADER_SIZE]; // 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); @@ -748,19 +745,18 @@ Rloadflats (INT32 i, INT32 w) // Work through each lump between the markers in the WAD. for (j = 0; j < (texend - texstart); j++) { - UINT8 *flatlump; UINT16 wadnum = (UINT16)w; lumpnum_t lumpnum = texstart + j; 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 } - flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0); lumplength = W_LumpLengthPwad(wadnum, lumpnum); switch (lumplength) @@ -793,14 +789,17 @@ Rloadflats (INT32 i, INT32 w) // Set texture properties. M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); + texture->hash = quickncasehash(texture->name, 8); #ifndef NO_PNG_LUMPS - if (Picture_IsLumpPNG((UINT8 *)flatlump, lumplength)) + if (Picture_IsLumpPNG(header, lumplength)) { + UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); INT32 width, height; Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, NULL, NULL, lumplength); texture->width = (INT16)width; texture->height = (INT16)height; + Z_Free(flatlump); } else #endif @@ -819,8 +818,6 @@ Rloadflats (INT32 i, INT32 w) patch->lump = texstart + j; patch->flip = 0; - Z_Unlock(flatlump); - texturewidth[i] = texture->width; textureheight[i] = texture->height << FRACBITS; i++; @@ -840,11 +837,11 @@ Rloadtextures (INT32 i, INT32 w) UINT16 j; UINT16 texstart, texend, texturesLumpPos; texture_t *texture; - softwarepatch_t *patchlump; texpatch_t *patch; + softwarepatch_t patchlump; // 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); @@ -875,13 +872,13 @@ 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 } - patchlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + W_ReadLumpHeaderPwad(wadnum, lumpnum, &patchlump, PNG_HEADER_SIZE, 0); #ifndef NO_PNG_LUMPS lumplength = W_LumpLengthPwad(wadnum, lumpnum); #endif @@ -891,20 +888,23 @@ Rloadtextures (INT32 i, INT32 w) // Set texture properties. M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); + texture->hash = quickncasehash(texture->name, 8); #ifndef NO_PNG_LUMPS - if (Picture_IsLumpPNG((UINT8 *)patchlump, lumplength)) + if (Picture_IsLumpPNG((UINT8 *)&patchlump, lumplength)) { + UINT8 *png = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); INT32 width, height; - Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, NULL, NULL, lumplength); + Picture_PNGDimensions(png, &width, &height, NULL, NULL, lumplength); texture->width = (INT16)width; texture->height = (INT16)height; + Z_Free(png); } else #endif { - texture->width = SHORT(patchlump->width); - texture->height = SHORT(patchlump->height); + texture->width = SHORT(patchlump.width); + texture->height = SHORT(patchlump.height); } texture->type = TEXTURETYPE_SINGLEPATCH; @@ -920,8 +920,6 @@ Rloadtextures (INT32 i, INT32 w) patch->lump = texstart + j; patch->flip = 0; - Z_Unlock(patchlump); - texturewidth[i] = texture->width; textureheight[i] = texture->height << FRACBITS; i++; @@ -931,27 +929,53 @@ Rloadtextures (INT32 i, INT32 w) return i; } -// -// R_LoadTextures -// Initializes the texture list with the textures from the world map. -// -void R_LoadTextures(void) +static INT32 +count_range +( const char * marker_start, + const char * marker_end, + const char * folder, + UINT16 wadnum) { - INT32 i, w; UINT16 j; - UINT16 texstart, texend, texturesLumpPos; + UINT16 texstart, texend; + INT32 count = 0; - // Free previous memory before numtextures change. - if (numtextures) + // Count flats + if (W_FileHasFolders(wadfiles[wadnum])) { - for (i = 0; i < numtextures; i++) - { - Z_Free(textures[i]); - Z_Free(texturecache[i]); - } - Z_Free(texturetranslation); - Z_Free(textures); + texstart = W_CheckNumForFolderStartPK3(folder, wadnum, 0); + texend = W_CheckNumForFolderEndPK3(folder, wadnum, texstart); } + else + { + texstart = W_CheckNumForMarkerStartPwad(marker_start, wadnum, 0); + texend = W_CheckNumForNamePwad(marker_end, wadnum, texstart); + } + + if (texstart != INT16_MAX && texend != INT16_MAX) + { + // PK3s have subfolders, so we can't just make a simple sum + if (W_FileHasFolders(wadfiles[wadnum])) + { + for (j = texstart; j < texend; j++) + { + if (!W_IsLumpFolder(wadnum, j)) // Check if lump is a folder; if not, then count it + count++; + } + } + else // Add all the textures between markers + { + count += (texend - texstart); + } + } + + return count; +} + +static INT32 R_CountTextures(UINT16 wadnum) +{ + UINT16 texturesLumpPos; + INT32 count = 0; // Load patches and textures. @@ -960,113 +984,132 @@ void R_LoadTextures(void) // the markers. // This system will allocate memory for all duplicate/patched textures even if it never uses them, // but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures. - for (w = 0, numtextures = 0; w < numwadfiles; w++) - { + #ifdef WALLFLATS - // Count flats - if (wadfiles[w]->type == RET_PK3) - { - texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); - } - else - { - texstart = W_CheckNumForMarkerStartPwad("F_START", (UINT16)w, 0); - texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); - } + count += count_range("F_START", "F_END", "flats/", wadnum); +#endif - 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) - { - for (j = texstart; j < texend; j++) - { - if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it - numtextures++; - } - } - else // Add all the textures between F_START and F_END - { - numtextures += (UINT32)(texend - texstart); - } - } -#endif/*WALLFLATS*/ + // Count the textures from TEXTURES lumps + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", wadnum, 0); - // Count the textures from TEXTURES lumps - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - while (texturesLumpPos != INT16_MAX) - { - numtextures += R_CountTexturesInTEXTURESLump((UINT16)w, (UINT16)texturesLumpPos); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); - } - - // Count single-patch textures - if (wadfiles[w]->type == RET_PK3) - { - texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); - } - else - { - texstart = W_CheckNumForMarkerStartPwad(TX_START, (UINT16)w, 0); - texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); - } - - if (texstart == INT16_MAX || texend == INT16_MAX) - continue; - - // PK3s have subfolders, so we can't just make a simple sum - if (wadfiles[w]->type == RET_PK3) - { - for (j = texstart; j < texend; j++) - { - if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it - numtextures++; - } - } - else // Add all the textures between TX_START and TX_END - { - numtextures += (UINT32)(texend - texstart); - } + while (texturesLumpPos != INT16_MAX) + { + count += R_CountTexturesInTEXTURESLump(wadnum, texturesLumpPos); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", wadnum, texturesLumpPos + 1); } - // If no textures found by this point, bomb out - if (!numtextures) - I_Error("No textures detected in any WADs!\n"); + // Count single-patch textures + count += count_range(TX_START, TX_END, "textures/", wadnum); + + return count; +} + +static void +recallocuser +( void * user, + size_t old, + size_t new) +{ + char *p = Z_Realloc(*(void**)user, + new, PU_STATIC, user); + + if (new > old) + memset(&p[old], 0, (new - old)); +} + +static void R_AllocateTextures(INT32 add) +{ + const INT32 newtextures = (numtextures + add); + const size_t newsize = newtextures * sizeof (void*); + const size_t oldsize = numtextures * sizeof (void*); + + INT32 i; // Allocate memory and initialize to 0 for all the textures we are initialising. - // There are actually 5 buffers allocated in one for convenience. - textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); + recallocuser(&textures, oldsize, newsize); // Allocate texture column offset table. - texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *))); + recallocuser(&texturecolumnofs, oldsize, newsize); // Allocate texture referencing cache. - texturecache = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 2)); + recallocuser(&texturecache, oldsize, newsize); // Allocate texture width table. - texturewidth = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 3)); + recallocuser(&texturewidth, oldsize, newsize); // Allocate texture height table. - textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4)); + recallocuser(&textureheight, oldsize, newsize); // Create translation table for global animation. - texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, NULL); + Z_Realloc(texturetranslation, (newtextures + 1) * sizeof(*texturetranslation), PU_STATIC, &texturetranslation); - for (i = 0; i < numtextures; i++) - texturetranslation[i] = i; - - for (i = 0, w = 0; w < numwadfiles; w++) + for (i = 0; i < numtextures; ++i) { -#ifdef WALLFLATS - i = Rloadflats(i, w); -#endif - i = Rloadtextures(i, w); + // R_FlushTextureCache relies on the user for + // Z_Free, texturecache has been reallocated so the + // user is now garbage memory. + Z_SetUser(texturecache[i], + (void**)&texturecache[i]); } + while (i < newtextures) + { + texturetranslation[i] = i; + i++; + } +} + +static INT32 R_DefineTextures(INT32 i, UINT16 w) +{ +#ifdef WALLFLATS + i = Rloadflats(i, w); +#endif + return Rloadtextures(i, w); +} + +static void R_FinishLoadingTextures(INT32 add) +{ + numtextures += add; + #ifdef HWRENDER if (rendermode == render_opengl) HWR_LoadMapTextures(numtextures); #endif } +// +// R_LoadTextures +// Initializes the texture list with the textures from the world map. +// +void R_LoadTextures(void) +{ + INT32 i, w; + INT32 newtextures = 0; + + for (w = 0; w < numwadfiles; w++) + { + newtextures += R_CountTextures((UINT16)w); + } + + // If no textures found by this point, bomb out + if (!newtextures) + I_Error("No textures detected in any WADs!\n"); + + R_AllocateTextures(newtextures); + + for (i = 0, w = 0; w < numwadfiles; w++) + { + i = R_DefineTextures(i, w); + } + + R_FinishLoadingTextures(newtextures); +} + +void R_LoadTexturesPwad(UINT16 wadnum) +{ + INT32 newtextures = R_CountTextures(wadnum); + + R_AllocateTextures(newtextures); + R_DefineTextures(numtextures, wadnum); + R_FinishLoadingTextures(newtextures); +} + static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) { char *texturesToken; @@ -1373,6 +1416,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture) // Allocate memory for a zero-patch texture. Obviously, we'll be adding patches momentarily. resultTexture = (texture_t *)Z_Calloc(sizeof(texture_t),PU_STATIC,NULL); M_Memcpy(resultTexture->name, newTextureName, 8); + resultTexture->hash = quickncasehash(newTextureName, 8); resultTexture->width = newTextureWidth; resultTexture->height = newTextureHeight; resultTexture->type = TEXTURETYPE_COMPOSITE; @@ -1558,6 +1602,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) @@ -1598,19 +1643,22 @@ void R_ClearTextureNumCache(boolean btell) INT32 R_CheckTextureNumForName(const char *name) { INT32 i; + UINT32 hash; // "NoTexture" marker. if (name[0] == '-') return 0; + hash = quickncasehash(name, 8); + for (i = 0; i < tidcachelen; i++) - if (!strncasecmp(tidcache[i].name, name, 8)) + if (tidcache[i].hash == hash && !strncasecmp(tidcache[i].name, name, 8)) return tidcache[i].id; // Need to parse the list backwards, so textures loaded more recently are used in lieu of ones loaded earlier //for (i = 0; i < numtextures; i++) <- old for (i = (numtextures - 1); i >= 0; i--) // <- new - if (!strncasecmp(textures[i]->name, name, 8)) + if (textures[i]->hash == hash && !strncasecmp(textures[i]->name, name, 8)) { tidcachelen++; Z_Realloc(tidcache, tidcachelen * sizeof(*tidcache), PU_STATIC, &tidcache); @@ -1619,6 +1667,7 @@ INT32 R_CheckTextureNumForName(const char *name) #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "texture #%s: %s\n", sizeu1(tidcachelen), tidcache[tidcachelen-1].name); #endif + tidcache[tidcachelen-1].hash = hash; tidcache[tidcachelen-1].id = i; return i; } diff --git a/src/r_textures.h b/src/r_textures.h index 74a94a9ed..9aa11ad4d 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -54,6 +54,7 @@ typedef struct { // Keep name for switch changing, etc. char name[8]; + UINT32 hash; UINT8 type; // TEXTURETYPE_ INT16 width, height; boolean holes; @@ -76,6 +77,7 @@ extern UINT8 **texturecache; // graphics data for each generated full-size textu // Load TEXTURES definitions, create lookup tables void R_LoadTextures(void); +void R_LoadTexturesPwad(UINT16 wadnum); void R_FlushTextureCache(void); // Texture generation diff --git a/src/r_things.c b/src/r_things.c index 083373927..db4263a6a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -230,7 +230,7 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 UINT8 rotation; lumpinfo_t *lumpinfo; softwarepatch_t patch; - UINT8 numadded = 0; + UINT16 numadded = 0; memset(sprtemp,0xFF, sizeof (sprtemp)); maxframe = (size_t)-1; @@ -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; @@ -547,8 +548,8 @@ void R_InitSprites(void) R_InitSkins(); for (i = 0; i < numwadfiles; i++) { - R_AddSkins((UINT16)i); - R_PatchSkins((UINT16)i); + R_AddSkins((UINT16)i, true); + R_PatchSkins((UINT16)i, true); R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps); } ST_ReloadSkinFaceGraphics(); @@ -753,7 +754,7 @@ UINT8 *R_GetSpriteTranslation(vissprite_t *vis) else if (vis->mobj->type == MT_METALSONIC_BATTLE) return R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); else - return R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); + return R_GetTranslationColormap(TC_BOSS, vis->mobj->color, GTC_CACHE); } else if (vis->mobj->color) { @@ -796,7 +797,7 @@ static void R_DrawVisSprite(vissprite_t *vis) INT32 pwidth; fixed_t frac; patch_t *patch = vis->patch; - fixed_t this_scale = vis->mobj->scale; + fixed_t this_scale = vis->thingscale; INT32 x1, x2; INT64 overflow_test; @@ -836,6 +837,12 @@ static void R_DrawVisSprite(vissprite_t *vis) else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. colfunc = colfuncs[COLDRAWFUNC_TRANS]; + // Hack: Use a special column function for drop shadows that bypasses + // invalid memory access crashes caused by R_ProjectDropShadow putting wrong values + // in dc_texturemid and dc_iscale when the shadow is sloped. + if (vis->cut & SC_SHADOW) + colfunc = R_DrawDropShadowColumn_8; + if (vis->extra_colormap && !(vis->renderflags & RF_NOCOLORMAPS)) { if (!dc_colormap) @@ -1078,6 +1085,14 @@ static void R_SplitSprite(vissprite_t *sprite) sprite->sz = cutfrac; newsprite->szt = (INT16)(sprite->sz - 1); + if (testheight < sprite->pzt && testheight > sprite->pz) + sprite->pz = newsprite->pzt = testheight; + else + { + newsprite->pz = newsprite->gz; + newsprite->pzt = newsprite->gzt; + } + newsprite->szt -= 8; newsprite->cut |= SC_TOP; @@ -1101,6 +1116,10 @@ static void R_SplitSprite(vissprite_t *sprite) if (lindex >= MAXLIGHTSCALE) lindex = MAXLIGHTSCALE-1; + + if (newsprite->cut & SC_SEMIBRIGHT) + lindex = (MAXLIGHTSCALE/2) + (lindex >>1); + newsprite->colormap = spritelights[lindex]; } } @@ -1256,6 +1275,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, vissprite_t *shadow; patch_t *patch; fixed_t xscale, yscale, shadowxscale, shadowyscale, shadowskew, x1, x2; + INT32 heightsec, phs; INT32 light = 0; fixed_t scalemul; UINT8 trans; fixed_t floordiff; @@ -1267,6 +1287,24 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes + heightsec = thing->subsector->sector->heightsec; + if (viewplayer->mo && viewplayer->mo->subsector) + phs = viewplayer->mo->subsector->sector->heightsec; + else + phs = -1; + + if (heightsec != -1 && phs != -1) // only clip things which are in special sectors + { + if (viewz < sectors[phs].floorheight ? + groundz >= sectors[heightsec].floorheight : + groundz < sectors[heightsec].floorheight) + return; + if (viewz > sectors[phs].ceilingheight ? + groundz < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : + groundz >= sectors[heightsec].ceilingheight) + return; + } + floordiff = abs((isflipped ? thing->height : 0) + thing->z - groundz); trans = floordiff / (100*FRACUNIT) + 3; @@ -1300,12 +1338,16 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->patch = patch; shadow->heightsec = vis->heightsec; + shadow->thingheight = FRACUNIT; + shadow->pz = groundz + (isflipped ? -shadow->thingheight : 0); + shadow->pzt = shadow->pz + shadow->thingheight; + shadow->mobjflags = 0; shadow->sortscale = vis->sortscale; shadow->dispoffset = vis->dispoffset - 5; shadow->gx = thing->x; shadow->gy = thing->y; - shadow->gzt = groundz + patch->height * shadowyscale / 2; + shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + patch->height * shadowyscale / 2; shadow->gz = shadow->gzt - patch->height * shadowyscale; shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) @@ -1320,6 +1362,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000 shadow->scale = FixedMul(yscale, shadowyscale); + shadow->thingscale = thing->scale; shadow->sector = vis->sector; shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS); shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS); @@ -1411,7 +1454,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t sheartan = 0; fixed_t shadowscale = FRACUNIT; - fixed_t basetx; // drop shadows + fixed_t basetx, basetz; // drop shadows boolean shadowdraw, shadoweffects, shadowskew; boolean splat = R_ThingIsFloorSprite(thing); @@ -1441,7 +1484,7 @@ static void R_ProjectSprite(mobj_t *thing) tr_x = thing->x - viewx; tr_y = thing->y - viewy; - tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance + basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance // thing is behind view plane? if (!papersprite && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later @@ -1568,7 +1611,16 @@ static void R_ProjectSprite(mobj_t *thing) if (thing->rollangle && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { - rollangle = R_GetRollAngle(thing->rollangle); + if (papersprite && ang >= ANGLE_180) + { + // Makes Software act much more sane like OpenGL + rollangle = R_GetRollAngle(InvAngle(thing->rollangle)); + } + else + { + rollangle = R_GetRollAngle(thing->rollangle); + } + rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); if (rotsprite != NULL) @@ -1784,13 +1836,19 @@ static void R_ProjectSprite(mobj_t *thing) return; } + INT32 blendmode; + if (oldthing->frame & FF_BLENDMASK) + blendmode = ((oldthing->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; + else + blendmode = oldthing->blendmode; + // Determine the translucency value. if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) trans = tr_trans80; // because now the translucency is set through FF_TRANSMASK else if (oldthing->frame & FF_TRANSMASK) { trans = (oldthing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; - if (oldthing->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + if (!R_BlendLevelVisible(blendmode, trans)) return; } else @@ -1912,13 +1970,19 @@ static void R_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { + fixed_t top = gzt; + fixed_t bottom = thing->z; + + if (splat) + top = bottom; + if (viewz < sectors[phs].floorheight ? - thing->z >= sectors[heightsec].floorheight : - gzt < sectors[heightsec].floorheight) + bottom >= sectors[heightsec].floorheight : + top < sectors[heightsec].floorheight) return; if (viewz > sectors[phs].ceilingheight ? - gzt < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : - thing->z >= sectors[heightsec].ceilingheight) + top < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : + bottom >= sectors[heightsec].ceilingheight) return; } @@ -1935,6 +1999,9 @@ static void R_ProjectSprite(mobj_t *thing) vis->gy = thing->y; vis->gz = gz; vis->gzt = gzt; + vis->thingheight = thing->height; + vis->pz = thing->z; + vis->pzt = vis->pz + vis->thingheight; vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); vis->scalestep = scalestep; vis->paperoffset = paperoffset; @@ -1942,6 +2009,10 @@ static void R_ProjectSprite(mobj_t *thing) vis->centerangle = centerangle; 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 @@ -1960,6 +2031,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000 vis->scale = FixedMul(spriteyscale, yscale); //<thingscale = oldthing->scale; vis->spritexscale = spritexscale; vis->spriteyscale = spriteyscale; @@ -1994,13 +2066,15 @@ static void R_ProjectSprite(mobj_t *thing) vis->scale += FixedMul(scalestep, spriteyscale) * (vis->x1 - x1); } - if ((oldthing->blendmode != AST_COPY) && cv_translucency.value) - vis->transmap = R_GetBlendTable(oldthing->blendmode, trans); + if ((blendmode != AST_COPY) && cv_translucency.value) + vis->transmap = R_GetBlendTable(blendmode, trans); else vis->transmap = NULL; if (R_ThingIsFullBright(oldthing) || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) vis->cut |= SC_FULLBRIGHT; + else if (R_ThingIsSemiBright(oldthing)) + vis->cut |= SC_SEMIBRIGHT; else if (R_ThingIsFullDark(oldthing)) vis->cut |= SC_FULLDARK; @@ -2023,6 +2097,9 @@ static void R_ProjectSprite(mobj_t *thing) if (lindex >= MAXLIGHTSCALE) lindex = MAXLIGHTSCALE-1; + if (vis->cut & SC_SEMIBRIGHT) + lindex = (MAXLIGHTSCALE/2) + (lindex >> 1); + vis->colormap = spritelights[lindex]; } @@ -2037,7 +2114,7 @@ static void R_ProjectSprite(mobj_t *thing) R_SplitSprite(vis); if (oldthing->shadowscale && cv_shadow.value) - R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, tz); + R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz); // Debug ++objectsdrawn; @@ -2151,6 +2228,9 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->gy = thing->y; vis->gz = gz; vis->gzt = gzt; + vis->thingheight = 4*FRACUNIT; + vis->pz = thing->z; + vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; vis->paperdistance = 0; @@ -2179,7 +2259,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // specific translucency if (thing->frame & FF_TRANSMASK) - vis->transmap = (thing->frame & FF_TRANSMASK) - 0x10000 + transtables; + vis->transmap = R_GetTranslucencyTable((thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT); else vis->transmap = NULL; @@ -2544,15 +2624,19 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy, r2->plane->height); planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height); - // bird: if any part of the sprite peeks in front the plane - if (planecameraz < viewz) + if (rover->mobjflags & MF_NOCLIPHEIGHT) { - if (rover->gzt >= planeobjectz) + //Objects with NOCLIPHEIGHT can appear halfway in. + if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz) + continue; + if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz) continue; } - else if (planecameraz > viewz) + else { - if (rover->gz <= planeobjectz) + if (planecameraz < viewz && rover->pz >= planeobjectz) + continue; + if (planecameraz > viewz && rover->pzt <= planeobjectz) continue; } @@ -2585,7 +2669,7 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps } else if (r2->thickseg) { - //fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; + fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz; if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1) continue; @@ -2596,11 +2680,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if (scale <= rover->sortscale) continue; - // bird: Always sort sprites behind segs. This helps the plane - // sorting above too. Basically if the sprite gets sorted behind - // the seg here, it will be behind the plane too, since planes - // are added after segs in the list. -#if 0 topplaneobjectz = P_GetFFloorTopZAt (r2->ffloor, rover->gx, rover->gy); topplanecameraz = P_GetFFloorTopZAt (r2->ffloor, viewx, viewy); botplaneobjectz = P_GetFFloorBottomZAt(r2->ffloor, rover->gx, rover->gy); @@ -2609,7 +2688,6 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if ((topplanecameraz > viewz && botplanecameraz < viewz) || (topplanecameraz < viewz && rover->gzt < topplaneobjectz) || (botplanecameraz > viewz && rover->gz > botplaneobjectz)) -#endif { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2650,11 +2728,23 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps if (!behind) { - // FIXME: calculate gz and gzt for splats properly and use that - if (rover->mobj->z < viewz) - infront = (r2->sprite->mobj->z >= rover->mobj->z); + fixed_t z1 = 0, z2 = 0; + + if (rover->mobj->z - viewz > 0) + { + z1 = rover->pz; + z2 = r2->sprite->pz; + } else - infront = (r2->sprite->mobj->z <= rover->mobj->z); + { + z1 = r2->sprite->pz; + z2 = rover->pz; + } + + z1 -= viewz; + z2 -= viewz; + + infront = (z1 >= z2); } } else @@ -2710,7 +2800,7 @@ static drawnode_t *R_CreateDrawNode(drawnode_t *link) node->ffloor = NULL; node->sprite = NULL; - ps_numdrawnodes++; + ps_numdrawnodes.value.i++; return node; } @@ -2753,7 +2843,7 @@ static void R_DrawSprite(vissprite_t *spr) mceilingclip = spr->cliptop; if (spr->cut & SC_SPLAT) - R_DrawFloorSprite(spr); + R_DrawFloorSplat(spr); else R_DrawVisSprite(spr); } @@ -2766,6 +2856,57 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr) R_DrawPrecipitationVisSprite(spr); } +//SoM: 3/17/2000: Clip sprites in water. +static void R_HeightSecClip(vissprite_t *spr, INT32 x1, INT32 x2) +{ + fixed_t mh, h; + INT32 x, phs; + + if (spr->heightsec == -1) + return; + + if (spr->cut & (SC_SPLAT | SC_SHADOW) || spr->renderflags & RF_SHADOWDRAW) + return; + + phs = viewplayer->mo->subsector->sector->heightsec; + + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && + (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && + (h >>= FRACBITS) < viewheight) + { + if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) + { // clip bottom + for (x = x1; x <= x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; + } + else // clip top + { + for (x = x1; x <= x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; + } + } + + if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && + (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && + (h >>= FRACBITS) < viewheight) + { + if (phs != -1 && viewz >= sectors[phs].ceilingheight) + { // clip bottom + for (x = x1; x <= x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; + } + else // clip top + { + for (x = x1; x <= x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; + } + } +} + // R_ClipVisSprite // Clips vissprites without drawing, so that portals can work. -Red void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal) @@ -2867,47 +3008,9 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p } } } - //SoM: 3/17/2000: Clip sprites in water. - if (spr->heightsec != -1) // only things in specially marked sectors - { - fixed_t mh, h; - INT32 phs = viewplayer->mo->subsector->sector->heightsec; - if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && - (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && - (h >>= FRACBITS) < viewheight) - { - if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) - { // clip bottom - for (x = x1; x <= x2; x++) - if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) - spr->clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = x1; x <= x2; x++) - if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) - spr->cliptop[x] = (INT16)h; - } - } - if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && - (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && - (h >>= FRACBITS) < viewheight) - { - if (phs != -1 && viewz >= sectors[phs].ceilingheight) - { // clip bottom - for (x = x1; x <= x2; x++) - if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) - spr->clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = x1; x <= x2; x++) - if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) - spr->cliptop[x] = (INT16)h; - } - } - } + R_HeightSecClip(spr, x1, x2); + if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) { for (x = x1; x <= x2; x++) @@ -2951,13 +3054,25 @@ void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, p if (portal) { - for (x = x1; x <= x2; x++) + INT32 start_index = max(portal->start, x1); + INT32 end_index = min(portal->start + portal->end - portal->start, x2); + for (x = x1; x < start_index; x++) + { + spr->clipbot[x] = -1; + spr->cliptop[x] = -1; + } + for (x = start_index; x <= end_index; x++) { if (spr->clipbot[x] > portal->floorclip[x - portal->start]) spr->clipbot[x] = portal->floorclip[x - portal->start]; if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) spr->cliptop[x] = portal->ceilingclip[x - portal->start]; } + for (x = end_index + 1; x <= x2; x++) + { + spr->clipbot[x] = -1; + spr->cliptop[x] = -1; + } } } @@ -3038,17 +3153,22 @@ boolean R_ThingIsPaperSprite(mobj_t *thing) boolean R_ThingIsFloorSprite(mobj_t *thing) { - return (thing->flags2 & MF2_SPLAT || thing->renderflags & RF_FLOORSPRITE); + return (thing->flags2 & MF2_SPLAT || thing->frame & FF_FLOORSPRITE || thing->renderflags & RF_FLOORSPRITE); } boolean R_ThingIsFullBright(mobj_t *thing) { - return (thing->frame & FF_FULLBRIGHT || thing->renderflags & RF_FULLBRIGHT); + return ((thing->frame & FF_BRIGHTMASK) == FF_FULLBRIGHT || (thing->renderflags & RF_BRIGHTMASK) == RF_FULLBRIGHT); +} + +boolean R_ThingIsSemiBright(mobj_t *thing) +{ + return ((thing->frame & FF_BRIGHTMASK) == FF_SEMIBRIGHT || (thing->renderflags & RF_BRIGHTMASK) == RF_SEMIBRIGHT); } boolean R_ThingIsFullDark(mobj_t *thing) { - return (thing->renderflags & RF_FULLDARK); + return ((thing->frame & FF_BRIGHTMASK) == FF_FULLDARK || (thing->renderflags & RF_BRIGHTMASK) == RF_FULLDARK); } // @@ -3113,10 +3233,10 @@ static void R_DrawMaskedList (drawnode_t* head) } } -void R_DrawMasked(maskcount_t* masks, UINT8 nummasks) +void R_DrawMasked(maskcount_t* masks, INT32 nummasks) { drawnode_t *heads; /**< Drawnode lists; as many as number of views/portals. */ - SINT8 i; + INT32 i; heads = calloc(nummasks, sizeof(drawnode_t)); diff --git a/src/r_things.h b/src/r_things.h index d15ae818c..857b03b24 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -82,6 +82,7 @@ boolean R_ThingIsPaperSprite (mobj_t *thing); boolean R_ThingIsFloorSprite (mobj_t *thing); boolean R_ThingIsFullBright (mobj_t *thing); +boolean R_ThingIsSemiBright (mobj_t *thing); boolean R_ThingIsFullDark (mobj_t *thing); // -------------- @@ -99,7 +100,7 @@ typedef struct sector_t* viewsector; } maskcount_t; -void R_DrawMasked(maskcount_t* masks, UINT8 nummasks); +void R_DrawMasked(maskcount_t* masks, INT32 nummasks); // ---------- // VISSPRITES @@ -123,13 +124,14 @@ typedef enum SC_PRECIP = 1<<2, SC_LINKDRAW = 1<<3, SC_FULLBRIGHT = 1<<4, - SC_FULLDARK = 1<<5, - SC_VFLIP = 1<<6, - SC_ISSCALED = 1<<7, - SC_ISROTATED = 1<<8, - SC_SHADOW = 1<<9, - SC_SHEAR = 1<<10, - SC_SPLAT = 1<<11, + SC_SEMIBRIGHT = 1<<5, + SC_FULLDARK = 1<<6, + SC_VFLIP = 1<<7, + SC_ISSCALED = 1<<8, + SC_ISROTATED = 1<<9, + SC_SHADOW = 1<<10, + SC_SHEAR = 1<<11, + SC_SPLAT = 1<<12, // masks SC_CUTMASK = SC_TOP|SC_BOTTOM, SC_FLAGMASK = ~SC_CUTMASK @@ -151,10 +153,12 @@ typedef struct vissprite_s INT32 x1, x2; fixed_t gx, gy; // for line side calculation - fixed_t gz, gzt; // global bottom/top for silhouette clipping and sorting with 3D floors + fixed_t gz, gzt; // global bottom/top for silhouette clipping + fixed_t pz, pzt; // physical bottom/top for sorting with 3D floors fixed_t startfrac; // horizontal position of x1 - fixed_t scale; + fixed_t xscale, scale; // projected horizontal and vertical scales + fixed_t thingscale; // the object's scale fixed_t sortscale; // sortscale only differs from scale for paper sprites, floor sprites, and MF2_LINKDRAW fixed_t sortsplat; // the sortscale from behind the floor sprite fixed_t scalestep; // only for paper sprites, 0 otherwise @@ -163,6 +167,12 @@ typedef struct vissprite_s angle_t centerangle; // for paper sprites + // 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 INT32 offset; // The center of the shearing location offset from x1 @@ -182,10 +192,10 @@ typedef struct vissprite_s extracolormap_t *extra_colormap; // global colormaps - fixed_t xscale; + 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. - sector_t *sector; // The sector containing the thing. INT16 sz, szt; spritecut_e cut; diff --git a/src/s_sound.c b/src/s_sound.c index 392a5b453..7e61e8a55 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -74,9 +74,9 @@ consvar_t stereoreverse = CVAR_INIT ("stereoreverse", "Off", CV_SAVE, CV_OnOff, static consvar_t precachesound = CVAR_INIT ("precachesound", "Off", CV_SAVE, CV_OnOff, NULL); // actual general (maximum) sound & music volume, saved into the config -consvar_t cv_soundvolume = CVAR_INIT ("soundvolume", "18", CV_SAVE, soundvolume_cons_t, NULL); -consvar_t cv_digmusicvolume = CVAR_INIT ("digmusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL); -consvar_t cv_midimusicvolume = CVAR_INIT ("midimusicvolume", "18", CV_SAVE, soundvolume_cons_t, NULL); +consvar_t cv_soundvolume = CVAR_INIT ("soundvolume", "16", CV_SAVE, soundvolume_cons_t, NULL); +consvar_t cv_digmusicvolume = CVAR_INIT ("digmusicvolume", "16", CV_SAVE, soundvolume_cons_t, NULL); +consvar_t cv_midimusicvolume = CVAR_INIT ("midimusicvolume", "16", CV_SAVE, soundvolume_cons_t, NULL); static void Captioning_OnChange(void) { @@ -1033,11 +1033,9 @@ void S_SetSfxVolume(INT32 volume) void S_ClearSfx(void) { -#ifndef DJGPPDOS size_t i; for (i = 1; i < NUMSFX; i++) I_FreeSfx(S_sfx + i); -#endif } static void S_StopChannel(INT32 cnum) @@ -1354,28 +1352,6 @@ void S_InitSfxChannels(INT32 sfxVolume) /// Music /// ------------------------ -#ifdef MUSICSLOT_COMPATIBILITY -const char *compat_special_music_slots[16] = -{ - "_title", // 1036 title screen - "_intro", // 1037 intro - "_clear", // 1038 level clear - "_inv", // 1039 invincibility - "_shoes", // 1040 super sneakers - "_minv", // 1041 Mario invincibility - "_drown", // 1042 drowning - "_gover", // 1043 game over - "_1up", // 1044 extra life - "_conti", // 1045 continue screen - "_super", // 1046 Super Sonic - "_chsel", // 1047 character select - "_creds", // 1048 credits - "_inter", // 1049 Race Results - "_stjr", // 1050 Sonic Team Jr. Presents - "" -}; -#endif - static char music_name[7]; // up to 6-character name static void *music_data; static UINT16 music_flags; @@ -2262,6 +2238,16 @@ static void S_ChangeMusicToQueue(void) void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 position, UINT32 prefadems, UINT32 fadeinms) { char newmusic[7]; + + struct MusicChange hook_param = { + newmusic, + &mflags, + &looping, + &position, + &prefadems, + &fadeinms + }; + boolean currentmidi = (I_SongType() == MU_MID || I_SongType() == MU_MID_EX); boolean midipref = cv_musicpref.value; @@ -2269,7 +2255,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 return; strncpy(newmusic, mmusic, 7); - if (LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) + if (LUA_HookMusicChange(music_name, &hook_param)) return; newmusic[6] = 0; @@ -2465,7 +2451,7 @@ void S_StartEx(boolean reset) static void Command_Tunes_f(void) { const char *tunearg; - UINT16 tunenum, track = 0; + UINT16 track = 0; UINT32 position = 0; const size_t argc = COM_Argc(); @@ -2481,7 +2467,6 @@ static void Command_Tunes_f(void) } tunearg = COM_Argv(1); - tunenum = (UINT16)atoi(tunearg); track = 0; if (!strcasecmp(tunearg, "-show")) @@ -2500,24 +2485,14 @@ static void Command_Tunes_f(void) tunearg = mapheaderinfo[gamemap-1]->musname; track = mapheaderinfo[gamemap-1]->mustrack; } - else if (!tunearg[2] && toupper(tunearg[0]) >= 'A' && toupper(tunearg[0]) <= 'Z') - tunenum = (UINT16)M_MapNumber(tunearg[0], tunearg[1]); - if (tunenum && tunenum >= 1036) - { - CONS_Alert(CONS_NOTICE, M_GetText("Valid music slots are 1 to 1035.\n")); - return; - } - if (!tunenum && strlen(tunearg) > 6) // This is automatic -- just show the error just in case + if (strlen(tunearg) > 6) // This is automatic -- just show the error just in case CONS_Alert(CONS_NOTICE, M_GetText("Music name too long - truncated to six characters.\n")); if (argc > 2) track = (UINT16)atoi(COM_Argv(2))-1; - if (tunenum) - snprintf(mapmusname, 7, "%sM", G_BuildMapName(tunenum)); - else - strncpy(mapmusname, tunearg, 7); + strncpy(mapmusname, tunearg, 7); if (argc > 4) position = (UINT32)atoi(COM_Argv(4)); diff --git a/src/s_sound.h b/src/s_sound.h index 4ac3c70bf..6223c4fdb 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -265,6 +265,16 @@ boolean S_RecallMusic(UINT16 status, boolean fromfirst); // Music Playback // +/* this is for the sake of the hook */ +struct MusicChange { + char * newname; + UINT16 * mflags; + boolean * looping; + UINT32 * position; + UINT32 * prefadems; + UINT32 * fadeinms; +}; + // Start music track, arbitrary, given its name, and set whether looping // note: music flags 12 bits for tracknum (gme, other formats with more than one track) // 13-15 aren't used yet @@ -319,10 +329,4 @@ void S_StopSoundByNum(sfxenum_t sfxnum); #define S_StartScreamSound S_StartSound #endif -#ifdef MUSICSLOT_COMPATIBILITY -// For compatibility with code/scripts relying on older versions -// This is a list of all the "special" slot names and their associated numbers -extern const char *compat_special_music_slots[16]; -#endif - #endif diff --git a/src/screen.c b/src/screen.c index 9d36eee39..73af4313d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -33,6 +33,11 @@ #include "s_sound.h" // ditto #include "g_game.h" // ditto #include "p_local.h" // P_AutoPause() +#ifdef HWRENDER +#include "hardware/hw_main.h" +#include "hardware/hw_light.h" +#include "hardware/hw_model.h" +#endif #if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200)) @@ -217,7 +222,7 @@ void SCR_SetMode(void) // Set the video mode in the video interface. if (setmodeneeded) - VID_SetMode(--setmodeneeded); + VID_SetMode(setmodeneeded - 1); V_SetPalette(0); @@ -423,6 +428,10 @@ void SCR_ChangeRenderer(void) CONS_Alert(CONS_ERROR, "OpenGL never loaded\n"); return; } + + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) // Clear these out before switching to software + HWR_ClearAllTextures(); + #endif // Set the new render mode diff --git a/src/screen.h b/src/screen.h index e4944775d..376953169 100644 --- a/src/screen.h +++ b/src/screen.h @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index a7f015c86..d369d11c0 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -21,46 +21,25 @@ if(${SRB2_CONFIG_SDL2_USEMIXER}) endif() if(${SDL2_MIXER_FOUND}) set(SRB2_HAVE_MIXER ON) - set(SRB2_SDL2_SOUNDIMPL mixer_sound.c) + target_sources(SRB2SDL2 PRIVATE mixer_sound.c) else() message(WARNING "You specified that SDL2_mixer is available, but it was not found. Falling back to sdl sound.") - set(SRB2_SDL2_SOUNDIMPL sdl_sound.c) + target_sources(SRB2SDL2 PRIVATE sdl_sound.c) endif() elseif(${MIXERX_FOUND}) - set(SRB2_SDL2_SOUNDIMPL mixer_sound.c) + target_sources(SRB2SDL2 PRIVATE mixer_sound.c) else() - set(SRB2_SDL2_SOUNDIMPL sdl_sound.c) + target_sources(SRB2SDL2 PRIVATE sdl_sound.c) endif() -set(SRB2_SDL2_SOURCES - dosstr.c - endtxt.c - hwsym_sdl.c - i_main.c - i_net.c - i_system.c - i_ttf.c - i_video.c - #IMG_xpm.c - ogl_sdl.c +target_sourcefile(c) - ${SRB2_SDL2_SOUNDIMPL} -) - -set(SRB2_SDL2_HEADERS - endtxt.h - hwsym_sdl.h - i_ttf.h - ogl_sdl.h - sdlmain.h -) +target_sources(SRB2SDL2 PRIVATE ogl_sdl.c) if(${SRB2_CONFIG_HAVE_THREADS}) - set(SRB2_SDL2_SOURCES ${SRB2_SDL2_SOURCES} i_threads.c) + target_sources(SRB2SDL2 PRIVATE i_threads.c) endif() -source_group("Interface Code" FILES ${SRB2_SDL2_SOURCES} ${SRB2_SDL2_HEADERS}) - # Dependency if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES}) set(SDL2_FOUND ON) @@ -76,79 +55,29 @@ else() endif() if(${SDL2_FOUND}) - set(SRB2_SDL2_TOTAL_SOURCES - ${SRB2_CORE_SOURCES} - ${SRB2_CORE_HEADERS} - ${SRB2_PNG_SOURCES} - ${SRB2_PNG_HEADERS} - ${SRB2_CORE_RENDER_SOURCES} - ${SRB2_CORE_GAME_SOURCES} - ${SRB2_LUA_SOURCES} - ${SRB2_LUA_HEADERS} - ${SRB2_BLUA_SOURCES} - ${SRB2_BLUA_HEADERS} - ${SRB2_SDL2_SOURCES} - ${SRB2_SDL2_HEADERS} - ) - - source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS} - ${SRB2_PNG_SOURCES} ${SRB2_PNG_HEADERS}) - source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES}) - source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES}) - source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES}) - source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS}) - source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS}) - - if(${SRB2_CONFIG_HWRENDER}) - set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES} - ${SRB2_HWRENDER_SOURCES} - ${SRB2_HWRENDER_HEADERS} - ${SRB2_R_OPENGL_SOURCES} - ${SRB2_R_OPENGL_HEADERS} - ) - - source_group("Hardware" FILES ${SRB2_HWRENDER_SOURCES} ${SRB2_HWRENDER_HEADERS}) - source_group("Hardware\\OpenGL Renderer" FILES ${SRB2_R_OPENGL_SOURCES} ${SRB2_R_OPENGL_HEADERS}) - endif() - if(${SRB2_USEASM}) - set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES} - ${SRB2_NASM_SOURCES} - ) - if(MSVC) - set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES} - ${SRB2_NASM_OBJECTS} - ) - set_source_files_properties(${SRB2_NASM_OBJECTS} PROPERTIES GENERATED ON) - else() - list(APPEND SRB2_SDL2_TOTAL_SOURCES ${SRB2_ASM_SOURCES}) - set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES LANGUAGE C) - set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp") - endif() + set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES LANGUAGE C) + set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp") endif() if(${CMAKE_SYSTEM} MATCHES Windows) - set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES} - ${CMAKE_SOURCE_DIR}/src/win32/win_dbg.c - ${CMAKE_SOURCE_DIR}/src/win32/Srb2win.rc - ) + target_sources(SRB2SDL2 PRIVATE + ../win32/win_dbg.c + ../win32/Srb2win.rc) endif() if(${CMAKE_SYSTEM} MATCHES Darwin) set(MACOSX_BUNDLE_ICON_FILE Srb2mac.icns) set_source_files_properties(macosx/Srb2mac.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") - set(SRB2_SDL2_MAC_SOURCES + target_sources(SRB2SDL2 PRIVATE macosx/mac_alert.c macosx/mac_alert.h macosx/mac_resources.c macosx/mac_resources.h macosx/Srb2mac.icns ) - source_group("Interface Code\\OSX Compatibility" FILES ${SRB2_SDL2_MAC_SOURCES}) - set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES} ${SRB2_SDL2_MAC_SOURCES}) endif() - add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 ${SRB2_SDL2_TOTAL_SOURCES}) if(${CMAKE_SYSTEM} MATCHES Windows) set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2win) elseif(${CMAKE_SYSTEM} MATCHES Linux) @@ -158,39 +87,40 @@ if(${SDL2_FOUND}) endif() if(${CMAKE_SYSTEM} MATCHES Darwin) - find_library(CORE_LIB CoreFoundation) + find_library(CORE_FOUNDATION_LIBRARY "CoreFoundation") target_link_libraries(SRB2SDL2 PRIVATE - ${CORE_LIB} - SDL2 - SDL2_mixer - ${GME_LIBRARIES} - ${OPENMPT_LIBRARIES} - ${MIXERX_LIBRARIES} - ${PNG_LIBRARIES} - ${ZLIB_LIBRARIES} - ${OPENGL_LIBRARIES} - ${CURL_LIBRARIES} + ${CORE_FOUNDATION_LIBRARY} ) set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}") - else() - target_link_libraries(SRB2SDL2 PRIVATE - ${SDL2_LIBRARIES} - ${SDL2_MIXER_LIBRARIES} - ${GME_LIBRARIES} - ${OPENMPT_LIBRARIES} - ${MIXERX_LIBRARIES} - ${PNG_LIBRARIES} - ${ZLIB_LIBRARIES} - ${OPENGL_LIBRARIES} - ${CURL_LIBRARIES} - ) - if(${CMAKE_SYSTEM} MATCHES Linux) - target_link_libraries(SRB2SDL2 PRIVATE - m - rt - ) - endif() + # Configure the app bundle icon and plist properties + target_sources(SRB2SDL2 PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/macosx/Srb2mac.icns") + set_target_properties(SRB2SDL2 PROPERTIES + MACOSX_BUNDLE_ICON_FILE "Srb2mac" + MACOSX_BUNDLE_BUNDLE_NAME "Sonic Robo Blast 2" + MACOSX_BUNDLE_BUNDLE_VERSION ${SRB2_VERSION} + + RESOURCE "${CMAKE_CURRENT_SOURCE_DIR}/macosx/Srb2mac.icns" + ) + endif() + + target_link_libraries(SRB2SDL2 PRIVATE + ${SDL2_LIBRARIES} + ${SDL2_MIXER_LIBRARIES} + ${GME_LIBRARIES} + ${OPENMPT_LIBRARIES} + ${MIXERX_LIBRARIES} + ${PNG_LIBRARIES} + ${ZLIB_LIBRARIES} + ${OPENGL_LIBRARIES} + ${CURL_LIBRARIES} + ) + + if(${CMAKE_SYSTEM} MATCHES Linux) + target_link_libraries(SRB2SDL2 PRIVATE + m + rt + ) endif() #target_link_libraries(SRB2SDL2 PRIVATE SRB2Core) @@ -205,22 +135,8 @@ if(${SDL2_FOUND}) set(ASM_ASSEMBLER_OBJFORMAT ${CMAKE_ASM_NASM_OBJECT_FORMAT}) set_source_files_properties(${SRB2_NASM_SOURCES} LANGUAGE ASM_NASM) endif() - - if(MSVC) - # using assembler with msvc doesn't work, must do it manually - foreach(ASMFILE ${SRB2_NASM_SOURCES}) - get_filename_component(ASMFILE_NAME ${ASMFILE} NAME_WE) - set(ASMFILE_NAME ${ASMFILE_NAME}.obj) - add_custom_command(TARGET SRB2SDL2 PRE_LINK - COMMAND ${ASM_ASSEMBLER_TEMP} ARGS -f ${ASM_ASSEMBLER_OBJFORMAT} -o ${CMAKE_CURRENT_BINARY_DIR}/${ASMFILE_NAME} ${ASMFILE} - COMMENT "assemble ${ASMFILE_NAME}." - ) - endforeach() - endif() endif() - set_target_properties(SRB2SDL2 PROPERTIES VERSION ${SRB2_VERSION}) - if(${CMAKE_SYSTEM} MATCHES Windows) target_link_libraries(SRB2SDL2 PRIVATE ws2_32 @@ -230,31 +146,6 @@ if(${SDL2_FOUND}) ) endif() - if(MSVC) - if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES}) - set(SDL2_MAIN_FOUND ON) - if(${SRB2_SYSTEM_BITS} EQUAL 64) - set(SDL2_MAIN_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/SDL2/x86_64-w64-mingw32/include/SDL2) - set(SDL2_MAIN_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/SDL2/x86_64-w64-mingw32/lib -lSDL2main") - else() # 32-bit - set(SDL2_MAIN_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/SDL2/i686-w64-mingw32/include/SDL2) - set(SDL2_MAIN_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/SDL2/i686-w64-mingw32/lib -lSDL2main") - endif() - else() - find_package(SDL2_MAIN REQUIRED) - endif() - target_link_libraries(SRB2SDL2 PRIVATE - ${SDL2_MAIN_LIBRARIES} - ) - target_compile_options(SRB2SDL2 PRIVATE - /Umain - /D_CRT_SECURE_NO_WARNINGS # something about string functions. - /D_CRT_NONSTDC_NO_DEPRECATE - /DSDLMAIN - /D_WINSOCK_DEPRECATED_NO_WARNINGS # Don't care - ) - endif() - target_include_directories(SRB2SDL2 PRIVATE ${SDL2_INCLUDE_DIRS} ${SDL2_MIXER_INCLUDE_DIRS} @@ -296,6 +187,7 @@ if(${SDL2_FOUND}) install(TARGETS SRB2SDL2 BUNDLE DESTINATION . ) + set_property(TARGET SRB2SDL2 PROPERTY INSTALL_RPATH_USE_LINK_PATH ON) else() install(TARGETS SRB2SDL2 SRB2SDL2 RUNTIME DESTINATION . diff --git a/src/sdl/MakeNIX.cfg b/src/sdl/MakeNIX.cfg deleted file mode 100644 index 47c944eb5..000000000 --- a/src/sdl/MakeNIX.cfg +++ /dev/null @@ -1,74 +0,0 @@ -# -# sdl/makeNIX.cfg for SRB2/?nix -# - -#Valgrind support -ifdef VALGRIND -VALGRIND_PKGCONFIG?=valgrind -VALGRIND_CFLAGS?=$(shell $(PKG_CONFIG) $(VALGRIND_PKGCONFIG) --cflags) -VALGRIND_LDFLAGS?=$(shell $(PKG_CONFIG) $(VALGRIND_PKGCONFIG) --libs) -ZDEBUG=1 -LIBS+=$(VALGRIND_LDFLAGS) -ifdef GCC46 -WFLAGS+=-Wno-error=unused-but-set-variable -WFLAGS+=-Wno-unused-but-set-variable -endif -endif - -# -#here is GNU/Linux and other -# - - OPTS=-DUNIXCOMMON - - #LDFLAGS = -L/usr/local/lib - LIBS=-lm -ifdef LINUX - LIBS+=-lrt -ifdef NOTERMIOS - OPTS+=-DNOTERMIOS -endif -endif - -ifdef LINUX64 - OPTS+=-DLINUX64 -endif - -# -#here is Solaris -# -ifdef SOLARIS - NOIPX=1 - NOASM=1 - OPTS+=-DSOLARIS -DINADDR_NONE=INADDR_ANY -DBSD_COMP - OPTS+=-I/usr/local/include -I/opt/sfw/include - LDFLAGS+=-L/opt/sfw/lib - LIBS+=-lsocket -lnsl -endif - -# -#here is FreeBSD -# -ifdef FREEBSD - OPTS+=-DLINUX -DFREEBSD -I/usr/X11R6/include - SDL_CONFIG?=sdl11-config - LDFLAGS+=-L/usr/X11R6/lib - LIBS+=-lipx -lkvm -endif - -# -#here is Mac OS X -# -ifdef MACOSX - OBJS+=$(OBJDIR)/mac_resources.o - OBJS+=$(OBJDIR)/mac_alert.o - LIBS+=-framework CoreFoundation -endif - -ifndef NOHW - OPTS+=-I/usr/X11R6/include - LDFLAGS+=-L/usr/X11R6/lib -endif - - # name of the exefile - EXENAME?=lsdl2srb2 diff --git a/src/sdl/Makefile.cfg b/src/sdl/Makefile.cfg deleted file mode 100644 index 45d0d6ba7..000000000 --- a/src/sdl/Makefile.cfg +++ /dev/null @@ -1,125 +0,0 @@ -# -# sdl/makefile.cfg for SRB2/SDL -# - -# -#SDL...., *looks at Alam*, THIS IS A MESS! -# - -ifdef UNIXCOMMON -include sdl/MakeNIX.cfg -endif - -ifdef PANDORA -include sdl/SRB2Pandora/Makefile.cfg -endif #ifdef PANDORA - -ifdef CYGWIN32 -include sdl/MakeCYG.cfg -endif #ifdef CYGWIN32 - -ifdef SDL_PKGCONFIG -SDL_CFLAGS?=$(shell $(PKG_CONFIG) $(SDL_PKGCONFIG) --cflags) -SDL_LDFLAGS?=$(shell $(PKG_CONFIG) $(SDL_PKGCONFIG) --libs) -else -ifdef PREFIX - SDL_CONFIG?=$(PREFIX)-sdl2-config -else - SDL_CONFIG?=sdl2-config -endif - -ifdef STATIC - SDL_CFLAGS?=$(shell $(SDL_CONFIG) --cflags) - SDL_LDFLAGS?=$(shell $(SDL_CONFIG) --static-libs) -else - SDL_CFLAGS?=$(shell $(SDL_CONFIG) --cflags) - SDL_LDFLAGS?=$(shell $(SDL_CONFIG) --libs) -endif -endif - - - #use the x86 asm code -ifndef CYGWIN32 -ifndef NOASM - USEASM=1 -endif -endif - - OBJS+=$(OBJDIR)/i_video.o $(OBJDIR)/dosstr.o $(OBJDIR)/endtxt.o $(OBJDIR)/hwsym_sdl.o - - OPTS+=-DDIRECTFULLSCREEN -DHAVE_SDL - -ifndef NOHW - OBJS+=$(OBJDIR)/r_opengl.o $(OBJDIR)/ogl_sdl.o -endif - -ifdef NOMIXER - i_sound_o=$(OBJDIR)/sdl_sound.o -else - i_sound_o=$(OBJDIR)/mixer_sound.o - OPTS+=-DHAVE_MIXER -ifdef HAVE_MIXERX - OPTS+=-DHAVE_MIXERX - SDL_LDFLAGS+=-lSDL2_mixer_ext -else - SDL_LDFLAGS+=-lSDL2_mixer -endif -endif - -ifndef NOTHREADS - OPTS+=-DHAVE_THREADS - OBJS+=$(OBJDIR)/i_threads.o -endif - -ifdef SDL_TTF - OPTS+=-DHAVE_TTF - SDL_LDFLAGS+=-lSDL2_ttf -lfreetype -lz - OBJS+=$(OBJDIR)/i_ttf.o -endif - -ifdef SDL_IMAGE - OPTS+=-DHAVE_IMAGE - SDL_LDFLAGS+=-lSDL2_image -endif - -ifdef SDL_NET - OPTS+=-DHAVE_SDLNET - SDL_LDFLAGS+=-lSDL2_net -endif - -ifdef MINGW -ifndef NOSDLMAIN - SDLMAIN=1 -endif -endif - -ifdef SDLMAIN - OPTS+=-DSDLMAIN -else -ifdef MINGW - SDL_CFLAGS+=-Umain - SDL_LDFLAGS+=-mconsole -endif -endif - -ifndef NOHW -ifdef OPENAL -ifdef MINGW - LIBS:=-lopenal32 $(LIBS) -else - LIBS:=-lopenal $(LIBS) -endif -else -ifdef MINGW -ifdef DS3D - LIBS:=-ldsound -luuid $(LIBS) -endif -endif -endif -endif - -CFLAGS+=$(SDL_CFLAGS) -LIBS:=$(SDL_LDFLAGS) $(LIBS) -ifdef STATIC - LIBS+=$(shell $(SDL_CONFIG) --static-libs) -endif diff --git a/src/sdl/Sourcefile b/src/sdl/Sourcefile new file mode 100644 index 000000000..82d5ce073 --- /dev/null +++ b/src/sdl/Sourcefile @@ -0,0 +1,7 @@ +i_net.c +i_system.c +i_main.c +i_video.c +dosstr.c +endtxt.c +hwsym_sdl.c diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index d46a4af2b..d79dde766 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -245,8 +245,10 @@ + + @@ -303,6 +305,7 @@ + @@ -406,6 +409,7 @@ + @@ -413,6 +417,7 @@ + @@ -473,10 +478,12 @@ + + true diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index adae2f446..4d2532ca4 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -135,6 +135,16 @@ D_Doom + + D_Doom + + + D_Doom + + + D_Doom + + D_Doom @@ -288,6 +298,9 @@ I_Interface + + I_Interface + I_Interface @@ -402,6 +415,12 @@ P_Play + + P_Play + + + R_Rend + R_Rend @@ -597,6 +616,16 @@ D_Doom + + D_Doom + + + D_Doom + + + D_Doom + + D_Doom @@ -720,6 +749,9 @@ LUA + + LUA + LUA @@ -741,6 +773,9 @@ LUA + + LUA + LUA @@ -786,6 +821,9 @@ M_Misc + + M_Misc + O_Other @@ -846,6 +884,9 @@ P_Play + + P_Play + P_Play diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index 398508662..96e3d7d69 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -90,7 +90,6 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ReadRect); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); - GETFUNC(ClearCacheList); GETFUNC(SetSpecialState); GETFUNC(GetTextureUsed); GETFUNC(DrawModel); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index d2c819c37..9de632734 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -5,7 +5,7 @@ // // Copyright (C) 1993-1996 by id Software, Inc. // Portions Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -102,7 +102,7 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #endif #endif -#if (defined (__unix__) && !defined (_MSDOS)) || (defined (UNIXCOMMON) && !defined(__APPLE__)) +#if defined (__unix__) || (defined (UNIXCOMMON) && !defined (__APPLE__)) #include #include #define NEWSIGNALHANDLER @@ -137,6 +137,12 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T); #include #endif +#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) +#include +#include +#define UNIXBACKTRACE +#endif + // Locations for searching the srb2.pk3 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2" @@ -238,6 +244,71 @@ SDL_bool framebuffer = SDL_FALSE; UINT8 keyboard_started = false; +#ifdef UNIXBACKTRACE +#define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string) +#define CRASHLOG_WRITE(string) if (fd != -1) write(fd, string, strlen(string)) +#define CRASHLOG_STDERR_WRITE(string) \ + if (fd != -1)\ + write(fd, string, strlen(string));\ + I_OutputMsg("%s", string) + +static void write_backtrace(INT32 signal) +{ + int fd = -1; + size_t size; + time_t rawtime; + struct tm timeinfo; + + enum { BT_SIZE = 1024, STR_SIZE = 32 }; + void *array[BT_SIZE]; + char timestr[STR_SIZE]; + + const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n"; + const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr. + + fd = open(va("%s" PATHSEP "%s", srb2home, "crash-log.txt"), O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR); + + if (fd == -1) + I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n"); + + // Get the current time as a string. + time(&rawtime); + localtime_r(&rawtime, &timeinfo); + strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo); + + CRASHLOG_WRITE("------------------------\n"); // Nice looking seperator + + CRASHLOG_STDERR_WRITE("\n"); // Newline to look nice for both outputs. + CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message + STDERR_WRITE(error2); // Tell the user where the crash log is. + + // Tell the log when we crashed. + CRASHLOG_WRITE("Time of crash: "); + CRASHLOG_WRITE(timestr); + CRASHLOG_WRITE("\n"); + + // Give the crash log the cause and a nice 'Backtrace:' thing + // The signal is given to the user when the parent process sees we crashed. + CRASHLOG_WRITE("Cause: "); + CRASHLOG_WRITE(strsignal(signal)); + CRASHLOG_WRITE("\n"); // Newline for the signal name + + CRASHLOG_STDERR_WRITE("\nBacktrace:\n"); + + // Flood the output and log with the backtrace + size = backtrace(array, BT_SIZE); + backtrace_symbols_fd(array, size, fd); + backtrace_symbols_fd(array, size, STDERR_FILENO); + + CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :) + + close(fd); +} +#undef STDERR_WRITE +#undef CRASHLOG_WRITE +#undef CRASHLOG_STDERR_WRITE +#endif // UNIXBACKTRACE + static void I_ReportSignal(int num, int coredumped) { //static char msg[] = "oh no! back to reality!\r\n"; @@ -287,9 +358,10 @@ static void I_ReportSignal(int num, int coredumped) I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, - "Process killed by signal", - sigmsg, NULL); + if (!M_CheckParm("-dedicated")) + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, + "Process killed by signal", + sigmsg, NULL); } #ifndef NEWSIGNALHANDLER @@ -297,6 +369,9 @@ FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num) { D_QuitNetGame(); // Fix server freezes CL_AbortDownloadResume(); +#ifdef UNIXBACKTRACE + write_backtrace(num); +#endif I_ReportSignal(num, 0); I_ShutdownSystem(); signal(num, SIG_DFL); //default signal action @@ -476,7 +551,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; @@ -498,7 +573,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 { @@ -506,19 +581,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; } @@ -552,18 +627,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); @@ -578,7 +653,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) @@ -687,6 +762,28 @@ static void I_RegisterSignals (void) #endif } +#ifdef NEWSIGNALHANDLER +static void signal_handler_child(INT32 num) +{ +#ifdef UNIXBACKTRACE + write_backtrace(num); +#endif + + signal(num, SIG_DFL); //default signal action + raise(num); +} + +static void I_RegisterChildSignals(void) +{ + // If these defines don't exist, + // then compilation would have failed above us... + signal(SIGILL , signal_handler_child); + signal(SIGSEGV , signal_handler_child); + signal(SIGABRT , signal_handler_child); + signal(SIGFPE , signal_handler_child); +} +#endif + // //I_OutputMsg // @@ -821,7 +918,7 @@ INT32 I_GetKey (void) ev = &events[eventtail]; if (ev->type == ev_keydown || ev->type == ev_console) { - rc = ev->data1; + rc = ev->key; continue; } } @@ -881,22 +978,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; @@ -1014,15 +1111,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 { @@ -1036,8 +1133,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); } @@ -1151,22 +1248,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); } @@ -1174,7 +1271,7 @@ void I_ShutdownJoystick2(void) event.type = ev_joystick2; for (i = 0; i < JOYAXISSET; i++) { - event.data1 = i; + event.key = i; D_PostEvent(&event); } @@ -1186,7 +1283,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 @@ -1225,7 +1322,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); } } @@ -1256,7 +1353,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); } } @@ -1268,7 +1365,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; @@ -1284,17 +1381,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 { @@ -1308,8 +1405,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); } @@ -1708,7 +1805,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) @@ -782,7 +795,7 @@ static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt) joyid[1] = SDL_JoystickInstanceID(JoyInfo2.dev); evt.axis++; - event.data1 = event.data2 = event.data3 = INT32_MAX; + event.key = event.x = event.y = INT32_MAX; if (evt.which == joyid[0]) { @@ -799,14 +812,14 @@ static void Impl_HandleJoystickAxisEvent(SDL_JoyAxisEvent evt) //vaule if (evt.axis%2) { - event.data1 = evt.axis / 2; - event.data2 = SDLJoyAxis(evt.value, event.type); + event.key = evt.axis / 2; + event.x = SDLJoyAxis(evt.value, event.type); } else { evt.axis--; - event.data1 = evt.axis / 2; - event.data3 = SDLJoyAxis(evt.value, event.type); + event.key = evt.axis / 2; + event.y = SDLJoyAxis(evt.value, event.type); } D_PostEvent(&event); } @@ -826,11 +839,11 @@ static void Impl_HandleJoystickHatEvent(SDL_JoyHatEvent evt) if (evt.which == joyid[0]) { - event.data1 = KEY_HAT1 + (evt.hat*4); + event.key = KEY_HAT1 + (evt.hat*4); } else if (evt.which == joyid[1]) { - event.data1 = KEY_2HAT1 + (evt.hat*4); + event.key = KEY_2HAT1 + (evt.hat*4); } else return; @@ -849,11 +862,11 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type) if (evt.which == joyid[0]) { - event.data1 = KEY_JOY1; + event.key = KEY_JOY1; } else if (evt.which == joyid[1]) { - event.data1 = KEY_2JOY1; + event.key = KEY_2JOY1; } else return; if (type == SDL_JOYBUTTONUP) @@ -867,7 +880,7 @@ static void Impl_HandleJoystickButtonEvent(SDL_JoyButtonEvent evt, Uint32 type) else return; if (evt.button < JOYBUTTONS) { - event.data1 += evt.button; + event.key += evt.button; } else return; @@ -1057,7 +1070,7 @@ void I_GetEvent(void) M_SetupJoystickMenu(0); break; case SDL_QUIT: - LUAh_GameQuit(true); + LUA_HookBool(true, HOOK(GameQuit)); I_Quit(); break; } @@ -1071,9 +1084,9 @@ void I_GetEvent(void) SDL_GetWindowSize(window, &wwidth, &wheight); //SDL_memset(&event, 0, sizeof(event_t)); event.type = ev_mouse; - event.data1 = 0; - event.data2 = (INT32)lround(mousemovex * ((float)wwidth / (float)realwidth)); - event.data3 = (INT32)lround(mousemovey * ((float)wheight / (float)realheight)); + event.key = 0; + event.x = (INT32)lround(mousemovex * ((float)wwidth / (float)realwidth)); + event.y = (INT32)lround(mousemovey * ((float)wheight / (float)realheight)); D_PostEvent(&event); } @@ -1862,7 +1875,6 @@ void VID_StartupOpenGL(void) HWD.pfnReadRect = hwSym("ReadRect",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); - HWD.pfnClearCacheList = hwSym("ClearCacheList",NULL); HWD.pfnSetSpecialState = hwSym("SetSpecialState",NULL); HWD.pfnSetPalette = hwSym("SetPalette",NULL); HWD.pfnGetTextureUsed = hwSym("GetTextureUsed",NULL); @@ -1939,3 +1951,8 @@ void I_ShutdownGraphics(void) framebuffer = SDL_FALSE; } #endif + +void I_GetCursorPosition(INT32 *x, INT32 *y) +{ + SDL_GetMouseState(x, y); +} diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index c64164caa..748cd374b 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -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,10 +1294,14 @@ 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}; +#if defined (GME_VERSION) && GME_VERSION >= 0x000603 + if (looping) + gme_set_autoload_playback_limit(gme, 0); +#endif gme_set_equalizer(gme, &eq); gme_start_track(gme, 0); current_track = 0; @@ -1356,7 +1360,7 @@ void I_StopSong(void) if (!fading_nocleanup) I_StopFadingSong(); -#ifdef HAVE_LIBGME +#ifdef HAVE_GME if (gme) { Mix_HookMusic(NULL, NULL); @@ -1429,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/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 52727c056..67e98d4f5 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -177,7 +177,9 @@ boolean OglSdlSurface(INT32 w, INT32 h) // Also set the renderer variable back to software so the next launch won't // repeat this error. CV_StealthSet(&cv_renderer, "Software"); - I_Error("OpenGL Error: Failed to access the GPU. There may be an issue with your graphics drivers."); + I_Error("OpenGL Error: Failed to access the GPU. Possible reasons include:\n" + "- GPU vendor has dropped OpenGL support on your GPU and OS. (Old GPU?)\n" + "- GPU drivers are missing or broken. You may need to update your drivers."); } } first_init = true; diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h index 748e30bae..9744bc6f1 100644 --- a/src/sdl/ogl_sdl.h +++ b/src/sdl/ogl_sdl.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 86e294fb5..0de3788fe 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 2014-2020 by Sonic Team Junior. +// Copyright (C) 2014-2022 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h index e35506114..6b6e79d97 100644 --- a/src/sdl/sdlmain.h +++ b/src/sdl/sdlmain.h @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// Copyright (C) 2006-2020 by Sonic Team Junior. +// Copyright (C) 2006-2022 by Sonic Team Junior. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License diff --git a/src/sounds.c b/src/sounds.c index 092bda21f..f7f3ad328 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/sounds.h b/src/sounds.h index e49dd2f3e..eec518689 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/st_stuff.c b/src/st_stuff.c index 649644620..6c9a0eeca 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -43,6 +43,7 @@ #endif #include "lua_hud.h" +#include "lua_hook.h" UINT16 objectsdrawn = 0; @@ -299,10 +300,6 @@ void ST_LoadGraphics(void) gravboots = W_CachePatchName("TVGVICON", PU_HUDGFX); tagico = W_CachePatchName("TAGICO", PU_HUDGFX); - rflagico = W_CachePatchName("RFLAGICO", PU_HUDGFX); - bflagico = W_CachePatchName("BFLAGICO", PU_HUDGFX); - rmatcico = W_CachePatchName("RMATCICO", PU_HUDGFX); - bmatcico = W_CachePatchName("BMATCICO", PU_HUDGFX); gotrflag = W_CachePatchName("GOTRFLAG", PU_HUDGFX); gotbflag = W_CachePatchName("GOTBFLAG", PU_HUDGFX); fnshico = W_CachePatchName("FNSHICO", PU_HUDGFX); @@ -1179,7 +1176,17 @@ static void ST_drawInput(void) break; case CS_SIMPLE: - V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "SIMPLE"); + V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "AUTOMATIC"); + y -= 8; + break; + + case CS_STANDARD: + V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "MANUAL"); + y -= 8; + break; + + case CS_LEGACY: + V_DrawThinString(x, y, hudinfo[HUD_LIVES].f, "STRAFE"); y -= 8; break; @@ -1371,7 +1378,7 @@ void ST_drawTitleCard(void) zzticker = lt_ticker; V_DrawMappedPatch(FixedInt(lt_zigzag), (-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); V_DrawMappedPatch(FixedInt(lt_zigzag), (zigzag->height-zzticker) % zigzag->height, V_SNAPTOTOP|V_SNAPTOLEFT, zigzag, colormap); - V_DrawMappedPatch(FixedInt(lt_zigzag), (-zigzag->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); + V_DrawMappedPatch(FixedInt(lt_zigzag), (-zztext->height+zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); V_DrawMappedPatch(FixedInt(lt_zigzag), (zzticker) % zztext->height, V_SNAPTOTOP|V_SNAPTOLEFT, zztext, colormap); } @@ -1395,7 +1402,7 @@ void ST_drawTitleCard(void) lt_lasttic = lt_ticker; luahook: - LUAh_TitleCardHUD(stplyr); + LUA_HUDHOOK(titlecard); } // @@ -2040,9 +2047,8 @@ static void ST_drawNiGHTSHUD(void) else numbersize = 48/2; - if ((oldspecialstage && leveltime & 2) - && (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER)) - && !(stplyr->powers[pw_shield] & SH_PROTECTWATER)) + if ((oldspecialstage && leveltime & 2) && + (stplyr->mo->eflags & (MFE_TOUCHWATER|MFE_UNDERWATER) && !(stplyr->powers[pw_shield] & ((stplyr->mo->eflags & MFE_TOUCHLAVA) ? SH_PROTECTFIRE : SH_PROTECTWATER)))) col = SKINCOLOR_ORANGE; ST_DrawNightsOverlayNum((160 + numbersize)<ammoremoval); V_DrawString(offset + 8 + stplyr->ammoremovalweapon * 20, y, - V_REDMAP|V_SNAPTOBOTTOM, penaltystr); + V_REDMAP|V_SNAPTOBOTTOM|V_PERPLAYER, penaltystr); } } @@ -2295,7 +2301,7 @@ static void ST_drawTextHUD(void) for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i] || players[i].spectator) + if (!playeringame[i] || players[i].spectator || players[i].bot) continue; if (players[i].lives <= 0) continue; @@ -2363,27 +2369,29 @@ static inline void ST_drawRaceHUD(void) static void ST_drawTeamHUD(void) { - patch_t *p; #define SEP 20 if (F_GetPromptHideHud(0)) // y base is 0 return; - if (gametyperules & GTR_TEAMFLAGS) - p = bflagico; - else - p = bmatcico; + rflagico = W_CachePatchName("RFLAGICO", PU_HUDGFX); + bflagico = W_CachePatchName("BFLAGICO", PU_HUDGFX); + rmatcico = W_CachePatchName("RMATCICO", PU_HUDGFX); + bmatcico = W_CachePatchName("BMATCICO", PU_HUDGFX); if (LUA_HudEnabled(hud_teamscores)) - V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - (p->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); - - if (gametyperules & GTR_TEAMFLAGS) - p = rflagico; - else - p = rmatcico; - - if (LUA_HudEnabled(hud_teamscores)) - V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - (p->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p); + { + if (gametyperules & GTR_TEAMFLAGS) + { + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - (bflagico->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, bflagico); + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - (rflagico->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, rflagico); + } + else + { + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - (bmatcico->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, bmatcico); + V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - (rmatcico->width / 4), 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, rmatcico); + } + } if (!(gametyperules & GTR_TEAMFLAGS)) goto num; @@ -2734,7 +2742,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/st_stuff.h b/src/st_stuff.h index 4ea307d2b..c59bc2ac6 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/strcasestr.c b/src/strcasestr.c index b266278ed..6a686d6dc 100644 --- a/src/strcasestr.c +++ b/src/strcasestr.c @@ -2,7 +2,7 @@ strcasestr -- case insensitive substring searching function. */ /* -Copyright 2019-2020 James R. +Copyright 2019-2022 James R. All rights reserved. Redistribution and use in source forms, with or without modification, is diff --git a/src/string.c b/src/string.c index e430c5cc3..5534a3f0c 100644 --- a/src/string.c +++ b/src/string.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by Graue. -// Copyright (C) 2006-2020 by Sonic Team Junior. +// Copyright (C) 2006-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tables.c b/src/tables.c index 70a1ecd0a..13949b6a7 100644 --- a/src/tables.c +++ b/src/tables.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tables.h b/src/tables.h index 953d891ce..c44c7d525 100644 --- a/src/tables.h +++ b/src/tables.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/taglist.c b/src/taglist.c index b11216b6c..305b05f04 100644 --- a/src/taglist.c +++ b/src/taglist.c @@ -1,8 +1,8 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. -// Copyright (C) 2020 by Nev3r. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// Copyright (C) 2020-2022 by Nev3r. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -14,6 +14,12 @@ #include "taglist.h" #include "z_zone.h" #include "r_data.h" +#include "p_spec.h" + +// Bit array of whether a tag exists for sectors/lines/things. +bitarray_t tags_available[BIT_ARRAY_SIZE (MAXTAGS)]; + +size_t num_tags; // Taggroups are used to list elements of the same tag, for iteration. // Since elements can now have multiple tags, it means an element may appear @@ -22,14 +28,35 @@ taggroup_t* tags_sectors[MAXTAGS + 1]; taggroup_t* tags_lines[MAXTAGS + 1]; taggroup_t* tags_mapthings[MAXTAGS + 1]; -/// Adds a tag to a given element's taglist. +/// Adds a tag to a given element's taglist. It will not add a duplicate. /// \warning This does not rebuild the global taggroups, which are used for iteration. void Tag_Add (taglist_t* list, const mtag_t tag) { - list->tags = Z_Realloc(list->tags, (list->count + 1) * sizeof(list->tags), PU_LEVEL, NULL); + if (Tag_Find(list, tag)) + return; + list->tags = Z_Realloc(list->tags, (list->count + 1) * sizeof(mtag_t), PU_LEVEL, NULL); list->tags[list->count++] = tag; } +/// Removes a tag from a given element's taglist. +/// \warning This does not rebuild the global taggroups, which are used for iteration. +void Tag_Remove(taglist_t* list, const mtag_t tag) +{ + UINT16 i; + + for (i = 0; i < list->count; i++) + { + if (list->tags[i] != tag) + continue; + + for (; i+1 < list->count; i++) + list->tags[i] = list->tags[i+1]; + + list->tags = Z_Realloc(list->tags, (list->count - 1) * sizeof(mtag_t), PU_LEVEL, NULL); + return; + } +} + /// Sets the first tag entry in a taglist. /// Replicates the old way of accessing element->tag. void Tag_FSet (taglist_t* list, const mtag_t tag) @@ -105,6 +132,39 @@ size_t Taggroup_Find (const taggroup_t *group, const size_t id) return -1; } +/// group->count, but also checks for NULL +size_t Taggroup_Count (const taggroup_t *group) +{ + return group ? group->count : 0; +} + +/// Iterate thru elements in a global taggroup. +INT32 Taggroup_Iterate +( taggroup_t *garray[], + const size_t max_elements, + const mtag_t tag, + const size_t p) +{ + const taggroup_t *group; + + if (tag == MTAG_GLOBAL) + { + if (p < max_elements) + return p; + return -1; + } + + group = garray[(UINT16)tag]; + + if (group) + { + if (p < group->count) + return group->elements[p]; + return -1; + } + return -1; +} + /// Add an element to a global taggroup. void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) { @@ -120,6 +180,12 @@ void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) if (Taggroup_Find(group, id) != (size_t)-1) return; + if (! in_bit_array(tags_available, tag)) + { + num_tags++; + set_bit_array(tags_available, tag); + } + // Create group if empty. if (!group) { @@ -133,25 +199,66 @@ void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) for (i = 0; i < group->count; i++) if (group->elements[i] > id) break; - - group->elements = Z_Realloc(group->elements, (group->count + 1) * sizeof(size_t), PU_LEVEL, NULL); - - // Offset existing elements to make room for the new one. - if (i < group->count) - memmove(&group->elements[i + 1], &group->elements[i], group->count - i); } + group->elements = Z_Realloc(group->elements, (group->count + 1) * sizeof(size_t), PU_LEVEL, NULL); + + // Offset existing elements to make room for the new one. + if (i < group->count) + memmove(&group->elements[i + 1], &group->elements[i], group->count - i); + group->count++; - group->elements = Z_Realloc(group->elements, group->count * sizeof(size_t), PU_LEVEL, NULL); group->elements[i] = id; } +static void Taggroup_Add_Init(taggroup_t *garray[], const mtag_t tag, size_t id) +{ + taggroup_t *group; + + if (tag == MTAG_GLOBAL) + return; + + group = garray[(UINT16)tag]; + + if (! in_bit_array(tags_available, tag)) + { + num_tags++; + set_bit_array(tags_available, tag); + } + + // Create group if empty. + if (!group) + group = garray[(UINT16)tag] = Z_Calloc(sizeof(taggroup_t), PU_LEVEL, NULL); + else if (group->elements[group->count - 1] == id) + return; // Don't add duplicates + + group->count++; + + if (group->count > group->capacity) + { + group->capacity = 2 * group->count; + group->elements = Z_Realloc(group->elements, group->capacity * sizeof(size_t), PU_LEVEL, NULL); + } + + group->elements[group->count - 1] = id; +} + +static size_t total_elements_with_tag (const mtag_t tag) +{ + return + ( + Taggroup_Count(tags_sectors[tag]) + + Taggroup_Count(tags_lines[tag]) + + Taggroup_Count(tags_mapthings[tag]) + ); +} + /// Remove an element from a global taggroup. void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) { taggroup_t *group; size_t rempos; - size_t newcount; + size_t oldcount; if (tag == MTAG_GLOBAL) return; @@ -161,8 +268,14 @@ void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) if ((rempos = Taggroup_Find(group, id)) == (size_t)-1) return; + if (group->count == 1 && total_elements_with_tag(tag) == 1) + { + num_tags--; + unset_bit_array(tags_available, tag); + } + // Strip away taggroup if no elements left. - if (!(newcount = --group->count)) + if (!(oldcount = group->count--)) { Z_Free(group->elements); Z_Free(group); @@ -170,19 +283,18 @@ void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) } else { - size_t *newelements = Z_Malloc(newcount * sizeof(size_t), PU_LEVEL, NULL); + size_t *newelements = Z_Malloc(group->count * sizeof(size_t), PU_LEVEL, NULL); size_t i; // Copy the previous entries save for the one to remove. for (i = 0; i < rempos; i++) newelements[i] = group->elements[i]; - for (i = rempos + 1; i < group->count; i++) + for (i = rempos + 1; i < oldcount; i++) newelements[i - 1] = group->elements[i]; Z_Free(group->elements); group->elements = newelements; - group->count = newcount; } } @@ -190,17 +302,17 @@ void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) static void Taglist_AddToSectors (const mtag_t tag, const size_t itemid) { - Taggroup_Add(tags_sectors, tag, itemid); + Taggroup_Add_Init(tags_sectors, tag, itemid); } static void Taglist_AddToLines (const mtag_t tag, const size_t itemid) { - Taggroup_Add(tags_lines, tag, itemid); + Taggroup_Add_Init(tags_lines, tag, itemid); } static void Taglist_AddToMapthings (const mtag_t tag, const size_t itemid) { - Taggroup_Add(tags_mapthings, tag, itemid); + Taggroup_Add_Init(tags_mapthings, tag, itemid); } /// After all taglists have been built for each element (sectors, lines, things), @@ -209,6 +321,9 @@ void Taglist_InitGlobalTables(void) { size_t i, j; + memset(tags_available, 0, sizeof tags_available); + num_tags = 0; + for (i = 0; i < MAXTAGS; i++) { tags_sectors[i] = NULL; @@ -236,56 +351,17 @@ void Taglist_InitGlobalTables(void) INT32 Tag_Iterate_Sectors (const mtag_t tag, const size_t p) { - if (tag == MTAG_GLOBAL) - { - if (p < numsectors) - return p; - return -1; - } - - if (tags_sectors[(UINT16)tag]) - { - if (p < tags_sectors[(UINT16)tag]->count) - return tags_sectors[(UINT16)tag]->elements[p]; - return -1; - } - return -1; + return Taggroup_Iterate(tags_sectors, numsectors, tag, p); } INT32 Tag_Iterate_Lines (const mtag_t tag, const size_t p) { - if (tag == MTAG_GLOBAL) - { - if (p < numlines) - return p; - return -1; - } - - if (tags_lines[(UINT16)tag]) - { - if (p < tags_lines[(UINT16)tag]->count) - return tags_lines[(UINT16)tag]->elements[p]; - return -1; - } - return -1; + return Taggroup_Iterate(tags_lines, numlines, tag, p); } INT32 Tag_Iterate_Things (const mtag_t tag, const size_t p) { - if (tag == MTAG_GLOBAL) - { - if (p < nummapthings) - return p; - return -1; - } - - if (tags_mapthings[(UINT16)tag]) - { - if (p < tags_mapthings[(UINT16)tag]->count) - return tags_mapthings[(UINT16)tag]->elements[p]; - return -1; - } - return -1; + return Taggroup_Iterate(tags_mapthings, nummapthings, tag, p); } INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag) @@ -352,6 +428,22 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) // Ingame list manipulation. +/// Adds the tag to the given sector, and updates the global taggroups. +void Tag_SectorAdd (const size_t id, const mtag_t tag) +{ + sector_t* sec = §ors[id]; + Tag_Add(&sec->tags, tag); + Taggroup_Add(tags_sectors, tag, id); +} + +/// Removes the tag from the given sector, and updates the global taggroups. +void Tag_SectorRemove (const size_t id, const mtag_t tag) +{ + sector_t* sec = §ors[id]; + Tag_Remove(&sec->tags, tag); + Taggroup_Remove(tags_sectors, tag, id); +} + /// Changes the first tag for a given sector, and updates the global taggroups. void Tag_SectorFSet (const size_t id, const mtag_t tag) { @@ -363,4 +455,22 @@ void Tag_SectorFSet (const size_t id, const mtag_t tag) Taggroup_Remove(tags_sectors, curtag, id); Taggroup_Add(tags_sectors, tag, id); Tag_FSet(&sec->tags, tag); + + // Sectors with linedef trigger effects need to have their trigger tag updated too + // This is a bit of a hack... + if (!udmf && GETSECSPECIAL(sec->special, 2) >= 1 && GETSECSPECIAL(sec->special, 2) <= 7) + sec->triggertag = tag; +} + +mtag_t Tag_NextUnused(mtag_t start) +{ + while ((UINT16)start < MAXTAGS) + { + if (!in_bit_array(tags_available, (UINT16)start)) + return start; + + start++; + } + + return MAXTAGS; } diff --git a/src/taglist.h b/src/taglist.h index 0e6d9f842..de6e9abd5 100644 --- a/src/taglist.h +++ b/src/taglist.h @@ -1,8 +1,8 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. -// Copyright (C) 2020 by Nev3r. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// Copyright (C) 2020-2022 by Nev3r. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -28,12 +28,15 @@ typedef struct } taglist_t; void Tag_Add (taglist_t* list, const mtag_t tag); +void Tag_Remove (taglist_t* list, const mtag_t tag); void Tag_FSet (taglist_t* list, const mtag_t tag); mtag_t Tag_FGet (const taglist_t* list); boolean Tag_Find (const taglist_t* list, const mtag_t tag); boolean Tag_Share (const taglist_t* list1, const taglist_t* list2); boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2); +void Tag_SectorAdd (const size_t id, const mtag_t tag); +void Tag_SectorRemove (const size_t id, const mtag_t tag); void Tag_SectorFSet (const size_t id, const mtag_t tag); /// Taggroup list. It is essentially just an element id list. @@ -41,8 +44,15 @@ typedef struct { size_t *elements; size_t count; + size_t capacity; } taggroup_t; +extern bitarray_t tags_available[]; + +extern mtag_t Tag_NextUnused(mtag_t start); + +extern size_t num_tags; + extern taggroup_t* tags_sectors[]; extern taggroup_t* tags_lines[]; extern taggroup_t* tags_mapthings[]; @@ -50,6 +60,13 @@ extern taggroup_t* tags_mapthings[]; void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id); void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id); size_t Taggroup_Find (const taggroup_t *group, const size_t id); +size_t Taggroup_Count (const taggroup_t *group); + +INT32 Taggroup_Iterate +( taggroup_t *garray[], + const size_t max_elements, + const mtag_t tag, + const size_t p); void Taglist_InitGlobalTables(void); @@ -60,25 +77,16 @@ INT32 Tag_Iterate_Things (const mtag_t tag, const size_t p); INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag); INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); -// Use this macro to declare an iterator position variable. -#define TAG_ITER_DECLARECOUNTER(level) size_t ICNT_##level - -#define TAG_ITER(level, fn, tag, return_varname) for(ICNT_##level = 0; (return_varname = fn(tag, ICNT_##level)) >= 0; ICNT_##level++) +#define ICNAME2(id) ICNT_##id +#define ICNAME(id) ICNAME2(id) +#define TAG_ITER(fn, tag, return_varname) for(size_t ICNAME(__LINE__) = 0; (return_varname = fn(tag, ICNAME(__LINE__))) >= 0; ICNAME(__LINE__)++) // Use these macros as wrappers for a taglist iteration. -#define TAG_ITER_SECTORS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Sectors, tag, return_varname) -#define TAG_ITER_LINES(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Lines, tag, return_varname) -#define TAG_ITER_THINGS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Things, tag, return_varname) +#define TAG_ITER_SECTORS(tag, return_varname) TAG_ITER(Tag_Iterate_Sectors, tag, return_varname) +#define TAG_ITER_LINES(tag, return_varname) TAG_ITER(Tag_Iterate_Lines, tag, return_varname) +#define TAG_ITER_THINGS(tag, return_varname) TAG_ITER(Tag_Iterate_Things, tag, return_varname) /* ITERATION MACROS -TAG_ITER_DECLARECOUNTER must be used before using the iterators. - -'level': -For each nested iteration, an additional TAG_ITER_DECLARECOUNTER -must be used with a different level number to avoid conflict with -the outer iterations. -Most cases don't have nested iterations and thus the level is just 0. - 'tag': Pretty much the elements' tag to iterate through. @@ -88,17 +96,12 @@ Target variable's name to return the iteration results to. EXAMPLE: { - TAG_ITER_DECLARECOUNTER(0); - TAG_ITER_DECLARECOUNTER(1); // For the nested iteration. - size_t li; - size_t sec; - INT32 tag1 = 4; ... - TAG_ITER_LINES(0, tag1, li) + TAG_ITER_LINES(tag1, li) { line_t *line = lines + li; @@ -106,11 +109,11 @@ EXAMPLE: if (something) { + size_t sec; mtag_t tag2 = 8; - // Nested iteration; just make sure the level is higher - // and that it has its own counter declared in scope. - TAG_ITER_SECTORS(1, tag2, sec) + // Nested iteration. + TAG_ITER_SECTORS(tag2, sec) { sector_t *sector = sectors + sec; diff --git a/src/tmap.nas b/src/tmap.nas index 69282d0b4..f096c8141 100644 --- a/src/tmap.nas +++ b/src/tmap.nas @@ -1,7 +1,7 @@ ;; SONIC ROBO BLAST 2 ;;----------------------------------------------------------------------------- ;; Copyright (C) 1998-2000 by DooM Legacy Team. -;; Copyright (C) 1999-2020 by Sonic Team Junior. +;; Copyright (C) 1999-2022 by Sonic Team Junior. ;; ;; This program is free software distributed under the ;; terms of the GNU General Public License, version 2. diff --git a/src/tmap.s b/src/tmap.s index 3a4cf2e1a..5bb2dea12 100644 --- a/src/tmap.s +++ b/src/tmap.s @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tmap_asm.s b/src/tmap_asm.s index 3cd0f87cc..8e307f42b 100644 --- a/src/tmap_asm.s +++ b/src/tmap_asm.s @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. diff --git a/src/tmap_mmx.nas b/src/tmap_mmx.nas index 15b97499d..5312f3c76 100644 --- a/src/tmap_mmx.nas +++ b/src/tmap_mmx.nas @@ -1,7 +1,7 @@ ;; SONIC ROBO BLAST 2 ;;----------------------------------------------------------------------------- ;; Copyright (C) 1998-2000 by DOSDOOM. -;; Copyright (C) 2010-2020 by Sonic Team Junior. +;; Copyright (C) 2010-2022 by Sonic Team Junior. ;; ;; This program is free software distributed under the ;; terms of the GNU General Public License, version 2. diff --git a/src/tmap_vc.nas b/src/tmap_vc.nas index 49eb21a6d..44b2d2e7b 100644 --- a/src/tmap_vc.nas +++ b/src/tmap_vc.nas @@ -1,7 +1,7 @@ ;; SONIC ROBO BLAST 2 ;;----------------------------------------------------------------------------- ;; Copyright (C) 1998-2000 by DooM Legacy Team. -;; Copyright (C) 1999-2020 by Sonic Team Junior. +;; Copyright (C) 1999-2022 by Sonic Team Junior. ;; ;; This program is free software distributed under the ;; terms of the GNU General Public License, version 2. diff --git a/src/v_video.c b/src/v_video.c index 4713db0d8..da725f78a 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -418,7 +418,7 @@ void V_SetPalette(INT32 palettenum) #ifdef HWRENDER if (rendermode == render_opengl) HWR_SetPalette(&pLocalPalette[palettenum*256]); -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) +#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) else #endif #endif @@ -432,7 +432,7 @@ void V_SetPaletteLump(const char *pal) #ifdef HWRENDER if (rendermode == render_opengl) HWR_SetPalette(pLocalPalette); -#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL) +#if defined (__unix__) || defined (UNIXCOMMON) || defined (HAVE_SDL) else #endif #endif @@ -455,7 +455,8 @@ void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, static void CV_constextsize_OnChange(void) { - con_recalc = true; + if (!con_refresh) + con_recalc = true; } @@ -510,7 +511,8 @@ static inline UINT8 transmappedpdraw(const UINT8 *dest, const UINT8 *source, fix void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap) { UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t); - UINT32 alphalevel = 0; + UINT32 alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT); + UINT32 blendmode = ((scrn & V_BLENDMASK) >> V_BLENDSHIFT); fixed_t col, ofs, colfrac, rowfrac, fdup, vdup; INT32 dupx, dupy; @@ -537,21 +539,21 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca patchdrawfunc = standardpdraw; v_translevel = NULL; - if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT))) + if (alphalevel || blendmode) { - if (alphalevel == 13) + if (alphalevel == 10) // V_HUDTRANSHALF alphalevel = hudminusalpha[st_translucency]; - else if (alphalevel == 14) + else if (alphalevel == 11) // V_HUDTRANS alphalevel = 10 - st_translucency; - else if (alphalevel == 15) + else if (alphalevel == 12) // V_HUDTRANSDOUBLE alphalevel = hudplusalpha[st_translucency]; if (alphalevel >= 10) return; // invis - if (alphalevel) + if (alphalevel || blendmode) { - v_translevel = R_GetTranslucencyTable(alphalevel); + v_translevel = R_GetBlendTable(blendmode+1, alphalevel); patchdrawfunc = translucentpdraw; } } @@ -590,10 +592,6 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca colfrac = FixedDiv(FRACUNIT, fdup); rowfrac = FixedDiv(FRACUNIT, vdup); - // So it turns out offsets aren't scaled in V_NOSCALESTART unless V_OFFSET is applied ...poo, that's terrible - // For now let's just at least give V_OFFSET the ability to support V_FLIP - // I'll probably make a better fix for 2.2 where I don't have to worry about breaking existing support for stuff - // -- Monster Iestyn 29/10/18 { fixed_t offsetx = 0, offsety = 0; @@ -604,15 +602,8 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca offsetx = FixedMul(patch->leftoffset<topoffset<> V_ALPHASHIFT); + UINT32 blendmode = ((scrn & V_BLENDMASK) >> V_BLENDSHIFT); // 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; @@ -829,7 +821,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 @@ -837,50 +829,75 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ patchdrawfunc = standardpdraw; v_translevel = NULL; - if ((alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT))) + if (alphalevel || blendmode) { - if (alphalevel == 13) + if (alphalevel == 10) // V_HUDTRANSHALF alphalevel = hudminusalpha[st_translucency]; - else if (alphalevel == 14) + else if (alphalevel == 11) // V_HUDTRANS alphalevel = 10 - st_translucency; - else if (alphalevel == 15) + else if (alphalevel == 12) // V_HUDTRANSDOUBLE alphalevel = hudplusalpha[st_translucency]; if (alphalevel >= 10) return; // invis - if (alphalevel) + if (alphalevel || blendmode) { - v_translevel = R_GetTranslucencyTable(alphalevel); + v_translevel = R_GetBlendTable(blendmode+1, alphalevel); patchdrawfunc = translucentpdraw; } } - // 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))) @@ -896,7 +913,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]) @@ -906,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 |= 4; y += adjusty; - sy += adjusty; scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT; } else //if (stplyr == &players[fourthdisplayplayer]) @@ -916,9 +931,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; } } @@ -937,7 +950,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; } } @@ -950,7 +962,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; @@ -998,7 +1011,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) @@ -1015,15 +1059,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); @@ -1358,11 +1402,11 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) if ((alphalevel = ((c & V_ALPHAMASK) >> V_ALPHASHIFT))) { - if (alphalevel == 13) + if (alphalevel == 10) // V_HUDTRANSHALF alphalevel = hudminusalpha[st_translucency]; - else if (alphalevel == 14) + else if (alphalevel == 11) // V_HUDTRANS alphalevel = 10 - st_translucency; - else if (alphalevel == 15) + else if (alphalevel == 12) // V_HUDTRANSDOUBLE alphalevel = hudplusalpha[st_translucency]; if (alphalevel >= 10) diff --git a/src/v_video.h b/src/v_video.h index 8a18f82ad..2831230a3 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -122,17 +122,23 @@ void V_CubeApply(UINT8 *red, UINT8 *green, UINT8 *blue); #define V_70TRANS 0x00070000 #define V_80TRANS 0x00080000 // used to be V_8020TRANS #define V_90TRANS 0x00090000 -#define V_HUDTRANSHALF 0x000D0000 -#define V_HUDTRANS 0x000E0000 // draw the hud translucent -#define V_HUDTRANSDOUBLE 0x000F0000 +#define V_HUDTRANSHALF 0x000A0000 +#define V_HUDTRANS 0x000B0000 // draw the hud translucent +#define V_HUDTRANSDOUBLE 0x000C0000 // Macros follow #define V_USERHUDTRANSHALF ((10-(cv_translucenthud.value/2))<handle); + if (wad->handle) + fclose(wad->handle); Z_Free(wad->filename); + if (wad->path) + Z_Free(wad->path); while (wad->numlumps--) { + if (wad->lumpinfo[wad->numlumps].diskpath) + Z_Free(wad->lumpinfo[wad->numlumps].diskpath); Z_Free(wad->lumpinfo[wad->numlumps].longname); Z_Free(wad->lumpinfo[wad->numlumps].fullname); } @@ -128,6 +134,8 @@ void W_Shutdown(void) Z_Free(wad->lumpinfo); Z_Free(wad); } + + Z_Free(wadfiles); } //=========================================================================== @@ -353,6 +361,7 @@ static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const lumpinfo->size = ftell(handle); fseek(handle, 0, SEEK_SET); strcpy(lumpinfo->name, lumpname); + lumpinfo->hash = quickncasehash(lumpname, 8); // Allocate the lump's long name. lumpinfo->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); @@ -421,6 +430,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; @@ -450,6 +460,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen lump_p->compression = CM_NOCOMPRESSION; memset(lump_p->name, 0x00, 9); strncpy(lump_p->name, fileinfo->name, 8); + lump_p->hash = quickncasehash(lump_p->name, 8); // Allocate the lump's long name. lump_p->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); @@ -602,6 +613,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); @@ -624,6 +636,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) memset(lump_p->name, '\0', 9); // Making sure they're initialized to 0. Is it necessary? strncpy(lump_p->name, trimname, min(8, dotpos - trimname)); + lump_p->hash = quickncasehash(lump_p->name, 8); lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL); strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); @@ -631,8 +644,6 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p->fullname = Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL); strncpy(lump_p->fullname, fullname, zentry.namelen); - free(fullname); - switch(zentry.compression) { case 0: @@ -652,6 +663,8 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) break; } + free(fullname); + // skip and ignore comments/extra fields if (fseek(handle, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) { @@ -679,6 +692,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 +815,19 @@ static UINT16 W_InitFileError (const char *filename, boolean exitworthy) return INT16_MAX; } +static void W_ReadFileShaders(wadfile_t *wadfile) +{ +#ifdef HWRENDER + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) + { + HWR_LoadCustomShadersFromFile(numwadfiles - 1, W_FileHasFolders(wadfile)); + HWR_CompileShaders(); + } +#else + (void)wadfile; +#endif +} + // Allocate a wadfile, setup the lumpinfo (directory) and // lumpcache, add the wadfile to the current active wadfiles // @@ -715,7 +849,6 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) #ifndef NOMD5 size_t i; #endif - size_t packetsize; UINT8 md5sum[16]; int important; @@ -733,9 +866,8 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) refreshdirname = NULL; //CONS_Debug(DBG_SETUP, "Loading %s\n", filename); - // - // check if limit of active wadfiles - // + + // Check if the game reached the limit of active wadfiles. if (numwadfiles >= MAX_WADFILES) { CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); @@ -755,24 +887,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) return INT16_MAX; } - // Check if wad files will overflow fileneededbuffer. Only the filename part - // is send in the packet; cf. - // see PutFileNeeded in d_netfil.c - if ((important = !important)) - { - packetsize = packetsizetally + nameonlylength(filename) + 22; - - if (packetsize > MAXFILENEEDED*sizeof(UINT8)) - { - CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); - refreshdirmenu |= REFRESHDIR_MAX; - if (handle) - fclose(handle); - return W_InitFileError(filename, startup); - } - - packetsizetally = packetsize; - } + important = !important; #ifndef NOMD5 // @@ -784,11 +899,12 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) for (i = 0; i < numwadfiles; i++) { + if (wadfiles[i]->type == RET_FOLDER) + continue; + if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) { CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); - if (important) - packetsizetally -= nameonlylength(filename) + 22; if (handle) fclose(handle); return W_InitFileError(filename, false); @@ -821,16 +937,21 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) } if (important && !mainfile) - G_SetGameModified(true); + { + //G_SetGameModified(true); + modifiedgame = true; // avoid savemoddata being set to false + } // // link wad file to search files // 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); @@ -850,17 +971,12 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // add the wadfile // CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps); + wadfiles = Z_Realloc(wadfiles, sizeof(wadfile_t) * (numwadfiles + 1), PU_STATIC, NULL); wadfiles[numwadfiles] = wadfile; numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded -#ifdef HWRENDER // Read shaders from file - if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) - { - HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3)); - HWR_CompileShaders(); - } -#endif // HWRENDER + W_ReadFileShaders(wadfile); // TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now. switch (wadfile->type) @@ -886,6 +1002,163 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) return wadfile->numlumps; } +// +// Loads a folder as a WAD. +// +UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup) +{ + lumpinfo_t *lumpinfo = NULL; + wadfile_t *wadfile; + UINT16 numlumps = 0; + UINT16 foldercount; + size_t i; + char *fn, *fullpath; + const char *p; + int important; + INT32 stat; + + if (!(refreshdirmenu & REFRESHDIR_ADDFILE)) + refreshdirmenu = REFRESHDIR_NORMAL|REFRESHDIR_ADDFILE; // clean out cons_alerts that happened earlier + + if (refreshdirname) + Z_Free(refreshdirname); + if (dirmenu) + refreshdirname = Z_StrDup(path); + else + refreshdirname = NULL; + + if (numwadfiles >= MAX_WADFILES) + { + CONS_Alert(CONS_ERROR, M_GetText("Maximum wad files reached\n")); + refreshdirmenu |= REFRESHDIR_MAX; + return W_InitFileError(path, startup); + } + + important = 0; /// \todo Implement a W_VerifyFolder. + + // Remove path delimiters. + p = path + (strlen(path) - 1); + + while (*p == '\\' || *p == '/' || *p == ':') + { + p--; + if (p < path) + { + CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), path); + return W_InitFileError(path, startup); + } + } + p++; + + // Allocate the new path name. + i = (p - path) + 1; + fn = ZZ_Alloc(i); + strlcpy(fn, path, i); + + // Don't add an empty path. + if (M_IsStringEmpty(fn)) + { + CONS_Alert(CONS_ERROR, M_GetText("Folder name is empty\n")); + Z_Free(fn); + + if (startup) + return W_InitFileError("A folder", true); + else + return W_InitFileError("a folder", false); + } + + // Check if the path is valid. + stat = W_IsPathToFolderValid(fn); + + if (stat != 1) + { + if (stat == 0) + CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn); + else if (stat < 0) + { +#ifndef AVOID_ERRNO + CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s: %s\n"), fn, strerror(direrror)); +#else + CONS_Alert(CONS_ERROR, M_GetText("Could not stat %s\n"), fn); +#endif + } + + Z_Free(fn); + return W_InitFileError(path, startup); + } + + // Get the full path for this folder. + fullpath = W_GetFullFolderPath(fn); + if (fullpath == NULL) + { + CONS_Alert(CONS_ERROR, M_GetText("Path %s is invalid\n"), fn); + Z_Free(fn); + return W_InitFileError(path, startup); + } + + // Check if the folder is already added. + for (i = 0; i < numwadfiles; i++) + { + if (wadfiles[i]->type != RET_FOLDER) + continue; + + if (samepaths(wadfiles[i]->path, fullpath) > 0) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), path); + Z_Free(fn); + Z_Free(fullpath); + return W_InitFileError(path, false); + } + } + + lumpinfo = ResGetLumpsFolder(fullpath, &numlumps, &foldercount); + + if (lumpinfo == NULL) + { + if (!numlumps) + CONS_Alert(CONS_ERROR, M_GetText("Folder %s is empty\n"), path); + else if (numlumps == UINT16_MAX) + CONS_Alert(CONS_ERROR, M_GetText("Folder %s contains too many files\n"), path); + else + CONS_Alert(CONS_ERROR, M_GetText("Unknown error enumerating files from folder %s\n"), path); + + Z_Free(fn); + Z_Free(fullpath); + + return W_InitFileError(path, startup); + } + + if (important && !mainfile) + G_SetGameModified(true); + + wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL); + wadfile->filename = fn; + wadfile->path = fullpath; + wadfile->type = RET_FOLDER; + wadfile->handle = NULL; + wadfile->numlumps = numlumps; + wadfile->foldercount = foldercount; + wadfile->lumpinfo = lumpinfo; + wadfile->important = important; + + // Irrelevant. + wadfile->filesize = 0; + memset(wadfile->md5sum, 0x00, 16); + + Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache); + Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); + + CONS_Printf(M_GetText("Added folder %s (%u files, %u folders)\n"), fn, numlumps, foldercount); + wadfiles[numwadfiles] = wadfile; + numwadfiles++; + + W_ReadFileShaders(wadfile); + W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile); + W_InvalidateLumpnumCache(); + + return wadfile->numlumps; +} + /** Tries to load a series of files. * All files are wads unless they have an extension of ".soc" or ".lua". * @@ -895,13 +1168,22 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) * * \param filenames A null-terminated list of files to use. */ -void W_InitMultipleFiles(char **filenames) +void W_InitMultipleFiles(addfilelist_t *list) { - // will be realloced as lumps are added - for (; *filenames; filenames++) + size_t i = 0; + + for (; i < list->numfiles; i++) { - //CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames); - W_InitFile(*filenames, numwadfiles < mainwads, true); + const char *fn = list->files[i]; + char pathsep = fn[strlen(fn) - 1]; + boolean mainfile = (numwadfiles < mainwads); + + //CONS_Debug(DBG_SETUP, "Loading %s\n", fn); + + if (pathsep == '\\' || pathsep == '/') + W_InitFolder(fn, mainfile, true); + else + W_InitFile(fn, mainfile, true); } } @@ -910,7 +1192,7 @@ void W_InitMultipleFiles(char **filenames) */ static boolean TestValidLump(UINT16 wad, UINT16 lump) { - I_Assert(wad < MAX_WADFILES); + I_Assert(wad < numwadfiles); if (!wadfiles[wad]) // make sure the wad file exists return false; @@ -946,12 +1228,14 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { UINT16 i; static char uname[8 + 1]; + UINT32 hash; if (!TestValidLump(wad,0)) return INT16_MAX; strlcpy(uname, name, sizeof uname); strupr(uname); + hash = quickncasehash(uname, 8); // // scan forward @@ -962,7 +1246,7 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) - if (!strncmp(lump_p->name, uname, sizeof(uname) - 1)) + if (lump_p->hash == hash && !strncmp(lump_p->name, uname, sizeof(uname) - 1)) return i; } @@ -1165,17 +1449,22 @@ lumpnum_t W_CheckNumForLongName(const char *name) // TODO: Make it search through cache first, maybe...? lumpnum_t W_CheckNumForMap(const char *name) { + UINT32 hash = quickncasehash(name, 8); UINT16 lumpNum, end; UINT32 i; + lumpinfo_t *p; for (i = numwadfiles - 1; i < numwadfiles; i--) { if (wadfiles[i]->type == RET_WAD) { for (lumpNum = 0; lumpNum < wadfiles[i]->numlumps; lumpNum++) - if (!strncmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) + { + p = wadfiles[i]->lumpinfo + lumpNum; + if (p->hash == hash && !strncmp(name, p->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) @@ -1184,8 +1473,15 @@ lumpnum_t W_CheckNumForMap(const char *name) continue; // Now look for the specified map. for (; lumpNum < end; lumpNum++) - if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) - return (i<<16) + lumpNum; + { + p = wadfiles[i]->lumpinfo + lumpNum; + if (p->hash == hash && !strnicmp(name, p->name, 8)) + { + const char *extension = strrchr(p->fullname, '.'); + if (!(extension && stricmp(extension, ".wad"))) + return (i<<16) + lumpNum; + } + } } } return LUMPERROR; @@ -1273,9 +1569,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. @@ -1290,11 +1623,11 @@ size_t W_LumpLength(lumpnum_t lumpnum) // // W_IsLumpWad -// Is the lump a WAD? (presumably in a PK3) +// Is the lump a WAD? (presumably not in a WAD) // boolean W_IsLumpWad(lumpnum_t lumpnum) { - if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3) + if (W_FileHasFolders(wadfiles[WADFILENUM(lumpnum)])) { const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname; @@ -1303,23 +1636,23 @@ boolean W_IsLumpWad(lumpnum_t lumpnum) return !strnicmp(lumpfullName + strlen(lumpfullName) - 4, ".wad", 4); } - return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned + return false; // WADs should never be inside WADs as far as SRB2 is concerned } // // W_IsLumpFolder -// Is the lump a folder? (in a PK3 obviously) +// Is the lump a folder? (not in a WAD obviously) // boolean W_IsLumpFolder(UINT16 wad, UINT16 lump) { - if (wadfiles[wad]->type == RET_PK3) + if (W_FileHasFolders(wadfiles[wad])) { const char *name = wadfiles[wad]->lumpinfo[lump].fullname; return (name[strlen(name)-1] == '/'); // folders end in '/' } - return false; // non-PK3s don't have folders + return false; // WADs don't have folders } #ifdef HAVE_ZLIB @@ -1362,17 +1695,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) @@ -1380,24 +1751,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 @@ -1682,26 +2051,12 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) // read the lump in full W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); + ptr = lumpdata; #ifndef NO_PNG_LUMPS - // lump is a png so convert it if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) - { - size_t newlen; - void *converted = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &newlen, 0); - ptr = Z_Malloc(newlen, PU_STATIC, NULL); - M_Memcpy(ptr, converted, newlen); - Z_Free(converted); - len = newlen; - } - else // just copy it into the patch cache + ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0); #endif - { - ptr = Z_Malloc(len, PU_STATIC, NULL); - M_Memcpy(ptr, lumpdata, len); - } - - Z_Free(lumpdata); dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]); Patch_Create(ptr, len, dest); @@ -1849,7 +2204,7 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5) #else I_Error #endif - (M_GetText("File is old, is corrupt or has been modified: %s (found md5: %s, wanted: %s)\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5); + (M_GetText("File is old, is corrupt or has been modified:\n%s\nFound MD5: %s\nWanted MD5: %s\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5); } #endif } @@ -2128,6 +2483,10 @@ int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error) {"STNONEX", 7}, // "X" graphic {"ULTIMATE", 8}, // Ultimate no-save + {"SLCT", 4}, // Level select "cursor" + {"LSSTATIC", 8}, // Level select static + {"BLANKLV", 7}, // "?" level images + {"CRFNT", 5}, // Sonic 1 font changes {"NTFNT", 5}, // Character Select font changes {"NTFNO", 5}, // Character Select font (outline) @@ -2139,12 +2498,23 @@ int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error) {"STLIVE", 6}, // Life graphics, background and the "X" that shows under skin's HUDNAME {"CROSHAI", 7}, // First person crosshairs {"INTERSC", 7}, // Default intermission backgrounds (co-op) + {"SPECTILE", 8}, // Special stage intermission background {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"YB_", 3}, // Intermission graphics, goes with the above {"RESULT", 6}, // Used in intermission for competitive modes, above too :3 {"RACE", 4}, // Race mode graphics, 321go + {"SRB2BACK", 8}, // MP intermission background {"M_", 2}, // Menu stuff {"LT", 2}, // Titlecard changes + {"HOMING", 6}, // Emerald hunt radar + {"HOMITM", 6}, // Emblem radar + + {"CHARFG", 6}, // Character select menu + {"CHARBG", 6}, + {"RECATK", 6}, // Record Attack menu + {"RECCLOCK", 8}, + {"NTSATK", 6}, // NiGHTS Mode menu + {"NTSSONC", 7}, {"SLID", 4}, // Continue {"CONT", 4}, @@ -2168,6 +2538,7 @@ int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error) {"DRILL", 5}, {"GRADE", 5}, {"MINUS5", 6}, + {"NGRTIMER", 8}, // NiGHTS Mode timer {"MUSICDEF", 8}, // Song definitions (thanks kart) {"SHADERS", 7}, // OpenGL shader definitions diff --git a/src/w_wad.h b/src/w_wad.h index d0a86bcb4..c4de55d77 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -67,8 +67,10 @@ typedef struct unsigned long position; // filelump_t filepos unsigned long disksize; // filelump_t size char name[9]; // filelump_t name[] e.g. "LongEntr" + UINT32 hash; char *longname; // e.g. "LongEntryName" char *fullname; // e.g. "Folder/Subfolder/LongEntryName.extension" + char *diskpath; // path to the file e.g. "/usr/games/srb2/Addon/Folder/Subfolder/LongEntryName.extension" size_t size; // real (uncompressed) size compmethod compression; // lump compression method } lumpinfo_t; @@ -96,9 +98,15 @@ virtlump_t* vres_Find(const virtres_t*, const char*); // DYNAMIC WAD LOADING // ========================================================================= +// Maximum of files that can be loaded +// (there is a max of simultaneous open files anyway) +#ifdef ENFORCE_WAD_LIMIT +#define MAX_WADFILES 2048 // This cannot be any higher than UINT16_MAX. +#else +#define MAX_WADFILES UINT16_MAX +#endif + #define MAX_WADPATH 512 -#define MAX_WADFILES 48 // maximum of wad files used at the same time -// (there is a max of simultaneous open files anyway, and this should be plenty) #define lumpcache_t void * @@ -109,17 +117,19 @@ typedef enum restype RET_SOC, RET_LUA, RET_PK3, + RET_FOLDER, RET_UNKNOWN, } restype_t; typedef struct wadfile_s { - char *filename; + char *filename, *path; restype_t type; lumpinfo_t *lumpinfo; lumpcache_t *lumpcache; lumpcache_t *patchcache; UINT16 numlumps; // this wad's number of resources + UINT16 foldercount; // folder count FILE *handle; UINT32 filesize; // for network UINT8 md5sum[16]; @@ -127,11 +137,17 @@ typedef struct wadfile_s boolean important; // also network - !W_VerifyNMUSlumps } wadfile_t; -#define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad flumpnum>>16) // wad file number in upper word +#define WADFILENUM(lumpnum) (UINT16)((lumpnum)>>16) // wad file number in upper word #define LUMPNUM(lumpnum) (UINT16)((lumpnum)&0xFFFF) // lump number for this pwad extern UINT16 numwadfiles; -extern wadfile_t *wadfiles[MAX_WADFILES]; +extern wadfile_t **wadfiles; + +typedef struct +{ + char **files; + size_t numfiles; +} addfilelist_t; // ========================================================================= @@ -141,9 +157,16 @@ void W_Shutdown(void); FILE *W_OpenWadFile(const char **filename, boolean useerrors); // Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup); +// Adds a folder as a file +UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup); // W_InitMultipleFiles exits if a file was not found, but not if all is okay. -void W_InitMultipleFiles(char **filenames); +void W_InitMultipleFiles(addfilelist_t *list); + +#define W_FileHasFolders(wadfile) ((wadfile)->type == RET_PK3 || (wadfile)->type == RET_FOLDER) + +INT32 W_IsPathToFolderValid(const char *path); +char *W_GetFullFolderPath(const char *path); const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump); const char *W_CheckNameForNum(lumpnum_t lumpnum); diff --git a/src/win32/CMakeLists.txt b/src/win32/CMakeLists.txt deleted file mode 100644 index 39b01588b..000000000 --- a/src/win32/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -file(GLOB SRB2_WIN_SOURCES *.c *.h *.rc) - -if(${SRB2_CONFIG_HWRENDER}) - set(SRB2_WIN_SOURCES ${SRB2_WIN_SOURCES} ${SRB2_HWRENDER_SOURCES} ${SRB2_HWRENDER_HEADERS}) - set(SRB2_WIN_SOURCES ${SRB2_WIN_SOURCES} ${SRB2_R_OPENGL_SOURCES} ${SRB2_R_OPENGL_HEADERS}) -endif() - -add_executable(SRB2DD EXCLUDE_FROM_ALL WIN32 - ${SRB2_WIN_SOURCES} -) - -target_compile_definitions(SRB2DD PRIVATE - -D_WINDOWS -) - -set_target_properties(SRB2DD PROPERTIES OUTPUT_NAME ${SRB2_WIN_EXE_NAME}) - -target_link_libraries(SRB2DD PRIVATE SRB2Core) diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg deleted file mode 100644 index 702ae3765..000000000 --- a/src/win32/Makefile.cfg +++ /dev/null @@ -1,136 +0,0 @@ -# -# win32/Makefile.cfg for SRB2/Minwgw -# - -# -#Mingw, if you don't know, that's Win32/Win64 -# - -ifdef MINGW64 - HAVE_LIBGME=1 - LIBGME_CFLAGS=-I../libs/gme/include - LIBGME_LDFLAGS=-L../libs/gme/win64 -lgme -ifdef HAVE_OPENMPT - LIBOPENMPT_CFLAGS?=-I../libs/libopenmpt/inc - LIBOPENMPT_LDFLAGS?=-L../libs/libopenmpt/lib/x86_64/mingw -lopenmpt -endif -ifndef NOMIXERX - HAVE_MIXERX=1 - SDL_CFLAGS?=-I../libs/SDL2/x86_64-w64-mingw32/include/SDL2 -I../libs/SDLMixerX/x86_64-w64-mingw32/include/SDL2 -Dmain=SDL_main - SDL_LDFLAGS?=-L../libs/SDL2/x86_64-w64-mingw32/lib -L../libs/SDLMixerX/x86_64-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows -else - SDL_CFLAGS?=-I../libs/SDL2/x86_64-w64-mingw32/include/SDL2 -I../libs/SDL2_mixer/x86_64-w64-mingw32/include/SDL2 -Dmain=SDL_main - SDL_LDFLAGS?=-L../libs/SDL2/x86_64-w64-mingw32/lib -L../libs/SDL2_mixer/x86_64-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows -endif -else - HAVE_LIBGME=1 - LIBGME_CFLAGS=-I../libs/gme/include - LIBGME_LDFLAGS=-L../libs/gme/win32 -lgme -ifdef HAVE_OPENMPT - LIBOPENMPT_CFLAGS?=-I../libs/libopenmpt/inc - LIBOPENMPT_LDFLAGS?=-L../libs/libopenmpt/lib/x86/mingw -lopenmpt -endif -ifndef NOMIXERX - HAVE_MIXERX=1 - SDL_CFLAGS?=-I../libs/SDL2/i686-w64-mingw32/include/SDL2 -I../libs/SDLMixerX/i686-w64-mingw32/include/SDL2 -Dmain=SDL_main - SDL_LDFLAGS?=-L../libs/SDL2/i686-w64-mingw32/lib -L../libs/SDLMixerX/i686-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows -else - SDL_CFLAGS?=-I../libs/SDL2/i686-w64-mingw32/include/SDL2 -I../libs/SDL2_mixer/i686-w64-mingw32/include/SDL2 -Dmain=SDL_main - SDL_LDFLAGS?=-L../libs/SDL2/i686-w64-mingw32/lib -L../libs/SDL2_mixer/i686-w64-mingw32/lib -lmingw32 -lSDL2main -lSDL2 -mwindows -endif -endif - -ifndef NOASM - USEASM=1 -endif - -ifndef NONET -ifndef MINGW64 #miniupnc is broken with MINGW64 - HAVE_MINIUPNPC=1 -endif -endif - - OPTS=-DSTDC_HEADERS - -ifndef GCC44 - #OPTS+=-mms-bitfields -endif - - LIBS+=-ladvapi32 -lkernel32 -lmsvcrt -luser32 -ifdef MINGW64 - LIBS+=-lws2_32 -else -ifdef NO_IPV6 - LIBS+=-lwsock32 -else - LIBS+=-lws2_32 -endif -endif - - # name of the exefile - EXENAME?=srb2win.exe - -ifdef SDL - i_system_o+=$(OBJDIR)/SRB2.res - #i_main_o+=$(OBJDIR)/win_dbg.o -ifndef NOHW - OPTS+=-DUSE_WGL_SWAP -endif -endif - - -ZLIB_CFLAGS?=-I../libs/zlib -ifdef MINGW64 -ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz64 -else -ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz32 -endif - -ifndef NOPNG -ifndef PNG_CONFIG - PNG_CFLAGS?=-I../libs/libpng-src -ifdef MINGW64 - PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng64 -else - PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng32 -endif #MINGW64 -endif #PNG_CONFIG -endif #NOPNG - -ifdef GETTEXT -ifndef CCBS - MSGFMT?=../libs/gettext/bin32/msgfmt.exe -endif -ifdef MINGW64 - CPPFLAGS+=-I../libs/gettext/include64 - LDFLAGS+=-L../libs/gettext/lib64 - LIBS+=-lmingwex -else - CPPFLAGS+=-I../libs/gettext/include32 - LDFLAGS+=-L../libs/gettext/lib32 - STATIC_GETTEXT=1 -endif #MINGW64 -ifdef STATIC_GETTEXT - LIBS+=-lasprintf -lintl -else - LIBS+=-lintl.dll -endif #STATIC_GETTEXT -endif #GETTEXT - -ifdef HAVE_MINIUPNPC - CPPFLAGS+=-I../libs/ -DSTATIC_MINIUPNPC -ifdef MINGW64 - LDFLAGS+=-L../libs/miniupnpc/mingw64 -else - LDFLAGS+=-L../libs/miniupnpc/mingw32 -endif #MINGW64 -endif - -ifndef NOCURL - CURL_CFLAGS+=-I../libs/curl/include -ifdef MINGW64 - CURL_LDFLAGS+=-L../libs/curl/lib64 -lcurl -else - CURL_LDFLAGS+=-L../libs/curl/lib32 -lcurl -endif #MINGW64 -endif diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj deleted file mode 100644 index 3e8af3b0e..000000000 --- a/src/win32/Srb2win-vc10.vcxproj +++ /dev/null @@ -1,517 +0,0 @@ - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - Srb2DD - {0F554F1D-ED49-4D65-A9A7-F63C57F277BE} - Win32Proj - Srb2win - 10.0.17763.0 - - - - v140 - true - - - true - true - v141 - - - v140 - false - true - - - false - true - true - v141 - - - v140 - true - - - true - true - v141 - - - v140 - false - true - - - false - true - true - v141 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - false - - - - true - gdi32.lib;%(AdditionalDependencies) - - - ProgramDatabase - false - - - - - true - gdi32.lib;%(AdditionalDependencies) - - - - - ProgramDatabase - false - - - gdi32.lib;%(AdditionalDependencies) - - - - - gdi32.lib;%(AdditionalDependencies) - - - - - gdi32.lib;%(AdditionalDependencies) - - - - - gdi32.lib;%(AdditionalDependencies) - - - - - gdi32.lib;%(AdditionalDependencies) - - - - - gdi32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {72b01aca-7a1a-4f7b-acef-2607299cf052} - - - {73a5729c-7323-41d4-ab48-8a03c9f81603} - - - - - - - Document - - - Document - - - Document - - - - - - diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters deleted file mode 100644 index 7279368f1..000000000 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ /dev/null @@ -1,943 +0,0 @@ - - - - - {20cba664-c3ef-48f1-85dd-42aafd5345cc} - - - {d3817a65-82f5-4989-9217-e5a7f43380a0} - - - {9c3ed4ae-dbed-4d00-a164-b8bb7fc1710c} - - - {4b8a8fb6-7c84-48c2-85d1-0583e6b8cacd} - - - {1907eee5-0ebf-4325-a2fa-793f089ed2e3} - - - {b9e78a3f-3e2b-4f89-9817-b77c7a26d2aa} - - - {3f336df5-a1d7-4610-9728-4525e42c0abc} - - - {b5090aa0-6645-4091-aa1a-ffc3bf4dc422} - - - {d59e82c9-68e5-44bf-827e-f7bb1676cd6c} - - - {29e746a2-3d91-4b69-af6e-5e03895516b7} - - - {b295d364-61c3-4ebb-9b68-7d6c0bb891be} - - - {ba258ec5-13d7-4083-98bd-c2ee58700b66} - - - {6163f1e5-da5d-4af2-b92c-753452f9e1d0} - - - {077b0966-1151-4afa-a533-120a4c931322} - - - {bded90bc-8019-42b1-ba19-32166743d3e3} - - - {c0ddfdb5-7494-4cca-b2ad-cb048be9cbdf} - - - {d5157f99-43ef-49cc-ad76-658a1168fc0d} - - - {2cedf139-53a1-40ea-b4de-19e9f4505a1f} - - - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - G_Game - - - G_Game - - - F_Frame - - - F_Frame - - - I_Interface - - - I_Interface - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - LUA - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - H_Hud - - - B_Bots - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - S_Sounds - - - W_Wad - - - W_Wad - - - S_Sounds - - - O_Other - - - H_Hud - - - H_Hud - - - I_Interface - - - H_Hud - - - P_Play - - - I_Interface - - - H_Hud - - - R_Rend - - - R_Rend - - - H_Hud - - - D_Doom - - - M_Misc - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Win32app - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - Hw_Hardware - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - BLUA - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - D_Doom - - - G_Game - - - G_Game - - - G_Game - - - F_Frame - - - I_Interface - - - I_Interface - - - I_Interface - - - I_Interface - - - I_Interface - - - I_Interface - - - I_Interface - - - LUA - - - LUA - - - LUA - - - LUA - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - M_Misc - - - H_Hud - - - B_Bots - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - P_Play - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - P_Play - - - S_Sounds - - - W_Wad - - - W_Wad - - - I_Interface - - - S_Sounds - - - O_Other - - - I_Interface - - - H_Hud - - - H_Hud - - - I_Interface - - - I_Interface - - - H_Hud - - - P_Play - - - I_Interface - - - A_Asm - - - H_Hud - - - R_Rend - - - R_Rend - - - H_Hud - - - D_Doom - - - O_Other - - - Hw_Hardware - - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - R_Rend - - - - - Win32app - - - - - Win32app - - - - - A_Asm - - - O_Other - - - - - A_Asm - - - A_Asm - - - A_Asm - - - diff --git a/src/win32/Srb2win-vc9.vcproj b/src/win32/Srb2win-vc9.vcproj deleted file mode 100644 index c1c6b5bc4..000000000 --- a/src/win32/Srb2win-vc9.vcproj +++ /dev/null @@ -1,4914 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/win32/Srb2win.dsp b/src/win32/Srb2win.dsp deleted file mode 100644 index 661f3eaf9..000000000 --- a/src/win32/Srb2win.dsp +++ /dev/null @@ -1,1008 +0,0 @@ -# Microsoft Developer Studio Project File - Name="Srb2win" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=Srb2win - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "Srb2win.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "Srb2win.mak" CFG="Srb2win - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "Srb2win - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "Srb2win - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "Srb2win - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "..\..\objs\Release" -# PROP BASE Intermediate_Dir "..\..\objs\Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\..\bin\VC\Release\Win32" -# PROP Intermediate_Dir "..\..\objs\VC\Release\Win32" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /G5 /W3 /GX /Zi /Ot /Og /Oi /Op /Oy /Ob1 /Gy /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "NDEBUG" /D "_WINDOWS" /D "USEASM" /D "HAVE_PNG" /FR /FD /GF /Gs /GF /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 -# ADD MTL /nologo /D "NDEBUG" /o "NUL" /win32 -# SUBTRACT MTL /mktyplib203 -# ADD BASE RSC /l 0x40c /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo /o"..\..\objs\Release\Srb2win.bsc" -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 dxguid.lib user32.lib gdi32.lib winmm.lib advapi32.lib ws2_32.lib dinput.lib /nologo /subsystem:windows /pdb:"C:\srb2demo2\srb2.pdb" /debug /machine:I386 /out:"C:\srb2demo2\srb2win.exe" -# SUBTRACT LINK32 /profile /pdb:none /incremental:yes /nodefaultlib - -!ELSEIF "$(CFG)" == "Srb2win - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "..\..\objs\Debug" -# PROP BASE Intermediate_Dir "..\..\objs\Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\..\bin\VC\Debug\Win32" -# PROP Intermediate_Dir "..\..\objs\VC\Debug\Win32" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c -# ADD CPP /nologo /G6 /W4 /Gm /GX /ZI /Od /Op /Oy /I "libs\libpng-src" /I "..\..\libs\libpng-src" /I "..\..\libs\zlib" /D "_DEBUG" /D "_WINDOWS" /D "USEASM" /D "HAVE_PNG" /FAcs /FR /FD /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 -# ADD BASE RSC /l 0x40c /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 dxguid.lib user32.lib gdi32.lib winmm.lib advapi32.lib ws2_32.lib dinput.lib /nologo /subsystem:windows /profile /debug /machine:I386 /out:"C:\srb2demo2\srb2debug.exe" -# SUBTRACT LINK32 /nodefaultlib - -!ENDIF - -# Begin Target - -# Name "Srb2win - Win32 Release" -# Name "Srb2win - Win32 Debug" -# Begin Group "Win32app" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=.\afxres.h -# End Source File -# Begin Source File - -SOURCE=.\dx_error.c -# End Source File -# Begin Source File - -SOURCE=.\dx_error.h -# End Source File -# Begin Source File - -SOURCE=.\fabdxlib.c -# End Source File -# Begin Source File - -SOURCE=.\fabdxlib.h -# End Source File -# Begin Source File - -SOURCE=..\filesrch.c -# End Source File -# Begin Source File - -SOURCE=..\filesrch.h -# End Source File -# Begin Source File - -SOURCE=.\mid2strm.c -# End Source File -# Begin Source File - -SOURCE=.\mid2strm.h -# End Source File -# Begin Source File - -SOURCE=.\midstuff.h -# End Source File -# Begin Source File - -SOURCE=.\resource.h -# End Source File -# Begin Source File - -SOURCE=.\Srb2win.rc - -!IF "$(CFG)" == "Srb2win - Win32 Release" - -# ADD BASE RSC /l 0x40c /i "win32" -# ADD RSC /l 0x409 /i "win32" - -!ELSEIF "$(CFG)" == "Srb2win - Win32 Debug" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=.\win_cd.c -# End Source File -# Begin Source File - -SOURCE=.\win_dbg.c -# End Source File -# Begin Source File - -SOURCE=.\win_dbg.h -# End Source File -# Begin Source File - -SOURCE=.\win_dll.c -# End Source File -# Begin Source File - -SOURCE=.\win_dll.h -# End Source File -# Begin Source File - -SOURCE=.\win_main.c -# End Source File -# Begin Source File - -SOURCE=.\win_main.h -# End Source File -# Begin Source File - -SOURCE=.\win_net.c -# End Source File -# Begin Source File - -SOURCE=.\win_snd.c -# End Source File -# Begin Source File - -SOURCE=.\win_sys.c -# End Source File -# Begin Source File - -SOURCE=.\win_vid.c -# End Source File -# End Group -# Begin Group "A_Asm" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\p5prof.h -# End Source File -# Begin Source File - -SOURCE=..\tmap.nas - -!IF "$(CFG)" == "Srb2win - Win32 Release" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Release\Win32 -InputPath=..\tmap.nas -InputName=tmap - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Srb2win - Win32 Debug" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Debug\Win32 -InputPath=..\tmap.nas -InputName=tmap - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\tmap_mmx.nas - -!IF "$(CFG)" == "Srb2win - Win32 Release" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Release\Win32 -InputPath=..\tmap_mmx.nas -InputName=tmap_mmx - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Srb2win - Win32 Debug" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Debug\Win32 -InputPath=..\tmap_mmx.nas -InputName=tmap_mmx - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\tmap_vc.nas - -!IF "$(CFG)" == "Srb2win - Win32 Release" - -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Release\Win32 -InputPath=..\tmap_vc.nas -InputName=tmap_vc - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ELSEIF "$(CFG)" == "Srb2win - Win32 Debug" - -# PROP Ignore_Default_Tool 1 -# Begin Custom Build - Compiling $(InputName).nas with NASM... -IntDir=.\..\..\objs\VC\Debug\Win32 -InputPath=..\tmap_vc.nas -InputName=tmap_vc - -"$(IntDir)/$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - nasm -g -o $(IntDir)/$(InputName).obj -f win32 $(InputPath) - -# End Custom Build - -!ENDIF - -# End Source File -# End Group -# Begin Group "D_Doom" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\comptime.c -# End Source File -# Begin Source File - -SOURCE=..\d_clisrv.c -# End Source File -# Begin Source File - -SOURCE=..\d_clisrv.h -# End Source File -# Begin Source File - -SOURCE=..\d_event.h -# End Source File -# Begin Source File - -SOURCE=..\d_main.c -# End Source File -# Begin Source File - -SOURCE=..\d_main.h -# End Source File -# Begin Source File - -SOURCE=..\d_net.c -# End Source File -# Begin Source File - -SOURCE=..\d_net.h -# End Source File -# Begin Source File - -SOURCE=..\d_netcmd.c -# End Source File -# Begin Source File - -SOURCE=..\d_netcmd.h -# End Source File -# Begin Source File - -SOURCE=..\d_netfil.c -# End Source File -# Begin Source File - -SOURCE=..\d_netfil.h -# End Source File -# Begin Source File - -SOURCE=..\d_player.h -# End Source File -# Begin Source File - -SOURCE=..\d_think.h -# End Source File -# Begin Source File - -SOURCE=..\d_ticcmd.h -# End Source File -# Begin Source File - -SOURCE=..\dehacked.c -# End Source File -# Begin Source File - -SOURCE=..\dehacked.h -# End Source File -# Begin Source File - -SOURCE=..\doomdata.h -# End Source File -# Begin Source File - -SOURCE=..\doomdef.h -# End Source File -# Begin Source File - -SOURCE=..\doomstat.h -# End Source File -# Begin Source File - -SOURCE=..\doomtype.h -# End Source File -# Begin Source File - -SOURCE=..\z_zone.c -# End Source File -# Begin Source File - -SOURCE=..\z_zone.h -# End Source File -# End Group -# Begin Group "F_Frame" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\f_finale.c -# End Source File -# Begin Source File - -SOURCE=..\f_finale.h -# End Source File -# Begin Source File - -SOURCE=..\f_wipe.c -# End Source File -# End Group -# Begin Group "G_Game" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\g_game.c -# End Source File -# Begin Source File - -SOURCE=..\g_game.h -# End Source File -# Begin Source File - -SOURCE=..\g_input.c -# End Source File -# Begin Source File - -SOURCE=..\g_input.h -# End Source File -# Begin Source File - -SOURCE=..\g_state.h -# End Source File -# End Group -# Begin Group "H_Hud" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\am_map.c -# End Source File -# Begin Source File - -SOURCE=..\am_map.h -# End Source File -# Begin Source File - -SOURCE=..\command.c -# End Source File -# Begin Source File - -SOURCE=..\command.h -# End Source File -# Begin Source File - -SOURCE=..\console.c -# End Source File -# Begin Source File - -SOURCE=..\console.h -# End Source File -# Begin Source File - -SOURCE=..\hu_stuff.c -# End Source File -# Begin Source File - -SOURCE=..\hu_stuff.h -# End Source File -# Begin Source File - -SOURCE=..\st_stuff.c -# End Source File -# Begin Source File - -SOURCE=..\st_stuff.h -# End Source File -# Begin Source File - -SOURCE=..\y_inter.c -# End Source File -# Begin Source File - -SOURCE=..\y_inter.h -# End Source File -# End Group -# Begin Group "Hw_Hardware" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\hardware\hw3dsdrv.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw3sound.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw3sound.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_bsp.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_cache.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_data.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_defs.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_dll.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_draw.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_drv.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_glob.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_light.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_light.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_main.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_main.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_md2.c -# End Source File -# Begin Source File - -SOURCE=..\hardware\hw_md2.h -# End Source File -# Begin Source File - -SOURCE=..\hardware\hws_data.h -# End Source File -# End Group -# Begin Group "I_Interface" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\byteptr.h -# End Source File -# Begin Source File - -SOURCE=..\i_joy.h -# End Source File -# Begin Source File - -SOURCE=..\i_net.h -# End Source File -# Begin Source File - -SOURCE=..\i_sound.h -# End Source File -# Begin Source File - -SOURCE=..\i_system.h -# End Source File -# Begin Source File - -SOURCE=..\i_tcp.c -# End Source File -# Begin Source File - -SOURCE=..\i_tcp.h -# End Source File -# Begin Source File - -SOURCE=..\i_video.h -# End Source File -# Begin Source File - -SOURCE=..\keys.h -# End Source File -# Begin Source File - -SOURCE=..\mserv.c -# End Source File -# Begin Source File - -SOURCE=..\mserv.h -# End Source File -# End Group -# Begin Group "M_Misc" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\m_argv.c -# End Source File -# Begin Source File - -SOURCE=..\m_argv.h -# End Source File -# Begin Source File - -SOURCE=..\m_bbox.c -# End Source File -# Begin Source File - -SOURCE=..\m_bbox.h -# End Source File -# Begin Source File - -SOURCE=..\m_cheat.c -# End Source File -# Begin Source File - -SOURCE=..\m_cheat.h -# End Source File -# Begin Source File - -SOURCE=..\m_dllist.h -# End Source File -# Begin Source File - -SOURCE=..\m_fixed.c -# End Source File -# Begin Source File - -SOURCE=..\m_fixed.h -# End Source File -# Begin Source File - -SOURCE=..\m_menu.c -# End Source File -# Begin Source File - -SOURCE=..\m_menu.h -# End Source File -# Begin Source File - -SOURCE=..\m_misc.c -# End Source File -# Begin Source File - -SOURCE=..\m_misc.h -# End Source File -# Begin Source File - -SOURCE=..\m_queue.c -# End Source File -# Begin Source File - -SOURCE=..\m_queue.h -# End Source File -# Begin Source File - -SOURCE=..\m_random.c -# End Source File -# Begin Source File - -SOURCE=..\m_random.h -# End Source File -# Begin Source File - -SOURCE=..\m_swap.h -# End Source File -# Begin Source File - -SOURCE=..\string.c -# End Source File -# End Group -# Begin Group "P_Play" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\info.c -# End Source File -# Begin Source File - -SOURCE=..\info.h -# End Source File -# Begin Source File - -SOURCE=..\p_ceilng.c -# End Source File -# Begin Source File - -SOURCE=..\p_enemy.c -# End Source File -# Begin Source File - -SOURCE=..\p_fab.c -# End Source File -# Begin Source File - -SOURCE=..\p_floor.c -# End Source File -# Begin Source File - -SOURCE=..\p_inter.c -# End Source File -# Begin Source File - -SOURCE=..\p_lights.c -# End Source File -# Begin Source File - -SOURCE=..\p_local.h -# End Source File -# Begin Source File - -SOURCE=..\p_map.c -# End Source File -# Begin Source File - -SOURCE=..\p_maputl.c -# End Source File -# Begin Source File - -SOURCE=..\p_maputl.h -# End Source File -# Begin Source File - -SOURCE=..\p_mobj.c -# End Source File -# Begin Source File - -SOURCE=..\p_mobj.h -# End Source File -# Begin Source File - -SOURCE=..\p_polyobj.c -# End Source File -# Begin Source File - -SOURCE=..\p_polyobj.h -# End Source File -# Begin Source File - -SOURCE=..\p_pspr.h -# End Source File -# Begin Source File - -SOURCE=..\p_saveg.c -# End Source File -# Begin Source File - -SOURCE=..\p_saveg.h -# End Source File -# Begin Source File - -SOURCE=..\p_setup.c -# End Source File -# Begin Source File - -SOURCE=..\p_setup.h -# End Source File -# Begin Source File - -SOURCE=..\p_sight.c -# End Source File -# Begin Source File - -SOURCE=..\p_spec.c -# End Source File -# Begin Source File - -SOURCE=..\p_spec.h -# End Source File -# Begin Source File - -SOURCE=..\p_telept.c -# End Source File -# Begin Source File - -SOURCE=..\p_tick.c -# End Source File -# Begin Source File - -SOURCE=..\p_tick.h -# End Source File -# Begin Source File - -SOURCE=..\p_user.c -# End Source File -# Begin Source File - -SOURCE=..\tables.c -# End Source File -# Begin Source File - -SOURCE=..\tables.h -# End Source File -# End Group -# Begin Group "R_Rend" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\r_bsp.c -# End Source File -# Begin Source File - -SOURCE=..\r_bsp.h -# End Source File -# Begin Source File - -SOURCE=..\r_data.c -# End Source File -# Begin Source File - -SOURCE=..\r_data.h -# End Source File -# Begin Source File - -SOURCE=..\r_defs.h -# End Source File -# Begin Source File - -SOURCE=..\r_draw.c -# End Source File -# Begin Source File - -SOURCE=..\r_draw.h -# End Source File -# Begin Source File - -SOURCE=..\r_draw16.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\r_draw8.c -# PROP Exclude_From_Build 1 -# End Source File -# Begin Source File - -SOURCE=..\r_local.h -# End Source File -# Begin Source File - -SOURCE=..\r_main.c -# End Source File -# Begin Source File - -SOURCE=..\r_main.h -# End Source File -# Begin Source File - -SOURCE=..\r_plane.c -# End Source File -# Begin Source File - -SOURCE=..\r_plane.h -# End Source File -# Begin Source File - -SOURCE=..\r_segs.c -# End Source File -# Begin Source File - -SOURCE=..\r_segs.h -# End Source File -# Begin Source File - -SOURCE=..\r_sky.c -# End Source File -# Begin Source File - -SOURCE=..\r_sky.h -# End Source File -# Begin Source File - -SOURCE=..\r_splats.c -# End Source File -# Begin Source File - -SOURCE=..\r_splats.h -# End Source File -# Begin Source File - -SOURCE=..\r_state.h -# End Source File -# Begin Source File - -SOURCE=..\r_things.c -# End Source File -# Begin Source File - -SOURCE=..\r_things.h -# End Source File -# Begin Source File - -SOURCE=..\screen.c -# End Source File -# Begin Source File - -SOURCE=..\screen.h -# End Source File -# Begin Source File - -SOURCE=..\v_video.c -# End Source File -# Begin Source File - -SOURCE=..\v_video.h -# End Source File -# End Group -# Begin Group "S_Sounds" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\s_sound.c -# End Source File -# Begin Source File - -SOURCE=..\s_sound.h -# End Source File -# Begin Source File - -SOURCE=..\sounds.c -# End Source File -# Begin Source File - -SOURCE=..\sounds.h -# End Source File -# End Group -# Begin Group "W_Wad" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\lzf.c -# End Source File -# Begin Source File - -SOURCE=..\lzf.h -# End Source File -# Begin Source File - -SOURCE=..\md5.c -# End Source File -# Begin Source File - -SOURCE=..\md5.h -# End Source File -# Begin Source File - -SOURCE=..\w_wad.c -# End Source File -# Begin Source File - -SOURCE=..\w_wad.h -# End Source File -# End Group -# Begin Group "Docs" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\..\doc\copying -# End Source File -# Begin Source File - -SOURCE=..\..\doc\faq.txt -# End Source File -# Begin Source File - -SOURCE=..\..\readme.txt -# End Source File -# Begin Source File - -SOURCE=..\..\doc\source.txt -# End Source File -# End Group -# Begin Source File - -SOURCE=.\Srb2win.ico -# End Source File -# End Target -# End Project diff --git a/src/win32/Srb2win.dsw b/src/win32/Srb2win.dsw deleted file mode 100644 index f20998142..000000000 --- a/src/win32/Srb2win.dsw +++ /dev/null @@ -1,77 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "Srb2win"=.\Srb2win.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name libpng - End Project Dependency - Begin Project Dependency - Project_Dep_Name zlib - End Project Dependency -}}} - -############################################################################### - -Project: "libpng"="..\..\libs\libpng-src\projects\visualc6\libpng.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name zlib - End Project Dependency -}}} - -############################################################################### - -Project: "r_opengl"=..\hardware\r_opengl\r_opengl.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ - Begin Project Dependency - Project_Dep_Name Srb2win - End Project Dependency -}}} - -############################################################################### - -Project: "zlib"=..\..\libs\zlib\projects\visualc6\zlib.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/src/win32/Srb2win.props b/src/win32/Srb2win.props deleted file mode 100644 index fa152f0c9..000000000 --- a/src/win32/Srb2win.props +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - HAVE_ZLIB;HAVE_LIBGME;_WINDOWS;%(PreprocessorDefinitions) - - _WINDOWS;%(PreprocessorDefinitions) - - - - dxguid.lib;winmm.lib;dinput8.lib;%(AdditionalDependencies) - - - - \ No newline at end of file diff --git a/src/win32/Srb2win.rc b/src/win32/Srb2win.rc index d5d59922c..83948ac81 100644 --- a/src/win32/Srb2win.rc +++ b/src/win32/Srb2win.rc @@ -76,8 +76,8 @@ END #include "../doomdef.h" // Needed for version string VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,2,8,0 - PRODUCTVERSION 2,2,8,0 + FILEVERSION 2,2,10,0 + PRODUCTVERSION 2,2,10,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -97,7 +97,7 @@ BEGIN VALUE "FileDescription", "Sonic Robo Blast 2\0" VALUE "FileVersion", VERSIONSTRING_RC VALUE "InternalName", "srb2\0" - VALUE "LegalCopyright", "Copyright 1998-2020 by Sonic Team Junior\0" + VALUE "LegalCopyright", "Copyright 1998-2022 by Sonic Team Junior\0" VALUE "LegalTrademarks", "Sonic the Hedgehog and related characters are trademarks of Sega.\0" VALUE "OriginalFilename", "srb2win.exe\0" VALUE "PrivateBuild", "\0" @@ -128,4 +128,3 @@ END ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED - diff --git a/src/win32/dx_error.c b/src/win32/dx_error.c deleted file mode 100644 index 8e14539a3..000000000 --- a/src/win32/dx_error.c +++ /dev/null @@ -1,276 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief DirectX error messages -/// adapted from DirectX6 sample code - -#include - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include -#define DIRECTSOUND_VERSION 0x0600 /* version 6.0 */ -#define DXVERSION_NTCOMPATIBLE 0x0300 -#ifdef _MSC_VER -#pragma warning(disable : 4201) -#endif -#include -#include -#include - -#include "dx_error.h" - -// ----------------- -// DXErrorMessageBox -// Displays a message box containing the given formatted string. -// ----------------- -/* -VOID DXErrorMessageBox (HRESULT error) LPSTR fmt, ...) -{ - char buff[256]; - va_list args; - - va_start(args, fmt); - wvsprintf(buff, fmt, args); - va_end(args); - - lstrcat(buff, "\r\n"); - MessageBoxA(NULL, buff, "DirectX Error:", MB_ICONEXCLAMATION + MB_OK); -}*/ - - -// --------------- -// DXErrorToString -// Returns a pointer to a string describing the given DD, D3D or D3DRM error code. -// --------------- -LPCSTR DXErrorToString (HRESULT error) -{ - switch (error) { - case DD_OK: - /* Also includes D3D_OK and D3DRM_OK */ - return "No error."; - case DDERR_ALREADYINITIALIZED: - return "This object is already initialized."; - case DDERR_BLTFASTCANTCLIP: - return "Return if a clipper object is attached to the source surface passed into a BltFast call."; - case DDERR_CANNOTATTACHSURFACE: - return "This surface can not be attached to the requested surface."; - case DDERR_CANNOTDETACHSURFACE: - return "This surface can not be detached from the requested surface."; - case DDERR_CANTCREATEDC: - return "Windows can not create any more DCs."; - case DDERR_CANTDUPLICATE: - return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created."; - case DDERR_CLIPPERISUSINGHWND: - return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd."; - case DDERR_COLORKEYNOTSET: - return "No src color key specified for this operation."; - case DDERR_CURRENTLYNOTAVAIL: - return "Support is currently not available."; - case DDERR_DIRECTDRAWALREADYCREATED: - return "A DirectDraw object representing this driver has already been created for this process."; - case DDERR_EXCEPTION: - return "An exception was encountered while performing the requested operation."; - case DDERR_EXCLUSIVEMODEALREADYSET: - return "An attempt was made to set the cooperative level when it was already set to exclusive."; - case DDERR_GENERIC: - return "Generic failure."; - case DDERR_HEIGHTALIGN: - return "Height of rectangle provided is not a multiple of reqd alignment."; - case DDERR_HWNDALREADYSET: - return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created."; - case DDERR_HWNDSUBCLASSED: - return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state."; - case DDERR_IMPLICITLYCREATED: - return "This surface can not be restored because it is an implicitly created surface."; - case DDERR_INCOMPATIBLEPRIMARY: - return "Unable to match primary surface creation request with existing primary surface."; - case DDERR_INVALIDCAPS: - return "One or more of the caps bits passed to the callback are incorrect."; - case DDERR_INVALIDCLIPLIST: - return "DirectDraw does not support the provided cliplist."; - case DDERR_INVALIDDIRECTDRAWGUID: - return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier."; - case DDERR_INVALIDMODE: - return "DirectDraw does not support the requested mode."; - case DDERR_INVALIDOBJECT: - return "DirectDraw received a pointer that was an invalid DIRECTDRAW object."; - case DDERR_INVALIDPARAMS: - return "One or more of the parameters passed to the function are incorrect."; - case DDERR_INVALIDPIXELFORMAT: - return "The pixel format was invalid as specified."; - case DDERR_INVALIDPOSITION: - return "Returned when the position of the overlay on the destination is no longer legal for that destination."; - case DDERR_INVALIDRECT: - return "Rectangle provided was invalid."; - case DDERR_LOCKEDSURFACES: - return "Operation could not be carried out because one or more surfaces are locked."; - case DDERR_NO3D: - return "There is no 3D present."; - case DDERR_NOALPHAHW: - return "Operation could not be carried out because there is no alpha accleration hardware present or available."; - case DDERR_NOBLTHW: - return "No blitter hardware present."; - case DDERR_NOCLIPLIST: - return "No cliplist available."; - case DDERR_NOCLIPPERATTACHED: - return "No clipper object attached to surface object."; - case DDERR_NOCOLORCONVHW: - return "Operation could not be carried out because there is no color conversion hardware present or available."; - case DDERR_NOCOLORKEY: - return "Surface doesn't currently have a color key"; - case DDERR_NOCOLORKEYHW: - return "Operation could not be carried out because there is no hardware support of the destination color key."; - case DDERR_NOCOOPERATIVELEVELSET: - return "Create function called without DirectDraw object method SetCooperativeLevel being called."; - case DDERR_NODC: - return "No DC was ever created for this surface."; - case DDERR_NODDROPSHW: - return "No DirectDraw ROP hardware."; - case DDERR_NODIRECTDRAWHW: - return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware."; - case DDERR_NOEMULATION: - return "Software emulation not available."; - case DDERR_NOEXCLUSIVEMODE: - return "Operation requires the application to have exclusive mode but the application does not have exclusive mode."; - case DDERR_NOFLIPHW: - return "Flipping visible surfaces is not supported."; - case DDERR_NOGDI: - return "There is no GDI present."; - case DDERR_NOHWND: - return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND."; - case DDERR_NOMIRRORHW: - return "Operation could not be carried out because there is no hardware present or available."; - case DDERR_NOOVERLAYDEST: - return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination."; - case DDERR_NOOVERLAYHW: - return "Operation could not be carried out because there is no overlay hardware present or available."; - case DDERR_NOPALETTEATTACHED: - return "No palette object attached to this surface."; - case DDERR_NOPALETTEHW: - return "No hardware support for 16 or 256 color palettes."; - case DDERR_NORASTEROPHW: - return "Operation could not be carried out because there is no appropriate raster op hardware present or available."; - case DDERR_NOROTATIONHW: - return "Operation could not be carried out because there is no rotation hardware present or available."; - case DDERR_NOSTRETCHHW: - return "Operation could not be carried out because there is no hardware support for stretching."; - case DDERR_NOT4BITCOLOR: - return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette."; - case DDERR_NOT4BITCOLORINDEX: - return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette."; - case DDERR_NOT8BITCOLOR: - return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color."; - case DDERR_NOTAOVERLAYSURFACE: - return "Returned when an overlay member is called for a non-overlay surface."; - case DDERR_NOTEXTUREHW: - return "Operation could not be carried out because there is no texture mapping hardware present or available."; - case DDERR_NOTFLIPPABLE: - return "An attempt has been made to flip a surface that is not flippable."; - case DDERR_NOTFOUND: - return "Requested item was not found."; - case DDERR_NOTLOCKED: - return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted."; - case DDERR_NOTPALETTIZED: - return "The surface being used is not a palette-based surface."; - case DDERR_NOVSYNCHW: - return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations."; - case DDERR_NOZBUFFERHW: - return "Operation could not be carried out because there is no hardware support for zbuffer blitting."; - case DDERR_NOZOVERLAYHW: - return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays."; - case DDERR_OUTOFCAPS: - return "The hardware needed for the requested operation has already been allocated."; - case DDERR_OUTOFMEMORY: - return "There is not enough memory to perform the operation."; - case DDERR_OUTOFVIDEOMEMORY: - return "DirectDraw does not have enough memory to perform the operation."; - case DDERR_OVERLAYCANTCLIP: - return "The hardware does not support clipped overlays."; - case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: - return "Can only have ony color key active at one time for overlays."; - case DDERR_OVERLAYNOTVISIBLE: - return "Returned when GetOverlayPosition is called on a hidden overlay."; - case DDERR_PALETTEBUSY: - return "Access to this palette is being refused because the palette is already locked by another thread."; - case DDERR_PRIMARYSURFACEALREADYEXISTS: - return "This process already has created a primary surface."; - case DDERR_REGIONTOOSMALL: - return "Region passed to Clipper::GetClipList is too small."; - case DDERR_SURFACEALREADYATTACHED: - return "This surface is already attached to the surface it is being attached to."; - case DDERR_SURFACEALREADYDEPENDENT: - return "This surface is already a dependency of the surface it is being made a dependency of."; - case DDERR_SURFACEBUSY: - return "Access to this surface is being refused because the surface is already locked by another thread."; - case DDERR_SURFACEISOBSCURED: - return "Access to surface refused because the surface is obscured."; - case DDERR_SURFACELOST: - return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it."; - case DDERR_SURFACENOTATTACHED: - return "The requested surface is not attached."; - case DDERR_TOOBIGHEIGHT: - return "Height requested by DirectDraw is too large."; - case DDERR_TOOBIGSIZE: - return "Size requested by DirectDraw is too large, but the individual height and width are OK."; - case DDERR_TOOBIGWIDTH: - return "Width requested by DirectDraw is too large."; - case DDERR_UNSUPPORTED: - return "Function call not supported."; - case DDERR_UNSUPPORTEDFORMAT: - return "FOURCC format requested is unsupported by DirectDraw."; - case DDERR_UNSUPPORTEDMASK: - return "Bitmask in the pixel format requested is unsupported by DirectDraw."; - case DDERR_VERTICALBLANKINPROGRESS: - return "Vertical blank is in progress."; - case DDERR_WASSTILLDRAWING: - return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete."; - case DDERR_WRONGMODE: - return "This surface can not be restored because it was created in a different mode."; - case DDERR_XALIGN: - return "Rectangle provided was not horizontally aligned on required boundary."; - - // - // DirectSound errors - // - case DSERR_ALLOCATED: - return "The request failed because resources, such as a priority level, were already in use by another caller."; - case DSERR_ALREADYINITIALIZED: - return "The object is already initialized."; - case DSERR_BADFORMAT: - return "The specified wave format is not supported."; - case DSERR_BUFFERLOST: - return "The buffer memory has been lost and must be restored."; - case DSERR_CONTROLUNAVAIL: - return "The control (volume, pan, and so forth) requested by the caller is not available."; - case DSERR_INVALIDCALL: - return "This function is not valid for the current state of this object."; - case DSERR_NOAGGREGATION: - return "The object does not support aggregation."; - case DSERR_NODRIVER: - return "No sound driver is available for use."; - case DSERR_NOINTERFACE: - return "The requested COM interface is not available."; - case DSERR_OTHERAPPHASPRIO: - return "Another application has a higher priority level, preventing this call from succeeding"; - case DSERR_PRIOLEVELNEEDED: - return "The caller does not have the priority level required for the function to succeed."; - case DSERR_UNINITIALIZED: - return "The IDirectSound::Initialize method has not been called or has not been called successfully before other methods were called."; - default: - return "Unrecognized error value."; - } -} diff --git a/src/win32/dx_error.h b/src/win32/dx_error.h deleted file mode 100644 index 3af4220de..000000000 --- a/src/win32/dx_error.h +++ /dev/null @@ -1,39 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief transform an unreadable DirectX error code -/// into a meaningful error message. - -#ifndef __DX_ERROR_H__ -#define __DX_ERROR_H__ - -//#define WIN32_LEAN_AND_MEAN -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Displays a message box containing the given formatted string. -//VOID DXErrorMessageBox (LPSTR fmt, ...); - -// Returns a pointer to a string describing the given DD, D3D or D3DRM error code. -LPCSTR DXErrorToString (HRESULT error); - -#ifdef __cplusplus -}; -#endif -#endif // __DX_ERROR_H__ diff --git a/src/win32/fabdxlib.c b/src/win32/fabdxlib.c deleted file mode 100644 index 45ec5d0d3..000000000 --- a/src/win32/fabdxlib.c +++ /dev/null @@ -1,677 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -//----------------------------------------------------------------------------- -/// \file -/// \brief faB's DirectX library v1.0 -/// - converted to C for Doom Legacy - -#include "../doomdef.h" - -#ifdef _WINDOWS - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include -#include -#include "../i_system.h" -#include "dx_error.h" - -#include "fabdxlib.h" - -#define NT4COMPAT //always defined, always compatible - - -// globals - -IDirectDraw2* DDr2 = NULL; -IDirectDrawSurface* ScreenReal = NULL; // DirectDraw primary surface -IDirectDrawSurface* ScreenVirtual = NULL; // DirectDraw back surface -IDirectDrawPalette* DDPalette = NULL; // The primary surface palette -static IDirectDrawClipper *windclip = NULL; // clipper for windowed mode - -BOOL bAppFullScreen; // true for fullscreen exclusive mode, - -int windowPosX = 0; // current position in windowed mode -int windowPosY = 0; - -int ScreenWidth; -int ScreenHeight; -BOOL ScreenLocked; // Screen surface is being locked -int ScreenPitch; // offset from one line to the next -LPBYTE ScreenPtr; // memory of the surface - - -// -// CreateNewSurface -// -static inline IDirectDrawSurface* CreateNewSurface(int dwWidth, - int dwHeight, - int dwSurfaceCaps) -{ - DDSURFACEDESC ddsd; - HRESULT hr; - LPDIRECTDRAWSURFACE psurf; - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; - - ddsd.ddsCaps.dwCaps = dwSurfaceCaps; - - ddsd.dwHeight = dwHeight; - ddsd.dwWidth = dwWidth; - - hr = IDirectDraw2_CreateSurface (DDr2, &ddsd, &psurf, NULL); - - if (hr == DD_OK) - { - //DDCOLORKEY ddck; - IDirectDrawSurface_Restore(psurf); - - //hr = IDirectDrawSurface_GetColorKey(DDCKEY_SRCBLT, &ddck); - //psurf->SetColorKey(DDCKEY_SRCBLT, &ddck); - } - else - psurf = NULL; - - return psurf; -} - -// -// wow! from 320x200x8 up to 1600x1200x32 thanks Banshee! :) -// -static HRESULT WINAPI myEnumModesCallback (LPDDSURFACEDESC surf, LPVOID lpContext) -{ - APPENUMMODESCALLBACK pfnContext = lpContext; - - if (pfnContext) pfnContext(surf->dwWidth, - surf->dwHeight,surf->ddpfPixelFormat. -#ifdef DUMMYUNIONNAMEN - DUMMYUNIONNAMEN(1). -#endif - dwRGBBitCount - ); - - /*I_OutputMsg("%dx%dx%d bpp %d refresh\n", - surf->dwWidth, - surf->dwHeight, - surf->ddpfPixelFormat.dwRGBBitCount, - surf->dwRefreshRate);*/ - - return DDENUMRET_OK; -} - - -// -// Application call here to enumerate display modes -// -BOOL EnumDirectDrawDisplayModes (APPENUMMODESCALLBACK appFunc) -{ - LPVOID lpappFunc = appFunc; - - if (DDr2 == NULL) - return FALSE; - - // enumerate display modes - // Carl: DirectX 3.x apparently does not support VGA modes. Who cares. :) - // faB: removed DDEDM_REFRESHRATES, detects too many modes, plus we don't care of refresh rate. - if (bDX0300) - IDirectDraw2_EnumDisplayModes (DDr2, 0 /*| DDEDM_REFRESHRATES*/, - NULL, lpappFunc, myEnumModesCallback); - else - IDirectDraw2_EnumDisplayModes (DDr2, DDEDM_STANDARDVGAMODES /*| DDEDM_REFRESHRATES*/, - NULL, lpappFunc, myEnumModesCallback); - return TRUE; -} - -static HINSTANCE DDrawDLL = NULL; -typedef HRESULT(WINAPI *DDCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter); -static DDCreate pfnDirectDrawCreate = NULL; - -static inline BOOL LoadDirectDraw(VOID) -{ - // load ddraw.dll - DDrawDLL = LoadLibraryA("DDRAW.DLL"); - if (DDrawDLL == NULL) - return false; - pfnDirectDrawCreate = (DDCreate)(LPVOID)GetProcAddress(DDrawDLL, "DirectDrawCreate"); - if (pfnDirectDrawCreate == NULL) - return false; - return true; -} - -static inline VOID UnLoadDirectDraw(VOID) -{ - if (!DDrawDLL) - return; - FreeLibrary(DDrawDLL); - pfnDirectDrawCreate = NULL; - DDrawDLL = NULL; -} - -// -// Create the DirectDraw object for later -// -BOOL CreateDirectDrawInstance (VOID) -{ - HRESULT hr; - IDirectDraw* DDr; - IDirectDraw** rp = &DDr; - IDirectDraw2** rp2 = &DDr2; - LPVOID *tp = (LPVOID *)rp2; - - if (!LoadDirectDraw()) - return FALSE; - // - // create an instance of DirectDraw object - // - if (FAILED(hr = pfnDirectDrawCreate(NULL, rp, NULL))) - I_Error("DirectDrawCreate FAILED: %s", DXErrorToString(hr)); - - // change interface to IDirectDraw2 - if (FAILED(hr = IDirectDraw_QueryInterface(DDr, &IID_IDirectDraw2, tp))) - I_Error("Failed to query DirectDraw2 interface: %s", DXErrorToString(hr)); - - // release the interface we don't need - IDirectDraw_Release (DDr); - return TRUE; -} - - -// -// - returns true if DirectDraw was initialized properly -// -int InitDirectDrawe (HWND appWin, int width, int height, int bpp, int fullScr) -{ - DDSURFACEDESC ddsd; // DirectDraw surface description for allocating - DDSCAPS ddscaps; - HRESULT ddrval; - - DWORD dwStyle; - RECT rect; - - // enumerate directdraw devices - //if (FAILED(DirectDrawEnumerate (myEnumDDDevicesCallback, NULL))) - // I_Error("Error with DirectDrawEnumerate"); - - if (!DDr2) - CreateDirectDrawInstance(); - - // remember what screen mode we are in - bAppFullScreen = fullScr; - ScreenHeight = height; - ScreenWidth = width; - - if (bAppFullScreen) - { - // Change window attributes - dwStyle = WS_POPUP | WS_VISIBLE; - SetWindowLong (appWin, GWL_STYLE, dwStyle); - SetWindowPos(appWin, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); - - // Get exclusive mode - ddrval = IDirectDraw2_SetCooperativeLevel(DDr2, appWin, DDSCL_EXCLUSIVE | - DDSCL_FULLSCREEN | - DDSCL_ALLOWREBOOT); - if (ddrval != DD_OK) - I_Error("SetCooperativeLevel FAILED: %s\n", DXErrorToString(ddrval)); - - // Switch from windows desktop to fullscreen - -#ifdef NT4COMPAT - ddrval = IDirectDraw2_SetDisplayMode(DDr2, width, height, bpp, 0, 0); -#else - ddrval = IDirectDraw2_SetDisplayMode(DDr2, width, height, bpp, 0, DDSDM_STANDARDVGAMODE); -#endif - if (ddrval != DD_OK) - I_Error("SetDisplayMode FAILED: %s\n", DXErrorToString(ddrval)); - - // This is not really needed, except in certain cases. One case - // is while using MFC. When the desktop is initally at 16bpp, a mode - // switch to 8bpp somehow causes the MFC window to not fully initialize - // and a CreateSurface will fail with DDERR_NOEXCLUSIVEMODE. This will - // ensure that the window is initialized properly after a mode switch. - - ShowWindow(appWin, SW_SHOW); - - // Create the primary surface with 1 back buffer. Always zero the - // DDSURFACEDESC structure and set the dwSize member! - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; - - // for fullscreen we use page flipping, for windowed mode, we blit the hidden surface to - // the visible surface, in both cases we have a visible (or 'real') surface, and a hidden - // (or 'virtual', or 'backbuffer') surface. - ddsd.dwBackBufferCount = 2; - - ddrval = IDirectDraw2_CreateSurface(DDr2,&ddsd, &ScreenReal, NULL); - if (ddrval != DD_OK) - I_Error("CreateSurface Primary Screen FAILED"); - - // Get a pointer to the back buffer - - ddscaps.dwCaps = DDSCAPS_BACKBUFFER; - ddrval = IDirectDrawSurface_GetAttachedSurface(ScreenReal,&ddscaps, &ScreenVirtual); - if (ddrval != DD_OK) - I_Error("GetAttachedSurface FAILED"); - } - else - { - rect.top = 0; - rect.left = 0; - rect.bottom = height; - rect.right = width; - - // Change window attributes - - dwStyle = GetWindowStyle(appWin); - dwStyle &= ~WS_POPUP; - dwStyle |= WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION; - - SetWindowLong(appWin, GWL_STYLE, dwStyle); - - // Resize the window so that the client area is the requested width/height - - AdjustWindowRectEx(&rect, GetWindowStyle(appWin), GetMenu(appWin) != NULL, - GetWindowExStyle(appWin)); - - // Just in case the window was moved off the visible area of the - // screen. - - SetWindowPos(appWin, NULL, 0, 0, rect.right-rect.left, - rect.bottom-rect.top, SWP_NOMOVE | SWP_NOZORDER | - SWP_NOACTIVATE); - - SetWindowPos(appWin, HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); - - // Exclusive mode is normal since it's in windowed mode and needs - // to cooperate with GDI - - ddrval = IDirectDraw2_SetCooperativeLevel(DDr2,appWin, DDSCL_NORMAL); - if (ddrval != DD_OK) - I_Error("SetCooperativeLevel FAILED"); - - // Always zero the DDSURFACEDESC structure and set the dwSize member! - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - // Create the primary surface - - ddrval = IDirectDraw2_CreateSurface(DDr2,&ddsd, &ScreenReal, NULL); - if (ddrval != DD_OK) - I_Error("CreateSurface Primary Screen FAILED"); - - // Create a back buffer for offscreen rendering, this will be used to - // blt to the primary - - ScreenVirtual = CreateNewSurface(width, height, DDSCAPS_OFFSCREENPLAIN | - DDSCAPS_SYSTEMMEMORY); - if (ScreenVirtual == NULL) - I_Error("CreateSurface Secondary Screen FAILED"); - - /// \todo get the desktop bit depth, and build a lookup table - /// for quick conversions of 8bit color indexes 0-255 to desktop colors - /// eg: 256 entries of equivalent of palette colors 0-255 in 15,16,24,32 bit format - /// when blit virtual to real, convert pixels through lookup table.. - - // Use a clipper object for clipping when in windowed mode - // (make sure our drawing doesn't affect other windows) - - ddrval = IDirectDraw2_CreateClipper (DDr2, 0, &windclip, 0); - if (ddrval != DD_OK) - I_Error("CreateClipper FAILED"); - - // Associate the clipper with the window. - ddrval = IDirectDrawClipper_SetHWnd (windclip,0, appWin); - if (ddrval != DD_OK) - I_Error("Clipper -> SetHWnd FAILED"); - - // Attach the clipper to the surface. - ddrval = IDirectDrawSurface_SetClipper (ScreenReal,windclip); - if (ddrval != DD_OK) - I_Error("PrimaryScreen -> SetClipperClipper FAILED"); - } - - return TRUE; -} - - -// -// Free all memory -// -VOID CloseDirectDraw (VOID) -{ - ReleaseChtuff(); - if (DDr2) - { - IDirectDraw2_Release(DDr2); - DDr2 = NULL; - } - UnLoadDirectDraw(); -} - - -// -// Release DirectDraw stuff before display mode change -// -VOID ReleaseChtuff (VOID) -{ - if (!DDr2) - return; - if (windclip) - { - IDirectDrawClipper_Release(windclip); - windclip = NULL; - } - if (DDPalette) - { - IDirectDrawPalette_Release(DDPalette); - DDPalette = NULL; - } - // If the app is fullscreen, the back buffer is attached to the - // primary. Releasing the primary buffer will also release any - // attached buffers, so explicitly releasing the back buffer is not - // necessary. - - if (!bAppFullScreen && ScreenVirtual) - { - IDirectDrawSurface_Release(ScreenVirtual); // release hidden surface - ScreenVirtual = NULL; - } - if (ScreenReal) - { - IDirectDrawSurface_Release(ScreenReal); // and attached backbuffers for bAppFullScreen mode - ScreenReal = NULL; - } -} - - -// -// Clear the surface to color -// -VOID ClearSurface(IDirectDrawSurface* surface, int color) -{ - DDBLTFX ddbltfx; - - // Use the blter to do a color fill to clear the back buffer - ddbltfx.dwSize = sizeof (ddbltfx); - ddbltfx. -#ifdef DUMMYUNIONNAMEN - DUMMYUNIONNAMEN(5). -#endif - dwFillColor = color; - IDirectDrawSurface_Blt(surface,NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - -} - -// -// Flip the real page with virtual page -// - in bAppFullScreen mode, do page flipping -// - in windowed mode, copy the hidden surface to the visible surface -// -// waitflip : if not 0, wait for page flip to end -BOOL ScreenFlip(int waitflip) -{ - HRESULT hr; - RECT rect; - - if (bAppFullScreen) - { - //hr = IDirectDrawSurface_GetFlipStatus (ScreenReal, DDGFS_); - - // In full-screen exclusive mode, do a hardware flip. - hr = IDirectDrawSurface_Flip(ScreenReal, NULL, DDFLIP_WAIT | (waitflip ? 0 : DDFLIP_NOVSYNC)); //return immediately - - // If the surface was lost, restore it. - if (hr == DDERR_SURFACELOST) - { - IDirectDrawSurface_Restore(ScreenReal); - - // The restore worked, so try the flip again. - hr = IDirectDrawSurface_Flip(ScreenReal, 0, DDFLIP_WAIT | (waitflip ? 0 : DDFLIP_NOVSYNC)); - } - } - else - { - rect.left = windowPosX; - rect.top = windowPosY; - rect.right = windowPosX + ScreenWidth - 1; - rect.bottom = windowPosY + ScreenHeight - 1; - - // Copy the back buffer to front. - hr = IDirectDrawSurface_Blt(ScreenReal, &rect, ScreenVirtual, 0, DDBLT_WAIT, 0); - - if (hr != DD_OK) - { - // If the surfaces were lost, restore them. - if (IDirectDrawSurface_IsLost(ScreenReal) == DDERR_SURFACELOST) - IDirectDrawSurface_Restore(ScreenReal); - - if (IDirectDrawSurface_IsLost(ScreenVirtual) == DDERR_SURFACELOST) - IDirectDrawSurface_Restore(ScreenVirtual); - - // Retry the copy. - hr = IDirectDrawSurface_Blt(ScreenReal,&rect, ScreenVirtual, 0, DDBLT_WAIT, 0); - } - } - - if (hr != DD_OK) - I_Error("ScreenFlip() : couldn't Flip surfaces because %s", DXErrorToString(hr)); - - return FALSE; -} - -// -// Print a text to the surface -// -VOID TextPrint(int x, int y, LPCSTR message) -{ - HRESULT hr; - HDC hdc = NULL; - - // Get the device context handle. - hr = IDirectDrawSurface_GetDC(ScreenVirtual,&hdc); - if (hr != DD_OK) - return; - - // Write the message. - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, RGB(255, 255, 255)); - TextOutA(hdc, x, y, message, (int)strlen(message)); - - // Release the device context. - hr = IDirectDrawSurface_ReleaseDC(ScreenVirtual,hdc); -} - -// -// Lock surface before multiple drawings by hand, for speed -// -boolean LockScreen(VOID) -{ - DDSURFACEDESC ddsd; - HRESULT ddrval; - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - - // attempt to Lock the surface - ddrval = IDirectDrawSurface_Lock(ScreenVirtual, NULL, &ddsd, DDLOCK_WAIT, NULL); - - // Always, always check for errors with DirectX! - // If the surface was lost, restore it. - if (ddrval == DDERR_SURFACELOST) - { - ddrval = IDirectDrawSurface_Restore(ScreenReal); - - // now retry to get the lock - ddrval = IDirectDrawSurface_Lock(ScreenVirtual, NULL, &ddsd, DDLOCK_WAIT, NULL); - } - - if (ddrval == DD_OK) - { - ScreenLocked = TRUE; - ScreenPtr = (LPBYTE)ddsd.lpSurface; - ScreenPitch = ddsd. -#ifdef DUMMYUNIONNAMEN - DUMMYUNIONNAMEN(1). -#endif - lPitch; - } - else - { - ScreenLocked = FALSE; - ScreenPtr = NULL; - ScreenPitch = 0; - //I_Error("LockScreen() : couldn't restore the surface."); - return false; - } - return true; -} - -// -// Unlock surface -// -VOID UnlockScreen(VOID) -{ - if (DD_OK != IDirectDrawSurface_Unlock(ScreenVirtual,NULL)) - I_Error("Couldn't UnLock the renderer!"); - - ScreenLocked = FALSE; - ScreenPtr = NULL; - ScreenPitch = 0; -} - -// Blit virtual screen to real screen -//faB: note: testing 14/03/1999, see if it is faster than memcopy of virtual to -/* -static LPDIRECTDRAWSURFACE lpDDS = NULL; -VOID BlitScreen(VOID) -{ - HRESULT hr; - - if (!lpDDS) - I_Error("lpDDS NULL"); - - hr = IDirectDrawSurface_BltFast(ScreenVirtual, - 0, 0, // Upper left xy of destination - lpDDS, // Source surface - NULL, // Source rectangle = entire surface - DDBLTFAST_WAIT | DDBLTFAST_NOCOLORKEY); - if (FAILED(hr)) - I_Error("BltFast FAILED"); -} - -VOID MakeScreen(int width, int height, BYTE* lpSurface) -{ - HRESULT hr; - DDSURFACEDESC ddsd; - - // Initialize the surface description. - ZeroMemory (&ddsd, sizeof ddsd); - ZeroMemory (&ddsd.ddpfPixelFormat, sizeof (DDPIXELFORMAT)); - ddsd.dwSize = sizeof ddsd; - ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | //DDSD_LPSURFACE | - DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_CAPS; - ddsd.dwWidth = width; - ddsd.dwHeight= height; - ddsd.lPitch = width; - ddsd.lpSurface = lpSurface; - ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; - - // Set up the pixel format for 8-bit - ddsd.ddpfPixelFormat.dwSize = sizeof (DDPIXELFORMAT); - ddsd.ddpfPixelFormat.dwFlags= DDPF_RGB | DDPF_PALETTEINDEXED8; - ddsd.ddpfPixelFormat.dwRGBBitCount = 8; - - // - ddsd.ddpfPixelFormat.dwRGBBitCount = (DWORD)DEPTH*8; - ddsd.ddpfPixelFormat.dwRBitMask = 0x00FF0000; - ddsd.ddpfPixelFormat.dwGBitMask = 0x0000FF00; - ddsd.ddpfPixelFormat.dwBBitMask = 0x000000FF; - - // Create the surface - hr = IDirectDraw2_CreateSurface(DDr2, &ddsd, &lpDDS, NULL); - if (FAILED(hr)) - I_Error("MakeScreen FAILED: %s",DDError(hr)); - //ddsd.lpSurface = lpSurface; -} -*/ - -// -// Create a palette object -// -VOID CreateDDPalette (PALETTEENTRY* colorTable) -{ - HRESULT ddrval; - ddrval = IDirectDraw2_CreatePalette(DDr2,DDPCAPS_8BIT|DDPCAPS_ALLOW256, colorTable, &DDPalette, NULL); - if (ddrval != DD_OK) - I_Error("couldn't CreatePalette"); -}; - - -// -// Free the palette object -// -VOID DestroyDDPalette (VOID) -{ - if (DDPalette) - { - IDirectDrawPalette_Release(DDPalette); - DDPalette = NULL; - } -} - -// -// Set a a full palette of 256 PALETTEENTRY entries -// -VOID SetDDPalette(PALETTEENTRY* pal) -{ - // create palette first time - if (DDPalette == NULL) - CreateDDPalette(pal); - else - IDirectDrawPalette_SetEntries(DDPalette, 0, 0, 256, pal); - // setting the same palette to the same surface again does not increase - // the reference count - IDirectDrawSurface_SetPalette(ScreenReal, DDPalette); -} - -// -// Wait for vsync, gross -// -VOID WaitVbl(VOID) -{ - IDirectDraw2_WaitForVerticalBlank(DDr2, DDWAITVB_BLOCKBEGIN, NULL); -} - - -// -// Restore the palette. Useful when we regain focus. -// -VOID RestoreDDPalette(VOID) -{ - if (DDPalette) - IDirectDrawSurface_SetPalette(ScreenReal, DDPalette); -} -#endif diff --git a/src/win32/fabdxlib.h b/src/win32/fabdxlib.h deleted file mode 100644 index 2836b795d..000000000 --- a/src/win32/fabdxlib.h +++ /dev/null @@ -1,82 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief faB's DirectX library v1.0 - -#ifndef _H_FABDXLIB_ -#define _H_FABDXLIB_ - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include -#ifdef __MINGW32__ -//#define NONAMELESSUNION -#endif -#ifdef _MSC_VER -#pragma warning(disable : 4201) -#endif -#include -#if (defined (DIRECTDRAW_VERSION) && (DIRECTDRAW_VERSION >= 0x0700)) -#undef DUMMYUNIONNAMEN -#endif -// format of function in app called with width,height -typedef BOOL (*APPENUMMODESCALLBACK)(int width, int height, int bpp); - - -// globals -extern IDirectDraw2* DDr2; -extern IDirectDrawSurface* ScreenReal; -extern IDirectDrawSurface* ScreenVirtual; -extern IDirectDrawPalette* DDPalette; - -extern BOOL bAppFullScreen; // main code might need this to know the current - // fullscreen or windowed state - -extern int windowPosX; // current position in windowed mode -extern int windowPosY; - -extern int ScreenWidth; -extern int ScreenHeight; -extern BOOL ScreenLocked; // Screen surface is being locked -extern int ScreenPitch; // offset from one line to the next -extern LPBYTE ScreenPtr; // memory of the surface - -extern BOOL bDX0300; - -BOOL EnumDirectDrawDisplayModes (APPENUMMODESCALLBACK appFunc); -BOOL CreateDirectDrawInstance (VOID); - -int InitDirectDrawe (HWND appWin, int width, int height, int bpp, int fullScr); -VOID CloseDirectDraw (VOID); - -VOID ReleaseChtuff (VOID); - -VOID ClearSurface (IDirectDrawSurface* surface, int color); -BOOL ScreenFlip (int wait); -VOID TextPrint (int x, int y, LPCSTR message); - -VOID CreateDDPalette (PALETTEENTRY* colorTable); -VOID DestroyDDPalette (VOID); -VOID SetDDPalette (PALETTEENTRY* pal); -VOID RestoreDDPalette(VOID); - -VOID WaitVbl (VOID); - -boolean LockScreen (VOID); -VOID UnlockScreen (VOID); - - -#endif /* _H_FABDXLIB_ */ diff --git a/src/win32/win_cd.c b/src/win32/win_cd.c deleted file mode 100644 index 324c24928..000000000 --- a/src/win32/win_cd.c +++ /dev/null @@ -1,539 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief cd music interface (uses MCI). - -#include "../doomdef.h" -#include "../doomstat.h" -#ifdef _WINDOWS -#include "win_main.h" -#include - -#include "../command.h" -#include "../doomtype.h" -#include "../i_sound.h" -#include "../i_system.h" - -#include "../s_sound.h" - -#define MAX_CD_TRACKS 255 - -typedef struct { - BOOL IsAudio; - DWORD Start, End; - DWORD Length; // minutes -} CDTrack; - -// ------- -// private -// ------- -static CDTrack m_nTracks[MAX_CD_TRACKS]; -static int m_nTracksCount; // up to MAX_CD_TRACKS -static MCI_STATUS_PARMS m_MCIStatus; -static MCI_OPEN_PARMS m_MCIOpen; - -// ------ -// protos -// ------ -static void Command_Cd_f (void); - - -// ------------------- -// MCIErrorMessageBox -// Retrieve error message corresponding to return value from -// mciSendCommand() or mciSenString() -// ------------------- -static VOID MCIErrorMessageBox (MCIERROR iErrorCode) -{ - char szErrorText[128]; - if (!mciGetErrorStringA (iErrorCode, szErrorText, sizeof (szErrorText))) - wsprintfA(szErrorText,"MCI CD Audio Unknown Error #%lu\n", iErrorCode); - I_OutputMsg("%s", szErrorText); - /*MessageBox (GetActiveWindow(), szTemp+1, "LEGACY", - MB_OK | MB_ICONSTOP);*/ -} - - -// -------- -// CD_Reset -// -------- -static VOID CD_Reset (VOID) -{ - // no win32 equivalent - //faB: for DOS, some odd drivers like to be reset sometimes.. useless in MCI I guess -} - - -// ---------------- -// CD_ReadTrackInfo -// Read in number of tracks, and length of each track in minutes/seconds -// returns true if error -// ---------------- -static BOOL CD_ReadTrackInfo(VOID) -{ - UINT nTrackLength; - INT i; - MCIERROR iErr; - - m_nTracksCount = 0; - - m_MCIStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM|MCI_WAIT, (DWORD_PTR)&m_MCIStatus); - if (iErr) - { - MCIErrorMessageBox (iErr); - return FALSE; - } - m_nTracksCount = (int)m_MCIStatus.dwReturn; - if (m_nTracksCount > MAX_CD_TRACKS) - m_nTracksCount = MAX_CD_TRACKS; - - for (i = 0; i < m_nTracksCount; i++) - { - m_MCIStatus.dwTrack = (DWORD)(i+1); - m_MCIStatus.dwItem = MCI_STATUS_LENGTH; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_STATUS, MCI_TRACK|MCI_STATUS_ITEM|MCI_WAIT, (DWORD_PTR)&m_MCIStatus); - if (iErr) - { - MCIErrorMessageBox (iErr); - return FALSE; - } - nTrackLength = (DWORD)(MCI_MSF_MINUTE(m_MCIStatus.dwReturn)*60 + MCI_MSF_SECOND(m_MCIStatus.dwReturn)); - m_nTracks[i].Length = nTrackLength; - - m_MCIStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_STATUS, MCI_TRACK|MCI_STATUS_ITEM|MCI_WAIT, (DWORD_PTR)&m_MCIStatus); - if (iErr) - { - MCIErrorMessageBox (iErr); - return FALSE; - } - m_nTracks[i].IsAudio = (m_MCIStatus.dwReturn == MCI_CDA_TRACK_AUDIO); - } - - return TRUE; -} - - -// ------------ -// CD_TotalTime -// returns total time for all audio tracks in seconds -// ------------ -static UINT CD_TotalTime(VOID) -{ - UINT nTotalLength = 0; - INT nTrack; - for (nTrack = 0; nTrack < m_nTracksCount; nTrack++) - { - if (m_nTracks[nTrack].IsAudio) - nTotalLength += m_nTracks[nTrack].Length; - } - return nTotalLength; -} - - -//====================================================================== -// CD AUDIO MUSIC SUBSYSTEM -//====================================================================== - -UINT8 cdaudio_started = 0; // for system startup/shutdown - -static BOOL cdPlaying = FALSE; -static INT cdPlayTrack; // when cdPlaying is true -static BOOL cdLooping = FALSE; -static BYTE cdRemap[MAX_CD_TRACKS]; -static BOOL cdEnabled = TRUE; // cd info available -static BOOL cdValid; // true when last cd audio info was ok -static BOOL wasPlaying; -//static INT cdVolume = 0; // current cd volume (0-31) - -// 0-31 like Music & Sfx, though CD hardware volume is 0-255. -consvar_t cd_volume = CVAR_INIT ("cd_volume","18",CV_SAVE,soundvolume_cons_t, NULL); - -// allow Update for next/loop track -// some crap cd drivers take up to -// a second for a simple 'busy' check.. -// (on those Update can be disabled) -consvar_t cdUpdate = CVAR_INIT ("cd_update","1",CV_SAVE, NULL, NULL); - -#if (__GNUC__ > 6) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat-overflow" -#endif -// hour,minutes,seconds -static LPSTR hms(UINT seconds) -{ - UINT hours, minutes; - static CHAR s[9]; - - minutes = seconds / 60; - seconds %= 60; - hours = minutes / 60; - minutes %= 60; - if (hours > 0) - sprintf (s, "%lu:%02lu:%02lu", (long unsigned int)hours, (long unsigned int)minutes, (long unsigned int)seconds); - else - sprintf (s, "%2lu:%02lu", (long unsigned int)minutes, (long unsigned int)seconds); - return s; -} -#if (__GNUC__ > 6) -#pragma GCC diagnostic pop -#endif - -static void Command_Cd_f(void) -{ - LPCSTR s; - int i,j; - - if (!cdaudio_started) - return; - - if (COM_Argc() < 2) - { - CONS_Printf (M_GetText( - "cd [on] [off] [remap] [reset] [select]\n" - " [open] [info] [play ] [resume]\n" - " [stop] [pause] [loop ]\n")); - return; - } - - s = COM_Argv(1); - - // activate cd music - if (!strncmp(s,"on",2)) - { - cdEnabled = TRUE; - return; - } - - // stop/deactivate cd music - if (!strncmp(s, "off", 3)) - { - if (cdPlaying) - I_StopCD(); - cdEnabled = FALSE; - return; - } - - // remap tracks - if (!strncmp(s, "remap", 5)) - { - i = (int)COM_Argc() - 2; - if (i <= 0) - { - CONS_Printf(M_GetText("CD tracks remapped in that order :\n")); - for (j = 1; j < MAX_CD_TRACKS; j++) - if (cdRemap[j] != j) - CONS_Printf(" %2d -> %2d\n", j, cdRemap[j]); - return; - } - for (j = 1; j <= i; j++) - cdRemap[j] = (UINT8)atoi(COM_Argv(j+1)); - return; - } - - // reset the CD driver, useful on some odd cd's - if (!strncmp(s,"reset",5)) - { - cdEnabled = TRUE; - if (cdPlaying) - I_StopCD (); - for (i = 0; i < MAX_CD_TRACKS; i++) - cdRemap[i] = (UINT8)i; - CD_Reset(); - cdValid = CD_ReadTrackInfo(); - return; - } - - // any other command is not allowed until we could retrieve cd information - if (!cdValid) - { - CONS_Printf(M_GetText("CD is not ready.\n")); - return; - } - - /* faB: not with MCI, didn't find it, useless anyway - if (!strncmp(s,"open",4)) - { - if (cdPlaying) - I_StopCD (); - bcd_open_door(); - cdValid = FALSE; - return; - }*/ - - if (!strncmp(s,"info",4)) - { - if (!CD_ReadTrackInfo()) - { - cdValid = FALSE; - return; - } - - cdValid = TRUE; - - if (m_nTracksCount <= 0) - CONS_Printf(M_GetText("No audio tracks\n")); - else - { - // display list of tracks - // highlight current playing track - for (i = 0; i < m_nTracksCount; i++) - { - CONS_Printf("%s%2d. %s %s\n", - cdPlaying && (cdPlayTrack == i) ? "\x82 " : " ", - i+1, m_nTracks[i].IsAudio ? M_GetText("audio") : M_GetText("data "), - hms(m_nTracks[i].Length)); - } - CONS_Printf(M_GetText("\x82Total time : %s\n"), hms(CD_TotalTime())); - } - if (cdPlaying) - { - CONS_Printf(M_GetText("Currently %s track %u\n"), cdLooping ? M_GetText("looping") : M_GetText("playing"), cdPlayTrack); - } - return; - } - - if (!strncmp(s,"play",4)) - { - I_PlayCD ((UINT8)atoi (COM_Argv (2)), false); - return; - } - - if (!strncmp(s,"stop",4)) - { - I_StopCD (); - return; - } - - if (!strncmp(s,"loop",4)) - { - I_PlayCD((UINT8)atoi (COM_Argv (2)), true); - return; - } - - if (!strncmp(s,"resume",4)) - { - I_ResumeCD (); - return; - } - - CONS_Printf (M_GetText("Invalid CD command \"CD %s\"\n"), s); -} - - -// ------------ -// I_ShutdownCD -// Shutdown CD Audio subsystem, release whatever was allocated -// ------------ -void I_ShutdownCD(void) -{ - MCIERROR iErr; - - if (!cdaudio_started) - return; - - CONS_Printf("I_ShutdownCD: "); - - I_StopCD(); - - // closes MCI CD - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_CLOSE, 0, 0); - if (iErr) - MCIErrorMessageBox (iErr); -} - - -// -------- -// I_InitCD -// Init CD Audio subsystem -// -------- -void I_InitCD(void) -{ - MCI_SET_PARMS mciSet; - MCIERROR iErr; - int i; - - // We don't have an open device yet - m_MCIOpen.wDeviceID = 0; - m_nTracksCount = 0; - - cdaudio_started = false; - - m_MCIOpen.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; - iErr = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, (DWORD_PTR)&m_MCIOpen); - if (iErr) - { - MCIErrorMessageBox (iErr); - return; - } - - // Set the time format to track/minute/second/frame (TMSF). - mciSet.dwTimeFormat = MCI_FORMAT_TMSF; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciSet); - if (iErr) - { - MCIErrorMessageBox (iErr); - mciSendCommand(m_MCIOpen.wDeviceID, MCI_CLOSE, 0, 0); - return; - } - - I_AddExitFunc (I_ShutdownCD); - cdaudio_started = true; - - CONS_Printf (M_GetText("CD audio Initialized\n")); - - // last saved in config.cfg - i = cd_volume.value; - //I_SetVolumeCD (0); // initialize to 0 for some odd cd drivers - I_SetVolumeCD (i); // now set the last saved volume - - for (i = 0; i < MAX_CD_TRACKS; i++) - cdRemap[i] = (UINT8)i; - - if (!CD_ReadTrackInfo()) - { - CONS_Printf(M_GetText("No CD in drive\n")); - cdEnabled = FALSE; - cdValid = FALSE; - } - else - { - cdEnabled = TRUE; - cdValid = TRUE; - } - - COM_AddCommand ("cd", Command_Cd_f); -} - - - -// loop/go to next track when track is finished (if cd_update var is true) -// update the volume when it has changed (from console/menu) -void I_UpdateCD(void) -{ - /// \todo check for cd change and restart music ? -} - - -// -void I_PlayCD(UINT8 nTrack, UINT8 bLooping) -{ - MCI_PLAY_PARMS mciPlay; - MCIERROR iErr; - - if (!cdaudio_started || !cdEnabled) - return; - - //faB: try again if it didn't work (just free the user of typing 'cd reset' command) - if (!cdValid) - cdValid = CD_ReadTrackInfo(); - if (!cdValid) - return; - - // tracks start at 0 in the code.. - nTrack--; - if (nTrack >= m_nTracksCount) - nTrack = (UINT8) (nTrack % m_nTracksCount); - - nTrack = cdRemap[nTrack]; - - if (cdPlaying) - { - if (cdPlayTrack == nTrack) - return; - I_StopCD (); - } - - cdPlayTrack = nTrack; - - if (!m_nTracks[nTrack].IsAudio) - { - //I_OutputMsg("\x82""CD Play: not an audio track\n"); // Tails 03-25-2001 - return; - } - - cdLooping = bLooping; - - //faB: stop MIDI music, MIDI music will restart if volume is upped later - cv_digmusicvolume.value = 0; - cv_midimusicvolume.value = 0; - I_StopSong(); - - //faB: I don't use the notify message, I'm trying to minimize the delay - mciPlay.dwCallback = (DWORD)((size_t)hWndMain); - mciPlay.dwFrom = MCI_MAKE_TMSF(nTrack+1, 0, 0, 0); - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_PLAY, MCI_FROM|MCI_NOTIFY, (DWORD_PTR)&mciPlay); - if (iErr) - { - MCIErrorMessageBox (iErr); - cdValid = FALSE; - cdPlaying = FALSE; - return; - } - - cdPlaying = TRUE; -} - - -// pause cd music -void I_StopCD(void) -{ - MCIERROR iErr; - - if (!cdaudio_started || !cdEnabled) - return; - - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_PAUSE, MCI_WAIT, 0); - if (iErr) - MCIErrorMessageBox (iErr); - else - { - wasPlaying = cdPlaying; - cdPlaying = FALSE; - } -} - - -// continue after a pause -void I_ResumeCD(void) -{ - MCIERROR iErr; - - if (!cdaudio_started || !cdEnabled) - return; - - if (!cdValid) - return; - - if (!wasPlaying) - return; - - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_RESUME, MCI_WAIT, 0); - if (iErr) - MCIErrorMessageBox (iErr); - else - cdPlaying = TRUE; -} - - -// volume : logical cd audio volume 0-31 (hardware is 0-255) -boolean I_SetVolumeCD (INT32 volume) -{ - UNREFERENCED_PARAMETER(volume); - return false; -} -#endif diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c deleted file mode 100644 index d942d8cd4..000000000 --- a/src/win32/win_dll.c +++ /dev/null @@ -1,240 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief load and initialise the 3D driver DLL - -#include "../doomdef.h" -#ifdef HWRENDER -#include "../hardware/hw_drv.h" // get the standard 3D Driver DLL exports prototypes -#endif - -#ifdef HW3SOUND -#include "../hardware/hw3dsdrv.h" // get the 3D sound driver DLL export prototypes -#endif - -#ifdef _WINDOWS - -#include "win_dll.h" -#include "win_main.h" // I_ShowLastError() - -#if defined(HWRENDER) || defined(HW3SOUND) -typedef struct loadfunc_s { - LPCSTR fnName; - LPVOID fnPointer; -} loadfunc_t; - -// -------------------------------------------------------------------------- -// Load a DLL, returns the HMODULE handle or NULL -// -------------------------------------------------------------------------- -static HMODULE LoadDLL (LPCSTR dllName, loadfunc_t *funcTable) -{ - LPVOID funcPtr; - loadfunc_t *loadfunc; - HMODULE hModule; - - if ((hModule = LoadLibraryA(dllName)) != NULL) - { - // get function pointers for all functions we use - for (loadfunc = funcTable; loadfunc->fnName != NULL; loadfunc++) - { - funcPtr = GetProcAddress(hModule, loadfunc->fnName); - if (!funcPtr) { - I_ShowLastError(FALSE); - MessageBoxA(NULL, va("The '%s' haven't the good specification (function %s missing)\n\n" - "You must use dll from the same zip of this exe\n", dllName, loadfunc->fnName), - "Error", MB_OK|MB_ICONINFORMATION); - return FALSE; - } - // store function address - *((LPVOID*)loadfunc->fnPointer) = funcPtr; - } - } - else - { - I_ShowLastError(FALSE); - MessageBoxA(NULL, va("LoadLibrary() FAILED : couldn't load '%s'\r\n", dllName), "Warning", MB_OK|MB_ICONINFORMATION); - } - - return hModule; -} - - -// -------------------------------------------------------------------------- -// Unload the DLL -// -------------------------------------------------------------------------- -static VOID UnloadDLL (HMODULE* pModule) -{ - if (FreeLibrary(*pModule)) - *pModule = NULL; - else - I_ShowLastError(TRUE); -} -#endif - -// ========================================================================== -// STANDARD 3D DRIVER DLL FOR DOOM LEGACY -// ========================================================================== - -// note : the 3D driver loading should be put somewhere else.. - -#ifdef HWRENDER -static HMODULE hwdModule = NULL; - -static loadfunc_t hwdFuncTable[] = { -#ifdef _X86_ - {"Init@4", &hwdriver.pfnInit}, - {"Shutdown@0", &hwdriver.pfnShutdown}, - {"GetModeList@8", &hwdriver.pfnGetModeList}, - {"SetPalette@4", &hwdriver.pfnSetPalette}, - {"FinishUpdate@4", &hwdriver.pfnFinishUpdate}, - {"Draw2DLine@12", &hwdriver.pfnDraw2DLine}, - {"DrawPolygon@16", &hwdriver.pfnDrawPolygon}, - {"RenderSkyDome@4", &hwdriver.pfnRenderSkyDome}, - {"SetBlend@4", &hwdriver.pfnSetBlend}, - {"ClearBuffer@12", &hwdriver.pfnClearBuffer}, - {"SetTexture@4", &hwdriver.pfnSetTexture}, - {"UpdateTexture@4", &hwdriver.pfnUpdateTexture}, - {"DeleteTexture@4", &hwdriver.pfnDeleteTexture}, - {"ReadRect@24", &hwdriver.pfnReadRect}, - {"GClipRect@20", &hwdriver.pfnGClipRect}, - {"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache}, - {"ClearCacheList@0", &hwdriver.pfnClearCacheList}, - {"SetSpecialState@8", &hwdriver.pfnSetSpecialState}, - {"DrawModel@16", &hwdriver.pfnDrawModel}, - {"SetTransform@4", &hwdriver.pfnSetTransform}, - {"GetTextureUsed@0", &hwdriver.pfnGetTextureUsed}, - {"GetRenderVersion@0", &hwdriver.pfnGetRenderVersion}, -#ifdef SHUFFLE - {"PostImgRedraw@4", &hwdriver.pfnPostImgRedraw}, -#endif - {"FlushScreenTextures@0",&hwdriver.pfnFlushScreenTextures}, - {"StartScreenWipe@0", &hwdriver.pfnStartScreenWipe}, - {"EndScreenWipe@0", &hwdriver.pfnEndScreenWipe}, - {"DoScreenWipe@0", &hwdriver.pfnDoScreenWipe}, - {"DrawIntermissionBG@0",&hwdriver.pfnDrawIntermissionBG}, - {"MakeScreenTexture@0", &hwdriver.pfnMakeScreenTexture}, - {"MakeScreenFinalTexture@0", &hwdriver.pfnMakeScreenFinalTexture}, - {"DrawScreenFinalTexture@8", &hwdriver.pfnDrawScreenFinalTexture}, -#else - {"Init", &hwdriver.pfnInit}, - {"Shutdown", &hwdriver.pfnShutdown}, - {"GetModeList", &hwdriver.pfnGetModeList}, - {"SetPalette", &hwdriver.pfnSetPalette}, - {"FinishUpdate", &hwdriver.pfnFinishUpdate}, - {"Draw2DLine", &hwdriver.pfnDraw2DLine}, - {"DrawPolygon", &hwdriver.pfnDrawPolygon}, - {"RenderSkyDome", &hwdriver.pfnRenderSkyDome}, - {"SetBlend", &hwdriver.pfnSetBlend}, - {"ClearBuffer", &hwdriver.pfnClearBuffer}, - {"SetTexture", &hwdriver.pfnSetTexture}, - {"UpdateTexture", &hwdriver.pfnUpdateTexture}, - {"DeleteTexture", &hwdriver.pfnDeleteTexture}, - {"ReadRect", &hwdriver.pfnReadRect}, - {"GClipRect", &hwdriver.pfnGClipRect}, - {"ClearMipMapCache", &hwdriver.pfnClearMipMapCache}, - {"ClearCacheList", &hwdriver.pfnClearCacheList}, - {"SetSpecialState", &hwdriver.pfnSetSpecialState}, - {"DrawModel", &hwdriver.pfnDrawModel}, - {"SetTransform", &hwdriver.pfnSetTransform}, - {"GetTextureUsed", &hwdriver.pfnGetTextureUsed}, - {"GetRenderVersion", &hwdriver.pfnGetRenderVersion}, -#ifdef SHUFFLE - {"PostImgRedraw", &hwdriver.pfnPostImgRedraw}, -#endif - {"FlushScreenTextures", &hwdriver.pfnFlushScreenTextures}, - {"StartScreenWipe", &hwdriver.pfnStartScreenWipe}, - {"EndScreenWipe", &hwdriver.pfnEndScreenWipe}, - {"DoScreenWipe", &hwdriver.pfnDoScreenWipe}, - {"DrawIntermissionBG", &hwdriver.pfnDrawIntermissionBG}, - {"MakeScreenTexture", &hwdriver.pfnMakeScreenTexture}, - {"MakeScreenFinalTexture", &hwdriver.pfnMakeScreenFinalTexture}, - {"DrawScreenFinalTexture", &hwdriver.pfnDrawScreenFinalTexture}, -#endif - {NULL,NULL} -}; - -BOOL Init3DDriver (LPCSTR dllName) -{ - hwdModule = LoadDLL(dllName, hwdFuncTable); - return (hwdModule != NULL); -} - -VOID Shutdown3DDriver (VOID) -{ - UnloadDLL(&hwdModule); -} -#endif - -#ifdef HW3SOUND -static HMODULE hwsModule = NULL; - -static loadfunc_t hwsFuncTable[] = { -#ifdef _X86_ - {"Startup@8", &hw3ds_driver.pfnStartup}, - {"Shutdown@0", &hw3ds_driver.pfnShutdown}, - {"AddSfx@4", &hw3ds_driver.pfnAddSfx}, - {"AddSource@8", &hw3ds_driver.pfnAddSource}, - {"StartSource@4", &hw3ds_driver.pfnStartSource}, - {"StopSource@4", &hw3ds_driver.pfnStopSource}, - {"GetHW3DSVersion@0", &hw3ds_driver.pfnGetHW3DSVersion}, - {"BeginFrameUpdate@0", &hw3ds_driver.pfnBeginFrameUpdate}, - {"EndFrameUpdate@0", &hw3ds_driver.pfnEndFrameUpdate}, - {"IsPlaying@4", &hw3ds_driver.pfnIsPlaying}, - {"UpdateListener@8", &hw3ds_driver.pfnUpdateListener}, - {"UpdateSourceParms@12", &hw3ds_driver.pfnUpdateSourceParms}, - {"SetCone@8", &hw3ds_driver.pfnSetCone}, - {"SetGlobalSfxVolume@4", &hw3ds_driver.pfnSetGlobalSfxVolume}, - {"Update3DSource@8", &hw3ds_driver.pfnUpdate3DSource}, - {"ReloadSource@8", &hw3ds_driver.pfnReloadSource}, - {"KillSource@4", &hw3ds_driver.pfnKillSource}, - {"KillSfx@4", &hw3ds_driver.pfnKillSfx}, - {"GetHW3DSTitle@8", &hw3ds_driver.pfnGetHW3DSTitle}, -#else - {"Startup", &hw3ds_driver.pfnStartup}, - {"Shutdown", &hw3ds_driver.pfnShutdown}, - {"AddSfx", &hw3ds_driver.pfnAddSfx}, - {"AddSource", &hw3ds_driver.pfnAddSource}, - {"StartSource", &hw3ds_driver.pfnStartSource}, - {"StopSource", &hw3ds_driver.pfnStopSource}, - {"GetHW3DSVersion", &hw3ds_driver.pfnGetHW3DSVersion}, - {"BeginFrameUpdate", &hw3ds_driver.pfnBeginFrameUpdate}, - {"EndFrameUpdate", &hw3ds_driver.pfnEndFrameUpdate}, - {"IsPlaying", &hw3ds_driver.pfnIsPlaying}, - {"UpdateListener", &hw3ds_driver.pfnUpdateListener}, - {"UpdateSourceParms", &hw3ds_driver.pfnUpdateSourceParms}, - {"SetCone", &hw3ds_driver.pfnSetCone}, - {"SetGlobalSfxVolume", &hw3ds_driver.pfnSetGlobalSfxVolume}, - {"Update3DSource", &hw3ds_driver.pfnUpdate3DSource}, - {"ReloadSource", &hw3ds_driver.pfnReloadSource}, - {"KillSource", &hw3ds_driver.pfnKillSource}, - {"KillSfx", &hw3ds_driver.pfnKillSfx}, - {"GetHW3DSTitle", &hw3ds_driver.pfnGetHW3DSTitle}, -#endif - {NULL, NULL} -}; - -BOOL Init3DSDriver(LPCSTR dllName) -{ - hwsModule = LoadDLL(dllName, hwsFuncTable); - return (hwsModule != NULL); -} - -VOID Shutdown3DSDriver (VOID) -{ - UnloadDLL(&hwsModule); -} -#endif -#endif //_WINDOWS diff --git a/src/win32/win_dll.h b/src/win32/win_dll.h deleted file mode 100644 index b4b259587..000000000 --- a/src/win32/win_dll.h +++ /dev/null @@ -1,31 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief load/unload a DLL at run-time - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include - -#ifdef HWRENDER -BOOL Init3DDriver (LPCSTR dllName); -VOID Shutdown3DDriver (VOID); -#endif - -#ifdef HW3SOUND -BOOL Init3DSDriver(LPCSTR dllName); -VOID Shutdown3DSDriver(VOID); -#endif diff --git a/src/win32/win_main.c b/src/win32/win_main.c deleted file mode 100644 index e1d90881b..000000000 --- a/src/win32/win_main.c +++ /dev/null @@ -1,674 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief Win32 WinMain Entry Point -/// -/// Win32 Sonic Robo Blast 2 -/// -/// NOTE: -/// To compile WINDOWS SRB2 version : define a '_WINDOWS' symbol. -/// to do this go to Project/Settings/ menu, click C/C++ tab, in -/// 'Preprocessor definitions:' add '_WINDOWS' - -#include "../doomdef.h" -#include - -#ifdef _WINDOWS - -#include "../doomstat.h" // netgame -#include "resource.h" - -#include "../m_argv.h" -#include "../d_main.h" -#include "../i_system.h" - -#include "../keys.h" //hack quick test - -#include "../console.h" - -#include "fabdxlib.h" -#include "win_main.h" -#include "win_dbg.h" -#include "../s_sound.h" // pause sound with handling -#include "../g_input.h" // KEY_MOUSEWHEELxxx -#include "../screen.h" // for BASEVID* - -// MSWheel support for Win95/NT3.51 -#include - -#ifndef WM_XBUTTONDOWN -#define WM_XBUTTONDOWN 523 -#endif -#ifndef WM_XBUTTONUP -#define WM_XBUTTONUP 524 -#endif -#ifndef MK_XBUTTON1 -#define MK_XBUTTON1 32 -#endif -#ifndef MK_XBUTTON2 -#define MK_XBUTTON2 64 -#endif - -typedef BOOL (WINAPI *p_IsDebuggerPresent)(VOID); - -HWND hWndMain = NULL; -static HCURSOR windowCursor = NULL; // main window cursor - -static LPCSTR wClassName = "SRB2WC"; - -INT appActive = false; // app window is active - -#ifdef LOGMESSAGES -FILE *logstream; -#endif - -BOOL nodinput = FALSE; - -static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - event_t ev; //Doom input event - int mouse_keys; - - // judgecutor: - // Response MSH Mouse Wheel event - - if (message == MSHWheelMessage) - { - message = WM_MOUSEWHEEL; - wParam <<= 16; - } - - //I_OutputMsg("MainWndproc: %p,%i,%i,%i",hWnd, message, wParam, (UINT)lParam); - - switch (message) - { - case WM_CREATE: - nodinput = M_CheckParm("-nodinput"); - if (!nodinput && !LoadDirectInput()) - nodinput = true; - break; - - case WM_ACTIVATEAPP: // Handle task switching - appActive = (int)wParam; - - //coming back from alt-tab? reset the palette. - if (appActive) - vid.recalc = true; - - // pause music when alt-tab - if (appActive && !paused) - S_ResumeAudio(); - else if (!paused) - S_PauseAudio(); - { - HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - DWORD mode; - if (ci != INVALID_HANDLE_VALUE && GetFileType(ci) == FILE_TYPE_CHAR && GetConsoleMode(ci, &mode)) - appActive = true; - } - InvalidateRect (hWnd, NULL, TRUE); - break; - - case WM_PAINT: - if (!appActive && !bAppFullScreen && !netgame) - // app becomes inactive (if windowed) - { - // Paint "Game Paused" in the middle of the screen - PAINTSTRUCT ps; - RECT rect; - HDC hdc = BeginPaint (hWnd, &ps); - GetClientRect (hWnd, &rect); - DrawText (hdc, TEXT("Game Paused"), -1, &rect, - DT_SINGLELINE | DT_CENTER | DT_VCENTER); - EndPaint (hWnd, &ps); - return 0; - } - - break; - - case WM_QUERYNEWPALETTE: - RestoreDDPalette(); - return TRUE; - - case WM_PALETTECHANGED: - if((HWND)wParam != hWnd) - RestoreDDPalette(); - break; - - //case WM_RBUTTONDOWN: - //case WM_LBUTTONDOWN: - - case WM_MOVE: - if (bAppFullScreen) - { - SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); - return 0; - } - else - { - windowPosX = (SHORT) LOWORD(lParam); // horizontal position - windowPosY = (SHORT) HIWORD(lParam); // vertical position - break; - } - break; - - // This is where switching windowed/fullscreen is handled. DirectDraw - // objects must be destroyed, recreated, and artwork reloaded. - - case WM_DISPLAYCHANGE: - case WM_SIZE: - break; - - case WM_SETCURSOR: - if (bAppFullScreen) - SetCursor(NULL); - else - SetCursor(windowCursor); - return TRUE; - - case WM_KEYUP: - ev.type = ev_keyup; - goto handleKeyDoom; - break; - - case WM_KEYDOWN: - ev.type = ev_keydown; - - handleKeyDoom: - ev.data1 = 0; - if (wParam == VK_PAUSE) - // intercept PAUSE key - { - ev.data1 = KEY_PAUSE; - } - else if (!keyboard_started) - // post some keys during the game startup - // (allow escaping from network synchronization, or pressing enter after - // an error message in the console) - { - 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 - } - } - - if (ev.data1) - D_PostEvent (&ev); - - return 0; - break; - - // judgecutor: - // Handle mouse events - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_MOUSEMOVE: - if (nodinput) - { - mouse_keys = 0; - if (wParam & MK_LBUTTON) - mouse_keys |= 1; - if (wParam & MK_RBUTTON) - mouse_keys |= 2; - if (wParam & MK_MBUTTON) - mouse_keys |= 4; - I_GetSysMouseEvents(mouse_keys); - } - break; - - case WM_XBUTTONUP: - if (nodinput) - { - ev.type = ev_keyup; - ev.data1 = KEY_MOUSE1 + 3 + HIWORD(wParam); - D_PostEvent(&ev); - return TRUE; - } - break; - case WM_XBUTTONDOWN: - if (nodinput) - { - ev.type = ev_keydown; - ev.data1 = KEY_MOUSE1 + 3 + HIWORD(wParam); - D_PostEvent(&ev); - return TRUE; - } - break; - case WM_MOUSEWHEEL: - //I_OutputMsg("MW_WHEEL dispatched.\n"); - ev.type = ev_keydown; - if ((INT16)HIWORD(wParam) > 0) - ev.data1 = KEY_MOUSEWHEELUP; - else - ev.data1 = KEY_MOUSEWHEELDOWN; - D_PostEvent(&ev); - break; - - case WM_SETTEXT: - COM_BufAddText((LPCSTR)lParam); - return TRUE; - break; - - case WM_CLOSE: - PostQuitMessage(0); //to quit while in-game - ev.data1 = KEY_ESCAPE; //to exit network synchronization - ev.type = ev_keydown; - D_PostEvent (&ev); - return 0; - case WM_DESTROY: - //faB: main app loop will exit the loop and proceed with I_Quit() - PostQuitMessage(0); - break; - - case WM_SYSCOMMAND: - // Don't allow the keyboard to activate the menu. - if(wParam == SC_KEYMENU) - return 0; - - break; - - default: - break; - } - - return DefWindowProc(hWnd, message, wParam, lParam); -} - -static inline VOID OpenTextConsole(VOID) -{ - HANDLE ci, co; - BOOL console; - -#ifdef _DEBUG - console = M_CheckParm("-noconsole") == 0; -#else - console = M_CheckParm("-console") != 0; -#endif - - dedicated = M_CheckParm("-dedicated") != 0; - - if (M_CheckParm("-detachconsole")) - { - if (FreeConsole()) - { - I_OutputMsg("Detatched console.\n"); - console = TRUE; //lets get back a console - } - else - { - I_OutputMsg("No console to detatch.\n"); - I_ShowLastError(FALSE); - } - } - - if (dedicated || console) - { - if (AllocConsole()) //Let get the real console HANDLEs, because Mingw's Bash is bad! - { - SetConsoleTitleA("SRB2 Console"); - CONS_Printf(M_GetText("Hello, it's me, SRB2's Console Window\n")); - } - else - { - I_OutputMsg("We have a console already.\n"); - I_ShowLastError(FALSE); - return; - } - } - else - return; - - ci = CreateFile(TEXT("CONIN$") , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (ci != INVALID_HANDLE_VALUE) - { - HANDLE sih = GetStdHandle(STD_INPUT_HANDLE); - if (sih != ci) - { - I_OutputMsg("Old STD_INPUT_HANDLE: %p\nNew STD_INPUT_HANDLE: %p\n", sih, ci); - SetStdHandle(STD_INPUT_HANDLE,ci); - } - else - I_OutputMsg("STD_INPUT_HANDLE already set at %p\n", ci); - - if (GetFileType(ci) == FILE_TYPE_CHAR) - { -#if 0 - const DWORD CM = ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT; //default mode but no ENABLE_MOUSE_INPUT - if (SetConsoleMode(ci,CM)) - { - I_OutputMsg("Disabled mouse input on the console\n"); - } - else - { - I_OutputMsg("Could not disable mouse input on the console\n"); - I_ShowLastError(FALSE); - } -#endif - } - else - I_OutputMsg("Handle CONIN$ in not a Console HANDLE\n"); - } - else - { - I_OutputMsg("Could not get a CONIN$ HANDLE\n"); - I_ShowLastError(FALSE); - } - - co = CreateFile(TEXT("CONOUT$"), GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (co != INVALID_HANDLE_VALUE) - { - HANDLE soh = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE seh = GetStdHandle(STD_ERROR_HANDLE); - if (soh != co) - { - I_OutputMsg("Old STD_OUTPUT_HANDLE: %p\nNew STD_OUTPUT_HANDLE: %p\n", soh, co); - SetStdHandle(STD_OUTPUT_HANDLE,co); - } - else - I_OutputMsg("STD_OUTPUT_HANDLE already set at %p\n", co); - if (seh != co) - { - I_OutputMsg("Old STD_ERROR_HANDLE: %p\nNew STD_ERROR_HANDLE: %p\n", seh, co); - SetStdHandle(STD_ERROR_HANDLE,co); - } - else - I_OutputMsg("STD_ERROR_HANDLE already set at %p\n", co); - } - else - I_OutputMsg("Could not get a CONOUT$ HANDLE\n"); -} - - -// -// Do that Windows initialization stuff... -// -static HWND OpenMainWindow (HINSTANCE hInstance, LPSTR wTitle) -{ - const LONG styles = WS_CAPTION|WS_POPUP|WS_SYSMENU, exstyles = 0; - HWND hWnd; - WNDCLASSEXA wc; - RECT bounds; - - // Set up and register window class - ZeroMemory(&wc, sizeof(wc)); - wc.cbSize = sizeof(wc); - wc.style = CS_HREDRAW | CS_VREDRAW /*| CS_DBLCLKS*/; - wc.lpfnWndProc = MainWndproc; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DLICON1)); - windowCursor = LoadCursor(NULL, IDC_WAIT); //LoadCursor(hInstance, MAKEINTRESOURCE(IDC_DLCURSOR1)); - wc.hCursor = windowCursor; - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszClassName = wClassName; - - if (!RegisterClassExA(&wc)) - { - I_OutputMsg("Error doing RegisterClassExA\n"); - I_ShowLastError(TRUE); - return INVALID_HANDLE_VALUE; - } - - // Create a window - // CreateWindowEx - seems to create just the interior, not the borders - - bounds.left = 0; - bounds.right = dedicated ? 0 : specialmodes[0].width; - bounds.top = 0; - bounds.bottom = dedicated ? 0 : specialmodes[0].height; - - AdjustWindowRectEx(&bounds, styles, FALSE, exstyles); - - hWnd = CreateWindowExA( - exstyles, //ExStyle - wClassName, //Classname - wTitle, //Windowname - styles, //dwStyle //WS_VISIBLE|WS_POPUP for bAppFullScreen - 0, - 0, - bounds.right - bounds.left, //GetSystemMetrics(SM_CXSCREEN), - bounds.bottom - bounds.top, //GetSystemMetrics(SM_CYSCREEN), - NULL, //hWnd Parent - NULL, //hMenu Menu - hInstance, - NULL); - - if (hWnd == INVALID_HANDLE_VALUE) - { - I_OutputMsg("Error doing CreateWindowExA\n"); - I_ShowLastError(TRUE); - } - - return hWnd; -} - - -static inline BOOL tlErrorMessage(const TCHAR *err) -{ - /* make the cursor visible */ - SetCursor(LoadCursor(NULL, IDC_ARROW)); - - // - // warn user if there is one - // - printf("Error %s..\n", err); - fflush(stdout); - - MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK); - return FALSE; -} - - -// ------------------ -// Command line stuff -// ------------------ -#define MAXCMDLINEARGS 64 -static char * myWargv[MAXCMDLINEARGS+1]; -static char myCmdline[512]; - -static VOID GetArgcArgv (LPSTR cmdline) -{ - LPSTR tokenstr; - size_t i = 0, len; - char cSep = ' '; - BOOL bCvar = FALSE, prevCvar = FALSE; - - // split arguments of command line into argv - strlcpy (myCmdline, cmdline, sizeof(myCmdline)); // in case window's cmdline is in protected memory..for strtok - len = strlen (myCmdline); - - myargc = 0; - while (myargc < MAXCMDLINEARGS) - { - // get token - while (myCmdline[i] == cSep) - i++; - if (i >= len) - break; - tokenstr = myCmdline + i; - if (myCmdline[i] == '"') - { - cSep = '"'; - i++; - if (!prevCvar) //cvar leave the "" in - tokenstr++; - } - else - cSep = ' '; - - //cvar - if (myCmdline[i] == '+' && cSep == ' ') //a + begins a cvarname, but not after quotes - bCvar = TRUE; - else - bCvar = FALSE; - - while (myCmdline[i] && - myCmdline[i] != cSep) - i++; - - if (myCmdline[i] == '"') - { - cSep = ' '; - if (prevCvar) - i++; // get ending " quote in arg - } - - prevCvar = bCvar; - - if (myCmdline + i > tokenstr) - { - myWargv[myargc++] = tokenstr; - } - - if (!myCmdline[i] || i >= len) - break; - - myCmdline[i++] = '\0'; - } - myWargv[myargc] = NULL; - - // m_argv.c uses myargv[], we used myWargv because we fill the arguments ourselves - // and myargv is just a pointer, so we set it to point myWargv - myargv = myWargv; -} - -static inline VOID MakeCodeWritable(VOID) -{ -#ifdef USEASM // Disable write-protection of code segment - DWORD OldRights; - const DWORD NewRights = PAGE_EXECUTE_READWRITE; - PBYTE pBaseOfImage = (PBYTE)GetModuleHandle(NULL); - PIMAGE_DOS_HEADER dosH =(PIMAGE_DOS_HEADER)pBaseOfImage; - PIMAGE_NT_HEADERS ntH = (PIMAGE_NT_HEADERS)(pBaseOfImage + dosH->e_lfanew); - PIMAGE_OPTIONAL_HEADER oH = (PIMAGE_OPTIONAL_HEADER) - ((PBYTE)ntH + sizeof (IMAGE_NT_SIGNATURE) + sizeof (IMAGE_FILE_HEADER)); - LPVOID pA = pBaseOfImage+oH->BaseOfCode; - SIZE_T pS = oH->SizeOfCode; -#if 1 // try to find the text section - PIMAGE_SECTION_HEADER ntS = IMAGE_FIRST_SECTION (ntH); - WORD s; - for (s = 0; s < ntH->FileHeader.NumberOfSections; s++) - { - if (memcmp (ntS[s].Name, ".text\0\0", 8) == 0) - { - pA = pBaseOfImage+ntS[s].VirtualAddress; - pS = ntS[s].Misc.VirtualSize; - break; - } - } -#endif - - if (!VirtualProtect(pA,pS,NewRights,&OldRights)) - I_Error("Could not make code writable\n"); -#endif -} - -// ----------------------------------------------------------------------------- -// HandledWinMain : called by exception handler -// ----------------------------------------------------------------------------- -static int WINAPI HandledWinMain(HINSTANCE hInstance) -{ - LPSTR args; - -#ifdef LOGMESSAGES - // DEBUG!!! - set logstream to NULL to disable debug log - // Replace WIN32 filehandle with standard C calls, because WIN32 doesn't handle \n properly. - logstream = fopen(va("%s"PATHSEP"%s", srb2home, "log.txt"), "wt"); -#endif - - // fill myargc,myargv for m_argv.c retrieval of cmdline arguments - args = GetCommandLineA(); - CONS_Printf("Command line arguments: '%s'\n", args); - GetArgcArgv(args); - // Create a text console window - OpenTextConsole(); - -#ifdef _DEBUG - { - int i; - CONS_Printf("Myargc: %d\n", myargc); - for (i = 0; i < myargc; i++) - CONS_Printf("myargv[%d] : '%s'\n", i, myargv[i]); - } -#endif - - // open a dummy window, both OpenGL and DirectX need one. - if ((hWndMain = OpenMainWindow(hInstance, va("SRB2 "VERSIONSTRING))) == INVALID_HANDLE_VALUE) - { - tlErrorMessage(TEXT("Couldn't open window")); - return FALSE; - } - - // currently starts DirectInput - CONS_Printf("I_StartupSystem() ...\n"); - I_StartupSystem(); - MakeCodeWritable(); - - // startup SRB2 - CONS_Printf("Setting up SRB2...\n"); - D_SRB2Main(); - CONS_Printf("Entering main game loop...\n"); - // never return - D_SRB2Loop(); - - // back to Windoze - return 0; -} - -// ----------------------------------------------------------------------------- -// Exception handler calls WinMain for catching exceptions -// ----------------------------------------------------------------------------- -int WINAPI WinMain (HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - int Result = -1; - UNREFERENCED_PARAMETER(hPrevInstance); - UNREFERENCED_PARAMETER(lpCmdLine); - UNREFERENCED_PARAMETER(nCmdShow); - - { -#if 0 - p_IsDebuggerPresent pfnIsDebuggerPresent = (p_IsDebuggerPresent)GetProcAddress(GetModuleHandleA("kernel32.dll"),"IsDebuggerPresent"); - if((!pfnIsDebuggerPresent || !pfnIsDebuggerPresent()) -#ifdef BUGTRAP - && !InitBugTrap() -#endif - ) -#endif - { - LoadLibraryA("exchndl.dll"); - } - } -#ifndef __MINGW32__ - prevExceptionFilter = SetUnhandledExceptionFilter(RecordExceptionInfo); -#endif - Result = HandledWinMain(hInstance); -#ifdef BUGTRAP - // This is safe even if BT didn't start. - ShutdownBugTrap(); -#endif - - return Result; -} -#endif //_WINDOWS diff --git a/src/win32/win_main.h b/src/win32/win_main.h deleted file mode 100644 index 326a813dd..000000000 --- a/src/win32/win_main.h +++ /dev/null @@ -1,45 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief Win32 Sharing - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include -#include - -extern HWND hWndMain; - -extern INT appActive; - -VOID I_GetSysMouseEvents(INT mouse_state); -extern UINT MSHWheelMessage; - -extern BOOL nodinput; -BOOL LoadDirectInput(VOID); - -//faB: midi channel Volume set is delayed by the MIDI stream callback thread, see win_snd.c -#define WM_MSTREAM_UPDATEVOLUME (WM_USER + 101) - -// defined in win_sys.c -VOID I_BeginProfile(VOID); //for timing code -DWORD I_EndProfile(VOID); - -VOID I_ShowLastError(BOOL MB); -VOID I_LoadingScreen (LPCSTR msg); - -VOID I_RestartSysMouse(VOID); -VOID I_DoStartupMouse(VOID); diff --git a/src/win32/win_net.c b/src/win32/win_net.c deleted file mode 100644 index 62c081bbe..000000000 --- a/src/win32/win_net.c +++ /dev/null @@ -1,42 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief Win32 network interface - -#include "../doomdef.h" -#include "../m_argv.h" -#include "../i_net.h" - -#ifdef _WINDOWS - -// -// NETWORKING -// - -// -// I_InitNetwork -// -boolean I_InitNetwork(void) -{ - if (M_CheckParm ("-net")) - { - I_Error("The Win32 version of SRB2 doesn't work with external drivers like ipxsetup, sersetup, or doomatic\n" - "Read the documentation about \"-server\" and \"-connect\" parameters or just use the launcher\n"); - } - - return false; -} -#endif diff --git a/src/win32/win_snd.c b/src/win32/win_snd.c deleted file mode 100644 index 13f766728..000000000 --- a/src/win32/win_snd.c +++ /dev/null @@ -1,959 +0,0 @@ -/// \file -/// \brief FMOD Ex interface for sound -#include "../doomdef.h" -#include "../sounds.h" -#include "../i_sound.h" -#include "../s_sound.h" -#include "../w_wad.h" -#include "../z_zone.h" -#include "../byteptr.h" - -#include // FMOD Ex -#define errcode _errcode -#include -#undef errcode - -#ifdef HAVE_LIBGME -#include "gme/gme.h" -#define GME_TREBLE 5.0 -#define GME_BASS 1.0 - -#ifdef HAVE_ZLIB -#ifndef _MSC_VER -#ifndef _LARGEFILE64_SOURCE -#define _LARGEFILE64_SOURCE -#endif -#endif - -#ifndef _LFS64_LARGEFILE -#define _LFS64_LARGEFILE -#endif - -#ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 0 -#endif - -#include "zlib.h" -#endif // HAVE_ZLIB -#endif // HAVE_LIBGME - -static FMOD_SYSTEM *fsys; -static FMOD_SOUND *music_stream; -static FMOD_CHANNEL *music_channel; - -static UINT8 music_volume, midi_volume, sfx_volume; -static INT32 current_track; - -#ifdef HAVE_LIBGME -static Music_Emu *gme; -#endif - -// -// SYSTEM -// - -// spew console messages for general errors. -static void FMR_Debug(FMOD_RESULT e, int line) -{ - if (e != FMOD_OK) - CONS_Alert(CONS_ERROR, "FMOD:%d - %s\n", line, FMOD_ErrorString(e)); -} -#define FMR(x) FMR_Debug(x, __LINE__) - -// for operations on music_channel ONLY. -// returns false if music was released. -// (in other words, if !FMR_MUSIC(op) return immediately, -// because music_stream and music_channel are no longer valid.) -static boolean FMR_Music_Debug(FMOD_RESULT e, int line) -{ - switch(e) - { - case FMOD_ERR_INVALID_HANDLE: // non-looping song ended - case FMOD_ERR_CHANNEL_STOLEN: // song ended and then sfx was played - FMOD_Sound_Release(music_stream); - music_stream = NULL; - return false; - default: - FMR_Debug(e, line); - break; - } - return true; -} -#define FMR_MUSIC(x) FMR_Music_Debug(x, __LINE__) - -void I_StartupSound(void) -{ - I_Assert(!sound_started); - sound_started = true; - - FMR(FMOD_System_Create(&fsys)); - FMR(FMOD_System_SetDSPBufferSize(fsys, 44100 / 30, 2)); - FMR(FMOD_System_Init(fsys, 64, FMOD_INIT_VOL0_BECOMES_VIRTUAL, NULL)); - music_stream = NULL; -#ifdef HAVE_LIBGME - gme = NULL; -#endif - current_track = -1; -} - -void I_ShutdownSound(void) -{ - I_Assert(sound_started); - sound_started = false; - -#ifdef HAVE_LIBGME - if (gme) - gme_delete(gme); -#endif - FMR(FMOD_System_Release(fsys)); -} - -void I_UpdateSound(void) -{ - FMR(FMOD_System_Update(fsys)); -} - -#ifdef HAVE_LIBGME -// Callback hook to read streaming GME data. -static FMOD_RESULT F_CALLBACK GMEReadCallback(FMOD_SOUND *sound, void *data, unsigned int datalen) -{ - Music_Emu *emu; - void *emuvoid = NULL; - // get our emu - FMR(FMOD_Sound_GetUserData(sound, &emuvoid)); - emu = emuvoid; - // no emu? no play. - if (!emu) - return FMOD_ERR_FILE_EOF; - if (gme_track_ended(emu)) - { - // don't delete the primary music stream - if (emu == gme) - return FMOD_ERR_FILE_EOF; - // do delete sfx streams - FMR(FMOD_Sound_SetUserData(sound, NULL)); - gme_delete(emu); - return FMOD_ERR_FILE_EOF; - } - // play beautiful musics theme of ancient land. - if (gme_play(emu, datalen/2, data)) - return FMOD_ERR_FILE_BAD; - // O.K - return FMOD_OK; -} -#endif - -// -// SFX -// - -// convert doom format sound (signed 8bit) -// to an fmod format sound (unsigned 8bit) -// and return the FMOD_SOUND. -static inline FMOD_SOUND *ds2fmod(char *stream) -{ - FMOD_SOUND *sound; - UINT16 ver; - UINT16 freq; - UINT32 samples; - FMOD_CREATESOUNDEXINFO fmt; - UINT32 i; - UINT8 *p; - - // lump header - ver = READUINT16(stream); // sound version format? - if (ver != 3) // It should be 3 if it's a doomsound... - return NULL; // onos! it's not a doomsound! - freq = READUINT16(stream); - samples = READUINT32(stream); - //CONS_Printf("FMT: v%d f%d, s%d, b%d\n", ver, freq, samples, bps); - - memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO)); - fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); - - // convert to unsigned - fmt.format = FMOD_SOUND_FORMAT_PCM8; // 8bit - fmt.length = samples*1; // 1 bps - fmt.numchannels = 1; // mono - fmt.defaultfrequency = freq; - - // Make a duplicate of the stream to change format. - p = Z_Malloc(fmt.length, PU_SOUND, NULL); - for (i = 0; i < fmt.length; i++) - p[i] = (UINT8)(stream[i]+0x80); // convert from signed to unsigned - stream = (char *)p; - - // Create FMOD_SOUND. - FMR(FMOD_System_CreateSound(fsys, stream, FMOD_CREATESAMPLE|FMOD_OPENMEMORY|FMOD_OPENRAW|FMOD_SOFTWARE|FMOD_LOWMEM, &fmt, &sound)); - - Z_Free(stream); // FMOD made its own copy, so we don't need this anymore. - return sound; -} - -void *I_GetSfx(sfxinfo_t *sfx) -{ - FMOD_SOUND *sound; - char *lump; - FMOD_CREATESOUNDEXINFO fmt; -#ifdef HAVE_LIBGME - Music_Emu *emu; - gme_info_t *info; -#endif - - if (sfx->lumpnum == LUMPERROR) - sfx->lumpnum = S_GetSfxLumpNum(sfx); - sfx->length = W_LumpLength(sfx->lumpnum); - - lump = W_CacheLumpNum(sfx->lumpnum, PU_SOUND); - sound = ds2fmod(lump); - if (sound) - { - Z_Free(lump); - return sound; - } - - // It's not a doom sound. - // Try to read it as an FMOD sound? - - memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO)); - fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); - fmt.length = sfx->length; - -#ifdef HAVE_LIBGME - // VGZ format - if ((UINT8)lump[0] == 0x1F - && (UINT8)lump[1] == 0x8B) - { -#ifdef HAVE_ZLIB - UINT8 *inflatedData; - size_t inflatedLen; - z_stream stream; - int zErr; // Somewhere to handle any error messages zlib tosses out - - memset(&stream, 0x00, sizeof (z_stream)); // Init zlib stream - // Begin the inflation process - inflatedLen = *(UINT32 *)(lump + (sfx->length-4)); // Last 4 bytes are the decompressed size, typically - inflatedData = (UINT8 *)Z_Malloc(inflatedLen, PU_SOUND, NULL); // Make room for the decompressed data - stream.total_in = stream.avail_in = sfx->length; - stream.total_out = stream.avail_out = inflatedLen; - stream.next_in = (UINT8 *)lump; - stream.next_out = inflatedData; - - zErr = inflateInit2(&stream, 32 + MAX_WBITS); - if (zErr == Z_OK) // We're good to go - { - zErr = inflate(&stream, Z_FINISH); - if (zErr == Z_STREAM_END) { - // Run GME on new data - if (!gme_open_data(inflatedData, inflatedLen, &emu, 44100)) - { - Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around - Z_Free(lump); // We're done with the uninflated lump now, too. - - gme_start_track(emu, 0); - gme_track_info(emu, &info, 0); - - fmt.format = FMOD_SOUND_FORMAT_PCM16; - fmt.defaultfrequency = 44100; - fmt.numchannels = 2; - fmt.length = ((UINT32)info->play_length * 441 / 10) * 4; - fmt.decodebuffersize = (44100 * 2) / 35; - fmt.pcmreadcallback = GMEReadCallback; - fmt.userdata = emu; - - FMR(FMOD_System_CreateSound(fsys, NULL, FMOD_CREATESAMPLE|FMOD_OPENUSER|FMOD_SOFTWARE|FMOD_LOWMEM, &fmt, &sound)); - return sound; - } - } - else - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg); - } - (void)inflateEnd(&stream); - } - else // Hold up, zlib's got a problem - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg); - } - Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up -#else - //CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); -#endif - } - // Try to read it as a GME sound - else if (!gme_open_data(lump, sfx->length, &emu, 44100)) - { - Z_Free(lump); - - gme_start_track(emu, 0); - gme_track_info(emu, &info, 0); - - fmt.format = FMOD_SOUND_FORMAT_PCM16; - fmt.defaultfrequency = 44100; - fmt.numchannels = 2; - fmt.length = ((UINT32)info->play_length * 441 / 10) * 4; - fmt.decodebuffersize = (44100 * 2) / 35; - fmt.pcmreadcallback = GMEReadCallback; - fmt.userdata = emu; - - gme_free_info(info); - - FMR(FMOD_System_CreateSound(fsys, NULL, FMOD_CREATESAMPLE|FMOD_OPENUSER|FMOD_SOFTWARE|FMOD_LOWMEM, &fmt, &sound)); - return sound; - } -#endif - - // Ogg, Mod, Midi, etc. - FMR(FMOD_System_CreateSound(fsys, lump, FMOD_CREATESAMPLE|FMOD_OPENMEMORY|FMOD_SOFTWARE|FMOD_LOWMEM, &fmt, &sound)); - Z_Free(lump); // We're done with the lump now, at least. - return sound; -} - -void I_FreeSfx(sfxinfo_t *sfx) -{ - if (sfx->data) - FMOD_Sound_Release(sfx->data); - sfx->data = NULL; -} - -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel) -{ - FMOD_SOUND *sound; - FMOD_CHANNEL *chan; - INT32 i; - float frequency; - (void)channel; - - sound = (FMOD_SOUND *)S_sfx[id].data; - I_Assert(sound != NULL); - - FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, sound, true, &chan)); - - if (sep == 0) - sep = 1; - - FMR(FMOD_Channel_SetVolume(chan, (vol / 255.0) * (sfx_volume / 31.0))); - FMR(FMOD_Channel_SetPan(chan, (sep - 128) / 127.0)); - - FMR(FMOD_Sound_GetDefaults(sound, &frequency, NULL, NULL, NULL)); - FMR(FMOD_Channel_SetFrequency(chan, (pitch / 128.0) * frequency)); - - FMR(FMOD_Channel_SetPriority(chan, priority)); - //UNREFERENCED_PARAMETER(priority); - //FMR(FMOD_Channel_SetPriority(chan, 1 + ((0xff-vol)>>1))); // automatic priority 1 - 128 based on volume (priority 0 is music) - - FMR(FMOD_Channel_GetIndex(chan, &i)); - FMR(FMOD_Channel_SetPaused(chan, false)); - return i; -} - -void I_StopSound(INT32 handle) -{ - FMOD_CHANNEL *chan; - FMR(FMOD_System_GetChannel(fsys, handle, &chan)); - if (music_stream && chan == music_channel) - return; - FMR(FMOD_Channel_Stop(chan)); -} - -boolean I_SoundIsPlaying(INT32 handle) -{ - FMOD_CHANNEL *chan; - FMOD_BOOL playing; - FMOD_RESULT e; - FMR(FMOD_System_GetChannel(fsys, handle, &chan)); - if (music_stream && chan == music_channel) - return false; - e = FMOD_Channel_IsPlaying(chan, &playing); - switch(e) - { - case FMOD_ERR_INVALID_HANDLE: // Sound effect finished. - case FMOD_ERR_CHANNEL_STOLEN: // Sound effect interrupted. -- technically impossible due to GetChannel by handle. :( - return false; // therefore, it's not playing anymore. - default: - FMR(e); - break; - } - return (boolean)playing; -} - -// seems to never be called on an invalid channel (calls I_SoundIsPlaying first?) -// so I'm not gonna worry about it. -void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch) -{ - FMOD_CHANNEL *chan; - FMOD_SOUND *sound; - float frequency; - - FMR(FMOD_System_GetChannel(fsys, handle, &chan)); - FMR(FMOD_Channel_SetVolume(chan, (vol / 255.0) * (sfx_volume / 31.0))); - FMR(FMOD_Channel_SetPan(chan, (sep - 128) / 127.0)); - - FMR(FMOD_Channel_GetCurrentSound(chan, &sound)); - FMR(FMOD_Sound_GetDefaults(sound, &frequency, NULL, NULL, NULL)); - FMR(FMOD_Channel_SetFrequency(chan, (pitch / 128.0) * frequency)); - - //FMR(FMOD_Channel_SetPriority(chan, 1 + ((0xff-vol)>>1))); // automatic priority 1 - 128 based on volume (priority 0 is music) -} - -void I_SetSfxVolume(UINT8 volume) -{ - // volume is 0 to 31. - sfx_volume = volume; -} - -/// ------------------------ -// MUSIC SYSTEM -/// ------------------------ - -void I_InitMusic(void) -{ -} - -void I_ShutdownMusic(void) -{ - I_StopSong(); -} - -/// ------------------------ -// MUSIC PROPERTIES -/// ------------------------ - -musictype_t I_SongType(void) -{ - FMOD_SOUND_TYPE type; - -#ifdef HAVE_LIBGME - if (gme) - return MU_GME; -#endif - - if (!music_stream) - return MU_NONE; - - if (FMOD_Sound_GetFormat(music_stream, &type, NULL, NULL, NULL) == FMOD_OK) - { - switch(type) - { - case FMOD_SOUND_TYPE_WAV: - return MU_WAV; - case FMOD_SOUND_TYPE_MOD: - return MU_MOD; - case FMOD_SOUND_TYPE_MIDI: - return MU_MID; - case FMOD_SOUND_TYPE_OGGVORBIS: - return MU_OGG; - case FMOD_SOUND_TYPE_MPEG: - return MU_MP3; - case FMOD_SOUND_TYPE_FLAC: - return MU_FLAC; - default: - return MU_NONE; - } - } - else - return MU_NONE; -} - -boolean I_SongPlaying(void) -{ - return (music_stream != NULL); -} - -boolean I_SongPaused(void) -{ - FMOD_BOOL fmpaused = false; - if (music_stream) - FMOD_Channel_GetPaused(music_channel, &fmpaused); - return (boolean)fmpaused; -} - -/// ------------------------ -// MUSIC EFFECTS -/// ------------------------ - -boolean I_SetSongSpeed(float speed) -{ - FMOD_RESULT e; - float frequency; - if (!music_stream) - return false; - if (speed > 250.0f) - speed = 250.0f; //limit speed up to 250x - -#ifdef HAVE_LIBGME - // Try to set GME speed - if (gme) - { - gme_set_tempo(gme, speed); - return true; - } -#endif - - // Try to set Mod/Midi speed - e = FMOD_Sound_SetMusicSpeed(music_stream, speed); - - if (e == FMOD_ERR_FORMAT) - { - // Just change pitch instead for Ogg/etc. - FMR(FMOD_Sound_GetDefaults(music_stream, &frequency, NULL, NULL, NULL)); - FMR_MUSIC(FMOD_Channel_SetFrequency(music_channel, speed*frequency)); - } - else - FMR_MUSIC(e); - - return true; -} - -/// ------------------------ -// MUSIC PLAYBACK -/// ------------------------ - -boolean I_LoadSong(char *data, size_t len) -{ - FMOD_CREATESOUNDEXINFO fmt; - FMOD_RESULT e; - FMOD_TAG tag; - unsigned int loopstart, loopend; - - if ( -#ifdef HAVE_LIBGME - gme || -#endif - music_stream - ) - I_UnloadSong(); - - memset(&fmt, 0, sizeof(FMOD_CREATESOUNDEXINFO)); - fmt.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); - -#ifdef HAVE_LIBGME - if ((UINT8)data[0] == 0x1F - && (UINT8)data[1] == 0x8B) - { -#ifdef HAVE_ZLIB - UINT8 *inflatedData; - size_t inflatedLen; - z_stream stream; - int zErr; // Somewhere to handle any error messages zlib tosses out - - memset(&stream, 0x00, sizeof (z_stream)); // Init zlib stream - // Begin the inflation process - inflatedLen = *(UINT32 *)(data + (len-4)); // Last 4 bytes are the decompressed size, typically - inflatedData = (UINT8 *)Z_Calloc(inflatedLen, PU_MUSIC, NULL); // Make room for the decompressed data - stream.total_in = stream.avail_in = len; - stream.total_out = stream.avail_out = inflatedLen; - stream.next_in = (UINT8 *)data; - stream.next_out = inflatedData; - - zErr = inflateInit2(&stream, 32 + MAX_WBITS); - if (zErr == Z_OK) // We're good to go - { - zErr = inflate(&stream, Z_FINISH); - if (zErr == Z_STREAM_END) { - // Run GME on new data - if (!gme_open_data(inflatedData, inflatedLen, &gme, 44100)) - { - gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; - Z_Free(inflatedData); // GME supposedly makes a copy for itself, so we don't need this lying around - Z_Free(data); // We don't need this, either. - gme_set_equalizer(gme,&gmeq); - fmt.format = FMOD_SOUND_FORMAT_PCM16; - fmt.defaultfrequency = 44100; - fmt.numchannels = 2; - fmt.length = -1; - fmt.decodebuffersize = (44100 * 2) / 35; - fmt.pcmreadcallback = GMEReadCallback; - fmt.userdata = gme; - FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER, &fmt, &music_stream)); - return true; - } - } - else - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflate: %s\n", errorType, stream.msg); - } - (void)inflateEnd(&stream); - } - else // Hold up, zlib's got a problem - { - const char *errorType; - switch (zErr) - { - case Z_ERRNO: - errorType = "Z_ERRNO"; break; - case Z_STREAM_ERROR: - errorType = "Z_STREAM_ERROR"; break; - case Z_DATA_ERROR: - errorType = "Z_DATA_ERROR"; break; - case Z_MEM_ERROR: - errorType = "Z_MEM_ERROR"; break; - case Z_BUF_ERROR: - errorType = "Z_BUF_ERROR"; break; - case Z_VERSION_ERROR: - errorType = "Z_VERSION_ERROR"; break; - default: - errorType = "unknown error"; - } - CONS_Alert(CONS_ERROR,"Encountered %s when running inflateInit: %s\n", errorType, stream.msg); - } - Z_Free(inflatedData); // GME didn't open jack, but don't let that stop us from freeing this up -#else - //CONS_Alert(CONS_ERROR,"Cannot decompress VGZ; no zlib support\n"); -#endif - } - else if (!gme_open_data(data, len, &gme, 44100)) - { - gme_equalizer_t gmeq = {GME_TREBLE, GME_BASS, 0,0,0,0,0,0,0,0}; - Z_Free(data); // We don't need this anymore. - gme_set_equalizer(gme,&gmeq); - fmt.format = FMOD_SOUND_FORMAT_PCM16; - fmt.defaultfrequency = 44100; - fmt.numchannels = 2; - fmt.length = -1; - fmt.decodebuffersize = (44100 * 2) / 35; - fmt.pcmreadcallback = GMEReadCallback; - fmt.userdata = gme; - FMR(FMOD_System_CreateStream(fsys, NULL, FMOD_OPENUSER, &fmt, &music_stream)); - return true; - } -#endif - - fmt.length = len; - - e = FMOD_System_CreateStream(fsys, data, FMOD_OPENMEMORY_POINT, &fmt, &music_stream); - if (e != FMOD_OK) - { - if (e == FMOD_ERR_FORMAT) - CONS_Alert(CONS_WARNING, "Failed to play music lump due to invalid format.\n"); - else - FMR(e); - return false; - } - - // Try to find a loop point in streaming music formats (ogg, mp3) - - // A proper LOOPPOINT is its own tag, stupid. - e = FMOD_Sound_GetTag(music_stream, "LOOPPOINT", 0, &tag); - if (e != FMOD_ERR_TAGNOTFOUND) - { - FMR(e); - loopstart = atoi((char *)tag.data); // assumed to be a string data tag. - FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); - if (loopstart > 0) - FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); - return true; - } - - // Use LOOPMS for time in miliseconds. - e = FMOD_Sound_GetTag(music_stream, "LOOPMS", 0, &tag); - if (e != FMOD_ERR_TAGNOTFOUND) - { - FMR(e); - loopstart = atoi((char *)tag.data); // assumed to be a string data tag. - FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_MS, &loopend, FMOD_TIMEUNIT_PCM)); - if (loopstart > 0) - FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_MS, loopend, FMOD_TIMEUNIT_PCM)); - return true; - } - - // Try to fetch it from the COMMENT tag, like A.J. Freda - e = FMOD_Sound_GetTag(music_stream, "COMMENT", 0, &tag); - if (e != FMOD_ERR_TAGNOTFOUND) - { - char *loopText; - // Handle any errors that arose, first - FMR(e); - // Figure out where the number starts - loopText = strstr((char *)tag.data,"LOOPPOINT="); - if (loopText != NULL) - { - // Skip the "LOOPPOINT=" part. - loopText += 10; - // Convert it to our looppoint - // FMOD seems to ensure the tag is properly NULL-terminated. - // atoi will stop when it reaches anything that's not a number. - loopstart = atoi(loopText); - // Now do the rest like above - FMR(FMOD_Sound_GetLoopPoints(music_stream, NULL, FMOD_TIMEUNIT_PCM, &loopend, FMOD_TIMEUNIT_PCM)); - if (loopstart > 0) - FMR(FMOD_Sound_SetLoopPoints(music_stream, loopstart, FMOD_TIMEUNIT_PCM, loopend, FMOD_TIMEUNIT_PCM)); - } - return true; - } - - // No special loop point - return true; -} - -void I_UnloadSong(void) -{ - I_StopSong(); -#ifdef HAVE_LIBGME - if (gme) - { - gme_delete(gme); - gme = NULL; - } -#endif - if (music_stream) - { - FMR(FMOD_Sound_Release(music_stream)); - music_stream = NULL; - } -} - -boolean I_PlaySong(boolean looping) -{ -#ifdef HAVE_LIBGME - if (gme) - { - gme_start_track(gme, 0); - current_track = 0; - FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); - FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); - FMR(FMOD_Channel_SetPriority(music_channel, 0)); - return true; - } -#endif - - FMR(FMOD_Sound_SetMode(music_stream, (looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF))); - FMR(FMOD_System_PlaySound(fsys, FMOD_CHANNEL_FREE, music_stream, false, &music_channel)); - if (I_SongType() != MU_MID) - FMR(FMOD_Channel_SetVolume(music_channel, midi_volume / 31.0)); - else - FMR(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); - FMR(FMOD_Channel_SetPriority(music_channel, 0)); - current_track = 0; - - return true; -} - -void I_StopSong(void) -{ - if (music_channel) - FMR_MUSIC(FMOD_Channel_Stop(music_channel)); -} - -void I_PauseSong(void) -{ - if (music_channel) - FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, true)); -} - -void I_ResumeSong(void) -{ - if (music_channel) - FMR_MUSIC(FMOD_Channel_SetPaused(music_channel, false)); -} - -void I_SetMusicVolume(UINT8 volume) -{ - if (!music_channel) - return; - - // volume is 0 to 31. - if (I_SongType() == MU_MID) - music_volume = 31; // windows bug hack - else - music_volume = volume; - - FMR_MUSIC(FMOD_Channel_SetVolume(music_channel, music_volume / 31.0)); -} - -UINT32 I_GetSongLength(void) -{ - UINT32 length; - if (I_SongType() == MU_MID) - return 0; - FMR_MUSIC(FMOD_Sound_GetLength(music_stream, &length, FMOD_TIMEUNIT_MS)); - return length; -} - -boolean I_SetSongLoopPoint(UINT32 looppoint) -{ - (void)looppoint; - return false; -} - -UINT32 I_GetSongLoopPoint(void) -{ - return 0; -} - -boolean I_SetSongPosition(UINT32 position) -{ - FMOD_RESULT e; - if(I_SongType() == MU_MID) - // Dummy out; this works for some MIDI, but not others. - // SDL does not support this for any MIDI. - return false; - - e = FMOD_Channel_SetPosition(music_channel, position, FMOD_TIMEUNIT_MS); - if (e == FMOD_OK) - return true; - else if (e == FMOD_ERR_UNSUPPORTED // Only music modules, numbnuts! - || e == FMOD_ERR_INVALID_POSITION) // Out-of-bounds! - return false; - else // Congrats, you horribly broke it somehow - { - FMR_MUSIC(e); - return false; - } -} - -UINT32 I_GetSongPosition(void) -{ - FMOD_RESULT e; - unsigned int fmposition = 0; - if(I_SongType() == MU_MID) - // Dummy out because unsupported, even though FMOD does this correctly. - return 0; - e = FMOD_Channel_GetPosition(music_channel, &fmposition, FMOD_TIMEUNIT_MS); - if (e == FMOD_OK) - return (UINT32)fmposition; - else - return 0; -} - -boolean I_SetSongTrack(INT32 track) -{ - if (track != current_track) // If the track's already playing, then why bother? - { - FMOD_RESULT e; - - #ifdef HAVE_LIBGME - // If the specified track is within the number of tracks playing, then change it - if (gme) - { - if (track >= 0 - && track < gme_track_count(gme)) - { - gme_err_t gme_e = gme_start_track(gme,track); - if (gme_e == NULL) - { - current_track = track; - return true; - } - else - CONS_Alert(CONS_ERROR, "Encountered GME error: %s\n", gme_e); - } - return false; - } - #endif // HAVE_LIBGME - - // Try to set it via FMOD - e = FMOD_Channel_SetPosition(music_channel, (UINT32)track, FMOD_TIMEUNIT_MODORDER); - if (e == FMOD_OK) // We good - { - current_track = track; - return true; - } - else if (e == FMOD_ERR_UNSUPPORTED // Only music modules, numbnuts! - || e == FMOD_ERR_INVALID_POSITION) // Out-of-bounds! - return false; - else // Congrats, you horribly broke it somehow - { - FMR_MUSIC(e); - return false; - } - } - return false; -} - -/// ------------------------ -/// MUSIC FADING -/// ------------------------ - -void I_SetInternalMusicVolume(UINT8 volume) -{ - (void)volume; -} - -void I_StopFadingSong(void) -{ -} - -boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms, void (*callback)(void)) -{ - (void)target_volume; - (void)source_volume; - (void)ms; - (void)callback; - return false; -} - -boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)) -{ - (void)target_volume; - (void)ms; - (void)callback; - return false; -} - -boolean I_FadeOutStopSong(UINT32 ms) -{ - (void)ms; - return false; -} - -boolean I_FadeInPlaySong(UINT32 ms, boolean looping) -{ - (void)ms; - (void)looping; - return false; -} diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c deleted file mode 100644 index da0d5b47e..000000000 --- a/src/win32/win_sys.c +++ /dev/null @@ -1,3707 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief win32 system i/o -/// -/// Startup & Shutdown routines for music,sound,timer,keyboard,... -/// Signal handler to trap errors and exit cleanly. - -#include "../doomdef.h" - -#ifdef _WINDOWS - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "../m_misc.h" -#include "../i_video.h" -#include "../i_sound.h" -#include "../i_system.h" - -#include "../d_net.h" -#include "../g_game.h" - -#include "../d_main.h" - -#include "../m_argv.h" - -#include "../w_wad.h" -#include "../z_zone.h" -#include "../g_input.h" - -#include "../keys.h" - -#include "../screen.h" - -#include "../m_menu.h" - -// Wheel support for Win95/WinNT3.51 -#include - -// Taken from Win98/NT4.0 -#ifndef SM_MOUSEWHEELPRESENT -#define SM_MOUSEWHEELPRESENT 75 -#endif - -#ifndef MSH_MOUSEWHEEL -#ifdef UNICODE -#define MSH_MOUSEWHEEL L"MSWHEEL_ROLLMSG" -#else -#define MSH_MOUSEWHEEL "MSWHEEL_ROLLMSG" -#endif -#endif - -#include "win_main.h" -#include "win_dbg.h" -#include "../i_joy.h" - -#ifndef NOMUMBLE -// Mumble context string -#include "../d_clisrv.h" -#include "../byteptr.h" -#endif - -#define DIRECTINPUT_VERSION 0x0500 -// Force dinput.h to generate old DX3 headers. -#define DXVERSION_NTCOMPATIBLE 0x0300 -#include -#ifndef IDirectInputEffect_Stop -#define IDirectInputEffect_Stop(p) (p)->lpVtbl->Stop(p) -#endif -#ifndef IDirectInputEffect_SetParameters -#define IDirectInputEffect_SetParameters(p,a,b) (p)->lpVtbl->SetParameters(p,a,b) -#endif -#ifndef IDirectInputEffect_Release -#define IDirectInputEffect_Release(p) (p)->lpVtbl->Release(p) -#endif - -#include "fabdxlib.h" - -/// \brief max number of joystick buttons -#define JOYBUTTONS_MAX 32 // rgbButtons[32] -/// \brief max number of joystick button events -#define JOYBUTTONS_MIN min((JOYBUTTONS),(JOYBUTTONS_MAX)) - -/// \brief max number of joysick axies -#define JOYAXISSET_MAX 4 // (lX, lY), (lZ,lRx), (lRy, lRz), rglSlider[2] is very diff -/// \brief max number ofjoystick axis events -#define JOYAXISSET_MIN min((JOYAXISSET),(JOYAXISSET_MAX)) - -/// \brief max number of joystick hats -#define JOYHATS_MAX 4 // rgdwPOV[4]; -/// \brief max number of joystick hat events -#define JOYHATS_MIN min((JOYHATS),(JOYHATS_MAX)) - -/// \brief max number of mouse buttons -#define MOUSEBUTTONS_MAX 8 // 8 bit of BYTE and DIMOFS_BUTTON7 -/// \brief max number of muse button events -#define MOUSEBUTTONS_MIN min((MOUSEBUTTONS),(MOUSEBUTTONS_MAX)) - -// ================== -// DIRECT INPUT STUFF -// ================== -BOOL bDX0300; // if true, we created a DirectInput 0x0300 version -static LPDIRECTINPUTA lpDI = NULL; -static LPDIRECTINPUTDEVICEA lpDIK = NULL; // Keyboard -static LPDIRECTINPUTDEVICEA lpDIM = NULL; // mice -static LPDIRECTINPUTDEVICEA lpDIJ = NULL; // joystick 1P -static LPDIRECTINPUTEFFECT lpDIE[NumberofForces]; // joystick 1Es -static LPDIRECTINPUTDEVICE2A lpDIJA = NULL; // joystick 1I -static LPDIRECTINPUTDEVICEA lpDIJ2 = NULL; // joystick 2P -static LPDIRECTINPUTEFFECT lpDIE2[NumberofForces]; // joystick 1Es -static LPDIRECTINPUTDEVICE2A lpDIJ2A = NULL;// joystick 2I - -// Do not execute cleanup code more than once. See Shutdown_xxx() routines. -UINT8 graphics_started = 0; -UINT8 keyboard_started = 0; -UINT8 sound_started = 0; -static boolean mouse_enabled = false; -static boolean joystick_detected = false; -static boolean joystick2_detected = false; - -static VOID I_ShutdownKeyboard(VOID); -static VOID I_GetKeyboardEvents(VOID); -static VOID I_ShutdownJoystick(VOID); -static VOID I_ShutdownJoystick2(VOID); - -static boolean entering_con_command = false; - -// -// Why would this be system specific?? hmmmm.... -// -// it is for virtual reality system, next incoming feature :) -static ticcmd_t emptycmd; -ticcmd_t *I_BaseTiccmd(void) -{ - return &emptycmd; -} - -static ticcmd_t emptycmd2; -ticcmd_t *I_BaseTiccmd2(void) -{ - return &emptycmd2; -} - -// Allocates the base zone memory, -// this function returns a valid pointer and size, -// else it should interrupt the program immediately. -// -// now checks if mem could be allocated, this is still -// prehistoric... there's a lot to do here: memory locking, detection -// of win95 etc... -// - -// return free and total memory in the system -UINT32 I_GetFreeMem(UINT32* total) -{ - MEMORYSTATUS info; - - info.dwLength = sizeof (MEMORYSTATUS); - GlobalMemoryStatus(&info); - if (total) - *total = (UINT32)info.dwTotalPhys; - return (UINT32)info.dwAvailPhys; -} - -// --------- -// I_Profile -// Two little functions to profile our code using the high resolution timer -// --------- -static LARGE_INTEGER ProfileCount; -VOID I_BeginProfile(VOID) -{ - if (!QueryPerformanceCounter(&ProfileCount)) - I_Error("I_BeginProfile failed"); // can't profile without the high res timer -} - -// we're supposed to use this to measure very small amounts of time, -// that's why we return a DWORD and not a 64bit value -DWORD I_EndProfile(VOID) -{ - LARGE_INTEGER CurrTime; - DWORD ret; - if (!QueryPerformanceCounter (&CurrTime)) - I_Error("I_EndProfile failed"); - if (CurrTime.QuadPart - ProfileCount.QuadPart > (LONGLONG)0xFFFFFFFFUL) - I_Error("I_EndProfile overflow"); - ret = (DWORD)(CurrTime.QuadPart - ProfileCount.QuadPart); - // we can call I_EndProfile() several time, I_BeginProfile() need be called just once - ProfileCount = CurrTime; - - return ret; -} - -// --------- -// I_GetTime -// Use the High Resolution Timer if available, -// else use the multimedia timer which has 1 millisecond precision on Windowz 95, -// but lower precision on Windows NT -// --------- -static long hacktics = 0; // used locally for keyboard repeat keys -static DWORD starttickcount = 0; // hack for win2k time bug - -tic_t I_GetTime(void) -{ - tic_t newtics = 0; - - if (!starttickcount) // high precision timer - { - LARGE_INTEGER currtime; // use only LowPart if high resolution counter is not available - static LARGE_INTEGER basetime = {{0, 0}}; - - // use this if High Resolution timer is found - static LARGE_INTEGER frequency; - - if (!basetime.LowPart) - { - if (!QueryPerformanceFrequency(&frequency)) - frequency.QuadPart = 0; - else - QueryPerformanceCounter(&basetime); - } - - if (frequency.LowPart && QueryPerformanceCounter(&currtime)) - { - newtics = (int)((currtime.QuadPart - basetime.QuadPart) * NEWTICRATE - / frequency.QuadPart); - } - else - { - currtime.LowPart = timeGetTime(); - if (!basetime.LowPart) - basetime.LowPart = currtime.LowPart; - newtics = ((currtime.LowPart - basetime.LowPart)/(1000/NEWTICRATE)); - } - } - else - newtics = (GetTickCount() - starttickcount)/(1000/NEWTICRATE); - - hacktics = newtics; // a local counter for keyboard repeat key - return newtics; -} - -void I_Sleep(void) -{ - if (cv_sleep.value != -1) - Sleep(cv_sleep.value); -} - -// should move to i_video -void I_WaitVBL(INT32 count) -{ - UNREFERENCED_PARAMETER(count); -} - -// this is probably to activate the 'loading' disc icon -// it should set a flag, that I_FinishUpdate uses to know -// whether it draws a small 'loading' disc icon on the screen or not -// -// also it should explicitly draw the disc because the screen is -// possibly not refreshed while loading -// -void I_BeginRead(void) {} - -// see above, end the 'loading' disc icon, set the flag false -// -void I_EndRead(void) {} - -// =========================================================================================== -// EVENTS -// =========================================================================================== -static BOOL I_ReadyConsole(HANDLE ci) -{ - DWORD gotinput; - if (ci == INVALID_HANDLE_VALUE) return FALSE; - if (WaitForSingleObject(ci,0) != WAIT_OBJECT_0) return FALSE; - if (GetFileType(ci) != FILE_TYPE_CHAR) return FALSE; - if (!GetConsoleMode(ci, &gotinput)) return FALSE; - return (GetNumberOfConsoleInputEvents(ci, &gotinput) && gotinput); -} - -static inline VOID I_GetConsoleEvents(VOID) -{ - event_t ev = {0,0,0,0}; - HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO CSBI; - INPUT_RECORD input; - DWORD t; - - while (I_ReadyConsole(ci) && ReadConsoleInput(ci, &input, 1, &t) && t) - { - ZeroMemory(&ev, sizeof(ev)); - switch (input.EventType) - { - case KEY_EVENT: - if (input.Event.KeyEvent.bKeyDown) - { - ev.type = ev_console; - entering_con_command = true; - switch (input.Event.KeyEvent.wVirtualKeyCode) - { - case VK_ESCAPE: - case VK_TAB: - ev.data1 = KEY_NULL; - break; - case VK_SHIFT: - ev.data1 = KEY_LSHIFT; - break; - case VK_RETURN: - entering_con_command = false; - /* FALLTHRU */ - default: - ev.data1 = 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) - { -#ifdef UNICODE - WriteConsole(co, &input.Event.KeyEvent.uChar.UnicodeChar, 1, &t, NULL); -#else - WriteConsole(co, &input.Event.KeyEvent.uChar.AsciiChar, 1, &t, NULL); -#endif - } - if (input.Event.KeyEvent.wVirtualKeyCode == VK_BACK - && GetConsoleScreenBufferInfo(co,&CSBI)) - { - WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t); - } - } - } - else - { - ev.type = ev_keyup; - switch (input.Event.KeyEvent.wVirtualKeyCode) - { - case VK_SHIFT: - ev.data1 = KEY_LSHIFT; - break; - default: - break; - } - } - if (ev.data1) D_PostEvent(&ev); - break; - case MOUSE_EVENT: - case WINDOW_BUFFER_SIZE_EVENT: - case MENU_EVENT: - case FOCUS_EVENT: - break; - } - } -} - -// ---------- -// I_GetEvent -// Post new events for all sorts of user-input -// ---------- -void I_GetEvent(void) -{ - I_GetConsoleEvents(); - I_GetKeyboardEvents(); - I_GetMouseEvents(); - I_GetJoystickEvents(); - I_GetJoystick2Events(); -} - -// ---------- -// I_OsPolling -// ---------- -void I_OsPolling(void) -{ - MSG msg; - HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - - // we need to dispatch messages to the window - // so the window procedure can respond to messages and PostEvent() for keys - // during D_SRB2Main startup. - // this one replaces the main loop of windows since I_OsPolling is called in the main loop - do - { - while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) - { - if (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else // winspec : this is quit message - I_Quit(); - } - if (!appActive && !netgame && !I_ReadyConsole(ci)) - WaitMessage(); - } while (!appActive && !netgame && !I_ReadyConsole(ci)); - - // this is called by the network synchronization, - // check keys and allow escaping - I_GetEvent(); - - // reset "emulated keys" - gamekeydown[KEY_MOUSEWHEELUP] = 0; - gamekeydown[KEY_MOUSEWHEELDOWN] = 0; -} - -// =========================================================================================== -// TIMER -// =========================================================================================== - -static VOID I_ShutdownTimer(VOID) -{ - timeEndPeriod(1); -} - -// -// Installs the timer interrupt handler with timer speed as TICRATE. -// -#define TIMER_ID 1 -#define TIMER_RATE (1000/TICRATE) -void I_StartupTimer(void) -{ - // for win2k time bug - if (M_CheckParm("-gettickcount")) - { - starttickcount = GetTickCount(); - CONS_Printf("Using GetTickCount()\n"); - } - timeBeginPeriod(1); - I_AddExitFunc(I_ShutdownTimer); -} - -// =========================================================================================== -// EXIT CODE, ERROR HANDLING -// =========================================================================================== - -static int errorcount = 0; // phuck recursive errors -static int shutdowning = false; - -// -// Used to trap various signals, to make sure things get shut down cleanly. -// -#ifdef NDEBUG -static void signal_handler(int num) -{ - //static char msg[] = "oh no! back to reality!\r\n"; - const char *sigmsg; - char sigdef[64]; - - D_QuitNetGame(); // Fix server freezes - CL_AbortDownloadResume(); - I_ShutdownSystem(); - - switch (num) - { - case SIGINT: - sigmsg = "interrupt"; - break; - case SIGILL: - sigmsg = "illegal instruction - invalid function image"; - break; - case SIGFPE: - sigmsg = "floating point exception"; - break; - case SIGSEGV: - sigmsg = "segment violation"; - break; - case SIGTERM: - sigmsg = "software termination signal from kill"; - break; - case SIGBREAK: - sigmsg = "Ctrl-Break sequence"; - break; - case SIGABRT: - sigmsg = "abnormal termination triggered by abort call"; - break; - default: - sprintf(sigdef, "signal number %d", num); - sigmsg = sigdef; - } - -#ifdef LOGMESSAGES - if (logstream) - { - I_OutputMsg("signal_handler() error: %s\r\n", sigmsg); - fclose(logstream); - logstream = NULL; - } -#endif - - MessageBoxA(hWndMain, va("signal_handler(): %s", sigmsg), "SRB2 error", MB_OK|MB_ICONERROR); - - signal(num, SIG_DFL); // default signal action - raise(num); -} -#endif - -// -// put an error message (with format) on stderr -// -void I_OutputMsg(const char *fmt, ...) -{ - HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD bytesWritten; - va_list argptr; - char txt[8192]; - - va_start(argptr,fmt); - vsprintf(txt, fmt, argptr); - va_end(argptr); - -#ifdef _MSC_VER - OutputDebugStringA(txt); -#endif - -#ifdef LOGMESSAGES - if (logstream) - { - fwrite(txt, strlen(txt), 1, logstream); - fflush(logstream); - } -#endif - - if (co == INVALID_HANDLE_VALUE) - return; - - if (GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &bytesWritten)) - { - static COORD coordNextWrite = {0,0}; - LPVOID oldLines = NULL; - INT oldLength; - CONSOLE_SCREEN_BUFFER_INFO csbi; - - // Save the lines that we're going to obliterate. - GetConsoleScreenBufferInfo(co, &csbi); - oldLength = csbi.dwSize.X * (csbi.dwCursorPosition.Y - coordNextWrite.Y) + csbi.dwCursorPosition.X - coordNextWrite.X; - - if (oldLength > 0) - { - LPVOID blank = malloc(oldLength); - if (!blank) return; - memset(blank, ' ', oldLength); // Blank out. - oldLines = malloc(oldLength*sizeof(TCHAR)); - if (!oldLines) - { - free(blank); - return; - } - - ReadConsoleOutputCharacter(co, oldLines, oldLength, coordNextWrite, &bytesWritten); - - // Move to where we what to print - which is where we would've been, - // had console input not been in the way, - SetConsoleCursorPosition(co, coordNextWrite); - - WriteConsoleA(co, blank, oldLength, &bytesWritten, NULL); - free(blank); - - // And back to where we want to print again. - SetConsoleCursorPosition(co, coordNextWrite); - } - - // Actually write the string now! - WriteConsoleA(co, txt, (DWORD)strlen(txt), &bytesWritten, NULL); - - // Next time, output where we left off. - GetConsoleScreenBufferInfo(co, &csbi); - coordNextWrite = csbi.dwCursorPosition; - - // Restore what was overwritten. - if (oldLines && entering_con_command) - WriteConsole(co, oldLines, oldLength, &bytesWritten, NULL); - if (oldLines) free(oldLines); - } - else // Redirected to a file. - WriteFile(co, txt, (DWORD)strlen(txt), &bytesWritten, NULL); -} - -// display error messy after shutdowngfx -// -void I_Error(const char *error, ...) -{ - va_list argptr; - char txt[8192]; - - // added 11-2-98 recursive error detecting - if (shutdowning) - { - errorcount++; - // try to shutdown each subsystem separately - if (errorcount == 5) - I_ShutdownGraphics(); - if (errorcount == 6) - I_ShutdownSystem(); - if (errorcount == 7) - { - M_SaveConfig(NULL); - G_SaveGameData(); - } - if (errorcount > 20) - { - // Don't print garbage - va_start(argptr,error); - vsprintf(txt, error, argptr); - va_end(argptr); - - OutputDebugStringA(txt); - MessageBoxA(hWndMain, txt, "SRB2 Recursive Error", MB_OK|MB_ICONERROR); - W_Shutdown(); - exit(-1); // recursive errors detected - } - } - shutdowning = true; - - // put message to stderr - va_start(argptr, error); - wvsprintfA(txt, error, argptr); - va_end(argptr); - - CONS_Printf("I_Error(): %s\n", txt); //don't change from CONS_Printf. - - // saving one time is enough! - if (!errorcount) - { - M_SaveConfig(NULL); // save game config, cvars.. - G_SaveGameData(); - } - - // save demo, could be useful for debug - // NOTE: demos are normally not saved here. - if (demorecording) - G_CheckDemoStatus(); - if (metalrecording) - G_StopMetalRecording(false); - - D_QuitNetGame(); - CL_AbortDownloadResume(); - M_FreePlayerSetupColors(); - - // shutdown everything that was started - I_ShutdownSystem(); - -#ifdef LOGMESSAGES - if (logstream) - { - fclose(logstream); - logstream = NULL; - } -#endif - - MessageBoxA(hWndMain, txt, "SRB2 Error", MB_OK|MB_ICONERROR); - - W_Shutdown(); - exit(-1); -} - -static inline VOID ShowEndTxt(HANDLE co) -{ - int i; - UINT16 j, att = 0; - int nlflag = 1; - CONSOLE_SCREEN_BUFFER_INFO backupcon; - COORD resizewin = {80,-1}; - DWORD bytesWritten; - CHAR let = 0; - UINT16 *ptext; - LPVOID data; - lumpnum_t endoomnum = W_GetNumForName("ENDOOM"); - //HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - - /* get the lump with the text */ - data = ptext = W_CacheLumpNum(endoomnum, PU_CACHE); - - backupcon.wAttributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE; // Just in case - GetConsoleScreenBufferInfo(co, &backupcon); //Store old state - resizewin.Y = backupcon.dwSize.Y; - if (backupcon.dwSize.X < resizewin.X) - SetConsoleScreenBufferSize(co, resizewin); - - for (i = 1; i <= 80*25; i++) // print 80x25 text and deal with the attributes too - { - j = (UINT16)(*ptext >> 8); // attribute first - let = (char)(*ptext & 0xff); // text senond - if (j != att) // attribute changed? - { - att = j; // save current attribute - SetConsoleTextAttribute(co, j); //set fg and bg color for buffer - } - - WriteConsoleA(co, &let, 1, &bytesWritten, NULL); // now the text - - if (nlflag && !(i % 80) && backupcon.dwSize.X > resizewin.X) // do we need a nl? - { - att = backupcon.wAttributes; - SetConsoleTextAttribute(co, att); // all attributes off - WriteConsoleA(co, "\n", 1, &bytesWritten, NULL); // newline to console - } - ptext++; - } - SetConsoleTextAttribute(co, backupcon.wAttributes); // all attributes off - //if (nlflag) - // WriteConsoleA(co, "\n", 1, &bytesWritten, NULL); - - getchar(); //pause! - - Z_Free(data); -} - - -// -// I_Quit: shutdown everything cleanly, in reverse order of Startup. -// -void I_Quit(void) -{ - HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD mode; - // when recording a demo, should exit using 'q', - // but sometimes we forget and use Alt+F4, so save here too. - if (demorecording) - G_CheckDemoStatus(); - if (metalrecording) - G_StopMetalRecording(false); - - M_SaveConfig(NULL); // save game config, cvars.. -#ifndef NONET - D_SaveBan(); // save the ban list -#endif - G_SaveGameData(); - - // maybe it needs that the ticcount continues, - // or something else that will be finished by I_ShutdownSystem(), - // so do it before. - D_QuitNetGame(); - CL_AbortDownloadResume(); - - M_FreePlayerSetupColors(); - - // shutdown everything that was started - I_ShutdownSystem(); - - if (shutdowning || errorcount) - I_Error("Error detected (%d)", errorcount); - -#ifdef LOGMESSAGES - if (logstream) - { - I_OutputMsg("I_Quit(): end of logstream.\n"); - fclose(logstream); - logstream = NULL; - } -#endif - if (!M_CheckParm("-noendtxt") && W_CheckNumForName("ENDOOM")!=LUMPERROR - && co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR - && GetConsoleMode(co, &mode)) - { - printf("\r"); - ShowEndTxt(co); - } - fflush(stderr); - if (myargmalloc) - free(myargv); // Deallocate allocated memory - W_Shutdown(); - exit(0); -} - -// -------------------------------------------------------------------------- -// I_ShowLastError -// Print a GetLastError() error message, and if MB is TRUE, also display it in a MessageBox -// -------------------------------------------------------------------------- -VOID I_ShowLastError(BOOL MB) -{ - LPSTR lpMsgBuf = NULL; - const DWORD LE = GetLastError(); - - if (LE == 0xdeadbeef) return; // Not a real error - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, LE, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPVOID)&lpMsgBuf, 0, NULL); - - if (!lpMsgBuf) - { - I_OutputMsg("GetLastError: Unknown\n"); - return; - } - - // Display the string - if (MB && LE) MessageBoxA(NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION); - - // put it in text console and log if any - I_OutputMsg("GetLastError: %s", lpMsgBuf); - - // Free the buffer. - LocalFree(lpMsgBuf); -} - -// =========================================================================================== -// CLEAN STARTUP & SHUTDOWN HANDLING, JUST CLOSE EVERYTHING YOU OPENED. -// =========================================================================================== -// -// -static quitfuncptr quit_funcs[MAX_QUIT_FUNCS] = -{ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -// Adds a function to the list that need to be called by I_SystemShutdown(). -// -void I_AddExitFunc(void (*func)()) -{ - int c; - - for (c = 0; c < MAX_QUIT_FUNCS; c++) - { - if (!quit_funcs[c]) - { - quit_funcs[c] = func; - break; - } - } -} - -// Removes a function from the list that need to be called by I_SystemShutdown(). -// -void I_RemoveExitFunc(void (*func)()) -{ - int c; - - for (c = 0; c < MAX_QUIT_FUNCS; c++) - { - if (quit_funcs[c] == func) - { - while (c < MAX_QUIT_FUNCS - 1) - { - quit_funcs[c] = quit_funcs[c+1]; - c++; - } - quit_funcs[MAX_QUIT_FUNCS-1] = NULL; - break; - } - } -} - -// =========================================================================================== -// DIRECT INPUT HELPER CODE -// =========================================================================================== - -// Create a DirectInputDevice interface, -// create a DirectInputDevice2 interface if possible -static VOID CreateDevice2A(LPDIRECTINPUTA di, REFGUID pguid, LPDIRECTINPUTDEVICEA* lpDEV, - LPDIRECTINPUTDEVICE2A* lpDEV2) -{ - HRESULT hr, hr2; - LPDIRECTINPUTDEVICEA lpdid1; - LPDIRECTINPUTDEVICE2A lpdid2 = NULL; - - hr = IDirectInput_CreateDevice(di, pguid, &lpdid1, NULL); - - if (SUCCEEDED(hr)) - { - // get Device2 but only if we are not in DirectInput version 3 - if (!bDX0300 && lpDEV2) - { - LPDIRECTINPUTDEVICE2A *rp = &lpdid2; - LPVOID *tp = (LPVOID *)rp; - hr2 = IDirectInputDevice_QueryInterface(lpdid1, &IID_IDirectInputDevice2, tp); - if (FAILED(hr2)) - { - CONS_Alert(CONS_ERROR, M_GetText("Could not create IDirectInput device 2")); - lpdid2 = NULL; - } - } - } - else - I_Error("Could not create IDirectInput device"); - - *lpDEV = lpdid1; - if (lpDEV2) // only if we requested it - *lpDEV2 = lpdid2; -} - -// =========================================================================================== -// DIRECT INPUT MOUSE -// =========================================================================================== - -#define DI_MOUSE_BUFFERSIZE 16 // number of data elements in mouse buffer - -// -// Initialise the mouse. -// -static void I_ShutdownMouse(VOID); - -void I_StartupMouse(VOID) -{ - // this gets called when cv_usemouse is initted - // for the win32 version, we want to startup the mouse later - if (menuactive) - { - if (cv_usemouse.value) - I_DoStartupMouse(); - else - I_ShutdownMouse(); - } -} - -static HANDLE mouse2filehandle = INVALID_HANDLE_VALUE; - -static void I_ShutdownMouse2(VOID) -{ - if (mouse2filehandle != INVALID_HANDLE_VALUE) - { - event_t event; - UINT i; - - SetCommMask(mouse2filehandle, 0); - - EscapeCommFunction(mouse2filehandle, CLRDTR); - EscapeCommFunction(mouse2filehandle, CLRRTS); - - PurgeComm(mouse2filehandle, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); - - CloseHandle(mouse2filehandle); - - // emulate the up of all mouse buttons - for (i = 0; i < MOUSEBUTTONS; i++) - { - event.type = ev_keyup; - event.data1 = KEY_2MOUSE1 + i; - D_PostEvent(&event); - } - - mouse2filehandle = INVALID_HANDLE_VALUE; - } -} - -#define MOUSECOMBUFFERSIZE 256 -static int handlermouse2x, handlermouse2y, handlermouse2buttons; - -static VOID I_PoolMouse2(VOID) -{ - BYTE buffer[MOUSECOMBUFFERSIZE]; - COMSTAT ComStat; - DWORD dwErrorFlags, dwLength, i; - CHAR dx, dy; - static BYTE bytenum, combytes[4]; - - ClearCommError(mouse2filehandle, &dwErrorFlags, &ComStat); - dwLength = min(MOUSECOMBUFFERSIZE, ComStat.cbInQue); - - if (dwLength > 0) - { - if (!ReadFile(mouse2filehandle, buffer, dwLength, &dwLength, NULL)) - { - CONS_Alert(CONS_ERROR, M_GetText("Read Error on secondary mouse port\n")); - return; - } - - // parse the mouse packets - for (i = 0; i < dwLength; i++) - { - if ((buffer[i] & 64) == 64) - bytenum = 0; - - if (bytenum < 4) - combytes[bytenum] = buffer[i]; - bytenum++; - - if (bytenum == 1) - { - handlermouse2buttons &= ~3; - handlermouse2buttons |= ((combytes[0] & (32+16)) >>4); - } - else if (bytenum == 3) - { - dx = (CHAR)((combytes[0] & 3) << 6); - dy = (CHAR)((combytes[0] & 12) << 4); - dx = (CHAR)(dx + combytes[1]); - dy = (CHAR)(dy + combytes[2]); - handlermouse2x += dx; - handlermouse2y += dy; - } - else if (bytenum == 4) // fourth byte (logitech mouses) - { - if (buffer[i] & 32) - handlermouse2buttons |= 4; - else - handlermouse2buttons &= ~4; - } - } - } -} - -// secondary mouse doesn't use DirectX, therefore forget all about grabbing, acquire, etc. -void I_StartupMouse2(void) -{ - DCB dcb; - - if (mouse2filehandle != INVALID_HANDLE_VALUE) - I_ShutdownMouse2(); - - if (!cv_usemouse2.value) - return; - - if (mouse2filehandle != INVALID_HANDLE_VALUE) - { - // COM file handle - mouse2filehandle = CreateFileA(cv_mouse2port.string, GENERIC_READ|GENERIC_WRITE, - 0, // exclusive access - NULL, // no security attrs - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (mouse2filehandle == INVALID_HANDLE_VALUE) - { - int e = GetLastError(); - if (e == 5) - CONS_Alert(CONS_ERROR, M_GetText("Error opening %s!\n"), cv_mouse2port.string); - else - CONS_Alert(CONS_ERROR, M_GetText("Can't open %s: error %d\n"), cv_mouse2port.string, e); - return; - } - } - - // buffers - SetupComm(mouse2filehandle, MOUSECOMBUFFERSIZE, MOUSECOMBUFFERSIZE); - - // purge buffers - PurgeComm(mouse2filehandle, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); - - // setup port to 1200 7N1 - dcb.DCBlength = sizeof (DCB); - - GetCommState(mouse2filehandle, &dcb); - - dcb.BaudRate = CBR_1200; - dcb.ByteSize = 7; - dcb.Parity = NOPARITY; - dcb.StopBits = ONESTOPBIT; - - dcb.fDtrControl = DTR_CONTROL_ENABLE; - dcb.fRtsControl = RTS_CONTROL_ENABLE; - - dcb.fBinary = dcb.fParity = TRUE; - - SetCommState(mouse2filehandle, &dcb); - - I_AddExitFunc(I_ShutdownMouse2); -} - -#define MAX_MOUSE_BTNS 5 -static int center_x, center_y; -static INT old_mparms[3], new_mparms[3] = {0, 0, 1}; -static BOOL restore_mouse = FALSE; -static INT old_mouse_state = 0; -UINT MSHWheelMessage = 0; - -static VOID I_DoStartupSysMouse(VOID) -{ - boolean valid; - RECT w_rect; - - valid = SystemParametersInfo(SPI_GETMOUSE, 0, old_mparms, 0); - if (valid) - { - new_mparms[2] = old_mparms[2]; - restore_mouse = SystemParametersInfo(SPI_SETMOUSE, 0, new_mparms, 0); - } - - if (bAppFullScreen) - { - w_rect.top = 0; - w_rect.left = 0; - } - else - { - w_rect.top = windowPosY; - w_rect.left = windowPosX; - } - - w_rect.bottom = w_rect.top + VIDHEIGHT; - w_rect.right = w_rect.left + VIDWIDTH; - center_x = w_rect.left + (VIDWIDTH >> 1); - center_y = w_rect.top + (VIDHEIGHT >> 1); - SetCursor(NULL); - SetCursorPos(center_x, center_y); - SetCapture(hWndMain); - ClipCursor(&w_rect); -} - -static VOID I_ShutdownSysMouse(VOID) -{ - if (restore_mouse) - SystemParametersInfo(SPI_SETMOUSE, 0, old_mparms, 0); - ClipCursor(NULL); - ReleaseCapture(); -} - -VOID I_RestartSysMouse(VOID) -{ - if (nodinput) - { - I_ShutdownSysMouse(); - I_DoStartupSysMouse(); - } -} - -VOID I_GetSysMouseEvents(INT mouse_state) -{ - UINT i; - event_t event; - int xmickeys = 0, ymickeys = 0; - POINT c_pos; - - for (i = 0; i < MAX_MOUSE_BTNS; i++) - { - // check if button pressed - if ((mouse_state & (1 << i)) && !(old_mouse_state & (1 << i))) - { - event.type = ev_keydown; - event.data1 = 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; - D_PostEvent(&event); - } - } - old_mouse_state = mouse_state; - - // proceed mouse movements - GetCursorPos(&c_pos); - xmickeys = c_pos.x - center_x; - ymickeys = c_pos.y - center_y; - - if (xmickeys || ymickeys) - { - event.type = ev_mouse; - event.data1 = 0; - event.data2 = xmickeys; - event.data3 = -ymickeys; - D_PostEvent(&event); - SetCursorPos(center_x, center_y); - } -} - -// This is called just before entering the main game loop, -// when we are going fullscreen and the loading screen has finished. -VOID I_DoStartupMouse(VOID) -{ - DIPROPDWORD dip; - - // mouse detection may be skipped by setting usemouse false - if (!cv_usemouse.value || M_CheckParm("-nomouse")) - { - mouse_enabled = false; - return; - } - - if (nodinput) - { - CONS_Printf(M_GetText("\tMouse will not use DirectInput.\n")); - // System mouse input will be initiated by VID_SetMode - I_AddExitFunc(I_ShutdownMouse); - - MSHWheelMessage = RegisterWindowMessage(MSH_MOUSEWHEEL); - } - else if (!lpDIM) // acquire the mouse only once - { - CreateDevice2A(lpDI, &GUID_SysMouse, &lpDIM, NULL); - - if (lpDIM) - { - if (FAILED(IDirectInputDevice_SetDataFormat(lpDIM, &c_dfDIMouse))) - I_Error("Couldn't set mouse data format"); - - // create buffer for buffered data - dip.diph.dwSize = sizeof (dip); - dip.diph.dwHeaderSize = sizeof (dip.diph); - dip.diph.dwObj = 0; - dip.diph.dwHow = DIPH_DEVICE; - dip.dwData = DI_MOUSE_BUFFERSIZE; - if (FAILED(IDirectInputDevice_SetProperty(lpDIM, DIPROP_BUFFERSIZE, &dip.diph))) - I_Error("Couldn't set mouse buffer size"); - - if (FAILED(IDirectInputDevice_SetCooperativeLevel(lpDIM, hWndMain, - DISCL_EXCLUSIVE|DISCL_FOREGROUND))) - { - I_Error("Couldn't set mouse coop level"); - } - I_AddExitFunc(I_ShutdownMouse); - } - else - I_Error("Couldn't create mouse input"); - } - - // if re-enabled while running, just set mouse_enabled true again, - // do not acquire the mouse more than once - mouse_enabled = true; -} - -// -// Shutdown Mouse DirectInput device -// -static void I_ShutdownMouse(void) -{ - int i; - event_t event; - - CONS_Printf("I_ShutdownMouse()\n"); - - if (lpDIM) - { - IDirectInputDevice_Unacquire(lpDIM); - IDirectInputDevice_Release(lpDIM); - lpDIM = NULL; - } - - // emulate the up of all mouse buttons - for (i = 0; i < MOUSEBUTTONS; i++) - { - event.type = ev_keyup; - event.data1 = KEY_MOUSE1 + i; - D_PostEvent(&event); - } - if (nodinput) - I_ShutdownSysMouse(); - - mouse_enabled = false; -} - -// -// Get buffered data from the mouse -// -void I_GetMouseEvents(void) -{ - DIDEVICEOBJECTDATA rgdod[DI_MOUSE_BUFFERSIZE]; - DWORD dwItems, d; - HRESULT hr; - - event_t event; - int xmickeys, ymickeys; - - if (mouse2filehandle != INVALID_HANDLE_VALUE) - { - //mouse movement - static UINT8 lastbuttons2 = 0; - - I_PoolMouse2(); - // post key event for buttons - if (handlermouse2buttons != lastbuttons2) - { - int i, j = 1, k; - k = handlermouse2buttons ^ lastbuttons2; // only changed bit to 1 - lastbuttons2 = (UINT8)handlermouse2buttons; - - for (i = 0; i < MOUSEBUTTONS; i++, j <<= 1) - if (k & j) - { - if (handlermouse2buttons & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_2MOUSE1 + i; - D_PostEvent(&event); - } - } - - if (handlermouse2x || handlermouse2y) - { - event.type = ev_mouse2; - event.data1 = 0; - event.data2 = handlermouse2x<<1; - event.data3 = -handlermouse2y<<1; - handlermouse2x = 0; - handlermouse2y = 0; - - D_PostEvent(&event); - } - } - - if (!mouse_enabled || nodinput) - return; - -getBufferedData: - dwItems = DI_MOUSE_BUFFERSIZE; - hr = IDirectInputDevice_GetDeviceData(lpDIM, sizeof (DIDEVICEOBJECTDATA), rgdod, &dwItems, 0); - - // If data stream was interrupted, reacquire the device and try again. - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - hr = IDirectInputDevice_Acquire(lpDIM); - if (SUCCEEDED(hr)) - goto getBufferedData; - } - - // We got buffered input, act on it - if (SUCCEEDED(hr)) - { - xmickeys = ymickeys = 0; - - // dwItems contains number of elements read (could be 0) - for (d = 0; d < dwItems; d++) - { - if (rgdod[d].dwOfs >= DIMOFS_BUTTON0 && - rgdod[d].dwOfs < DIMOFS_BUTTON0 + MOUSEBUTTONS) - { - if (rgdod[d].dwData & 0x80) // Button down - event.type = ev_keydown; - else - event.type = ev_keyup; // Button up - - event.data1 = rgdod[d].dwOfs - DIMOFS_BUTTON0 + KEY_MOUSE1; - D_PostEvent(&event); - } - else if (rgdod[d].dwOfs == DIMOFS_X) - xmickeys += rgdod[d].dwData; - else if (rgdod[d].dwOfs == DIMOFS_Y) - ymickeys += rgdod[d].dwData; - - else if (rgdod[d].dwOfs == DIMOFS_Z) - { - // z-axes the wheel - if ((int)rgdod[d].dwData > 0) - event.data1 = KEY_MOUSEWHEELUP; - else - event.data1 = KEY_MOUSEWHEELDOWN; - event.type = ev_keydown; - D_PostEvent(&event); - } - - } - - if (xmickeys || ymickeys) - { - event.type = ev_mouse; - event.data1 = 0; - event.data2 = xmickeys; - event.data3 = -ymickeys; - D_PostEvent(&event); - } - } -} - -void I_UpdateMouseGrab(void) {} - -// =========================================================================================== -// DIRECT INPUT JOYSTICK -// =========================================================================================== - -struct DIJoyInfo_s -{ - BYTE X,Y,Z,Rx,Ry,Rz,U,V; - LONG ForceAxises; -}; -typedef struct DIJoyInfo_s DIJoyInfo_t; - -// private info - static BYTE iJoyNum; // used by enumeration - static DIJoyInfo_t JoyInfo; - static BYTE iJoy2Num; - static DIJoyInfo_t JoyInfo2; - -//----------------------------------------------------------------------------- -// Name: EnumAxesCallback() -// Desc: Callback function for enumerating the axes on a joystick and counting -// each force feedback enabled axis -//----------------------------------------------------------------------------- -static BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCEA* pdidoi, - VOID* pContext) -{ - DWORD* pdwNumForceFeedbackAxis = (DWORD*) pContext; - - if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0) - (*pdwNumForceFeedbackAxis)++; - - return DIENUM_CONTINUE; -} - - -static HRESULT SetupForceTacile(LPDIRECTINPUTDEVICE2A DJI, LPDIRECTINPUTEFFECT *DJE, DWORD FFAXIS, FFType EffectType,REFGUID EffectGUID) -{ - HRESULT hr; - DIEFFECT eff; - DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; - LONG rglDirection[2] = { 0, 0 }; - DICONSTANTFORCE cf = { 0 }; // LONG lMagnitude - DIRAMPFORCE rf = {0,0}; // LONG lStart, lEnd; - DIPERIODIC pf = {0,0,0,0}; - ZeroMemory(&eff, sizeof (eff)); - if (FFAXIS > 2) - FFAXIS = 2; //up to 2 FFAXIS - eff.dwSize = sizeof (DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; // Cartesian and data format offsets - eff.dwDuration = INFINITE; - eff.dwSamplePeriod = 0; - eff.dwGain = DI_FFNOMINALMAX; - eff.dwTriggerButton = DIEB_NOTRIGGER; - eff.dwTriggerRepeatInterval = 0; - eff.cAxes = FFAXIS; - eff.rgdwAxes = rgdwAxes; - eff.rglDirection = rglDirection; - eff.lpEnvelope = NULL; - eff.lpvTypeSpecificParams = NULL; - if (EffectType == ConstantForce) - { - eff.cbTypeSpecificParams = sizeof (cf); - eff.lpvTypeSpecificParams = &cf; - } - else if (EffectType == RampForce) - { - eff.cbTypeSpecificParams = sizeof (rf); - eff.lpvTypeSpecificParams = &rf; - } - else if (EffectType >= SquareForce && SawtoothDownForce >= EffectType) - { - eff.cbTypeSpecificParams = sizeof (pf); - eff.lpvTypeSpecificParams = &pf; - } - - // Create the prepared effect - if (FAILED(hr = IDirectInputDevice2_CreateEffect(DJI, EffectGUID, - &eff, DJE, NULL))) - { - return hr; - } - - if (NULL == *DJE) - return E_FAIL; - - return hr; -} - -static BOOL CALLBACK DIEnumEffectsCallback1(LPCDIEFFECTINFOA pdei, LPVOID pvRef) -{ - LPDIRECTINPUTEFFECT *DJE = pvRef; - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_CONSTANTFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJA,DJE, JoyInfo.ForceAxises, ConstantForce, &pdei->guid))) - return DIENUM_STOP; - } - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_RAMPFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJA,DJE, JoyInfo.ForceAxises, RampForce, &pdei->guid))) - return DIENUM_STOP; - } - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK DIEnumEffectsCallback2(LPCDIEFFECTINFOA pdei, LPVOID pvRef) -{ - LPDIRECTINPUTEFFECT *DJE = pvRef; - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_CONSTANTFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJ2A,DJE, JoyInfo2.ForceAxises, ConstantForce, &pdei->guid))) - return DIENUM_STOP; - } - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_RAMPFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJ2A,DJE, JoyInfo2.ForceAxises, RampForce, &pdei->guid))) - return DIENUM_STOP; - } - return DIENUM_CONTINUE; -} - -static REFGUID DIETable[] = -{ - &GUID_ConstantForce, //ConstantForce - &GUID_RampForce, //RampForce - &GUID_Square, //SquareForce - &GUID_Sine, //SineForce - &GUID_Triangle, //TriangleForce - &GUID_SawtoothUp, //SawtoothUpForce - &GUID_SawtoothDown, //SawtoothDownForce - (REFGUID)-1, //NumberofForces -}; - -static HRESULT SetupAllForces(LPDIRECTINPUTDEVICE2A DJI, LPDIRECTINPUTEFFECT DJE[], DWORD FFAXIS) -{ - FFType ForceType = EvilForce; - if (DJI == lpDIJA) - { - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback1,&DJE[ConstantForce],DIEFT_CONSTANTFORCE); - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback1,&DJE[RampForce],DIEFT_RAMPFORCE); - } - else if (DJI == lpDIJA) - { - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback2,&DJE[ConstantForce],DIEFT_CONSTANTFORCE); - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback2,&DJE[RampForce],DIEFT_RAMPFORCE); - } - for (ForceType = SquareForce; ForceType > NumberofForces && DIETable[ForceType] != (REFGUID)-1; ForceType++) - if (DIETable[ForceType]) - SetupForceTacile(DJI,&DJE[ForceType], FFAXIS, ForceType, DIETable[ForceType]); - return S_OK; -} - -static inline VOID LimitEffect(LPDIEFFECT eff, FFType EffectType) -{ - LPDICONSTANTFORCE pCF = eff->lpvTypeSpecificParams; - LPDIPERIODIC pDP= eff->lpvTypeSpecificParams; - if (eff->rglDirection) - { - } -/* if (eff->dwDuration != INFINITE && eff->dwDuration < 0) - { - eff->dwDuration = 0; - }*/ - if (eff->dwGain != 0) - { - if (eff->dwGain > DI_FFNOMINALMAX) - eff->dwGain = DI_FFNOMINALMAX; - //else if (eff->dwGain < -DI_FFNOMINALMAX) - // eff->dwGain = DI_FFNOMINALMAX; - } - if (EffectType == ConstantForce && pCF->lMagnitude) - { - } - else if (EffectType >= SquareForce && SawtoothDownForce >= EffectType && pDP) - { - } - -} - -static HRESULT SetForceTacile(LPDIRECTINPUTEFFECT SDIE, const JoyFF_t *FF,DWORD FFAXIS, FFType EffectType) -{ - DIEFFECT eff; - HRESULT hr; - LONG Magnitude; - LONG rglDirection[2] = { 0, 0 }; - DICONSTANTFORCE cf = { 0 }; // LONG lMagnitude - DIRAMPFORCE rf = {0,0}; // LONG lStart, lEnd; - DIPERIODIC pf = {0,0,0,0}; - if (!FF) - IDirectInputEffect_Stop(SDIE); - Magnitude = FF->Magnitude; - ZeroMemory(&eff, sizeof (eff)); - eff.dwSize = sizeof (eff); - //DIEP_START - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; // Cartesian and data format offsets - //DIEP_DURATION - eff.dwDuration = FF->Duration; - //DIEP_GAIN - eff.dwGain = FF->Gain; - //DIEP_DIRECTION - eff.rglDirection = rglDirection; - //DIEP_TYPESPECIFICPARAMS - if (FFAXIS > 1) - { - double dMagnitude; - dMagnitude = (double)Magnitude; - dMagnitude = hypot(dMagnitude, dMagnitude); - Magnitude = (DWORD)dMagnitude; - rglDirection[0] = FF->ForceX; - rglDirection[1] = FF->ForceY; - } - if (EffectType == ConstantForce) - { - cf.lMagnitude = Magnitude; - eff.cbTypeSpecificParams = sizeof (cf); - eff.lpvTypeSpecificParams = &cf; - } - else if (EffectType == RampForce) - { - rf.lStart = FF->Start; - rf.lEnd = FF->End; - eff.cbTypeSpecificParams = sizeof (rf); - eff.lpvTypeSpecificParams = &rf; - } - else if (EffectType >= SquareForce && SawtoothDownForce >= EffectType) - { - pf.dwMagnitude = Magnitude; - pf.lOffset = FF->Offset; - pf.dwPhase = FF->Phase; - pf.dwPeriod = FF->Period; - eff.cbTypeSpecificParams = sizeof (pf); - eff.lpvTypeSpecificParams = &pf; - } - - LimitEffect(&eff, EffectType); - - hr = IDirectInputEffect_SetParameters(SDIE, &eff, - DIEP_START|DIEP_DURATION|DIEP_GAIN|DIEP_DIRECTION|DIEP_TYPESPECIFICPARAMS); - return hr; -} - -void I_Tactile(FFType Type, const JoyFF_t *Effect) -{ - if (!lpDIJA) return; - if (FAILED(IDirectInputDevice2_Acquire(lpDIJA))) - return; - if (Type == EvilForce) - IDirectInputDevice2_SendForceFeedbackCommand(lpDIJA,DISFFC_STOPALL); - if (Type <= EvilForce || Type > NumberofForces || !lpDIE[Type]) - return; - SetForceTacile(lpDIE[Type], Effect, JoyInfo.ForceAxises, Type); -} - -void I_Tactile2(FFType Type, const JoyFF_t *Effect) -{ - if (!lpDIJ2A) return; - if (FAILED(IDirectInputDevice2_Acquire(lpDIJ2A))) - return; - if (Type == EvilForce) - IDirectInputDevice2_SendForceFeedbackCommand(lpDIJ2A,DISFFC_STOPALL); - if (Type <= EvilForce || Type > NumberofForces || !lpDIE2[Type]) - return; - SetForceTacile(lpDIE2[Type],Effect, JoyInfo2.ForceAxises, Type); -} - -// ------------------ -// SetDIDwordProperty (HELPER) -// Set a DWORD property on a DirectInputDevice. -// ------------------ -static HRESULT SetDIDwordProperty(LPDIRECTINPUTDEVICEA pdev, - REFGUID guidProperty, - DWORD dwObject, - DWORD dwHow, - DWORD dwValue) -{ - DIPROPDWORD dipdw; - - dipdw.diph.dwSize = sizeof (dipdw); - dipdw.diph.dwHeaderSize = sizeof (dipdw.diph); - dipdw.diph.dwObj = dwObject; - dipdw.diph.dwHow = dwHow; - dipdw.dwData = dwValue; - - return IDirectInputDevice_SetProperty(pdev, guidProperty, &dipdw.diph); -} - -#define DIDEADZONE 0000 //2500 - -// --------------- -// DIEnumJoysticks -// There is no such thing as a 'system' joystick, contrary to mouse, -// we must enumerate and choose one joystick device to use -// --------------- -static BOOL CALLBACK DIEnumJoysticks (LPCDIDEVICEINSTANCEA lpddi, - LPVOID pvRef) //cv_usejoystick -{ - LPDIRECTINPUTDEVICEA pdev; - DIPROPRANGE diprg; - DIDEVCAPS caps; - BOOL bUseThisOne = FALSE; - - iJoyNum++; - - //faB: if cv holds a string description of joystick, the value from atoi() is 0 - // else, the value was probably set by user at console to one of the previously - // enumerated joysticks - if (((consvar_t *)pvRef)->value == iJoyNum || !strcmp(((consvar_t *)pvRef)->string, lpddi->tszProductName)) - bUseThisOne = TRUE; - - //I_OutputMsg(" cv joy is %s\n", ((consvar_t *)pvRef)->string); - - // print out device name - CONS_Printf("%c%d: %s\n", - (bUseThisOne) ? '\2' : ' ', // show name in white if this is the one we will use - iJoyNum, - //(GET_DIDEVICE_SUBTYPE(lpddi->dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD) ? "Gamepad " : "Joystick", - lpddi->tszProductName); //, lpddi->tszInstanceName); - - // use specified joystick (cv_usejoystick.value in pvRef) - if (!bUseThisOne) - return DIENUM_CONTINUE; - - ((consvar_t *)pvRef)->value = iJoyNum; - if (IDirectInput_CreateDevice(lpDI, &lpddi->guidInstance, - &pdev, NULL) != DI_OK) - { - // if it failed, then we can't use this joystick for some - // bizarre reason. (Maybe the user unplugged it while we - // were in the middle of enumerating it.) So continue enumerating - I_OutputMsg("DIEnumJoysticks(): CreateDevice FAILED\n"); - return DIENUM_CONTINUE; - } - - // get the Device capabilities - // - caps.dwSize = sizeof (DIDEVCAPS_DX3); - if (FAILED(IDirectInputDevice_GetCapabilities (pdev, &caps))) - { - I_OutputMsg("DIEnumJoysticks(): GetCapabilities FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - if (!(caps.dwFlags & DIDC_ATTACHED)) // should be, since we enumerate only attached devices - return DIENUM_CONTINUE; - - Joystick.bJoyNeedPoll = ((caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0); - - if (caps.dwFlags & DIDC_FORCEFEEDBACK) - JoyInfo.ForceAxises = 0; - else - JoyInfo.ForceAxises = -1; - - Joystick.bGamepadStyle = (GET_DIDEVICE_SUBTYPE(caps.dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD); - //I_OutputMsg("Gamepad: %d\n", Joystick.bGamepadStyle); - - - CONS_Printf(M_GetText("Capabilities: %lu axes, %lu buttons, %lu POVs, poll %u, Gamepad %d\n"), caps.dwAxes, caps.dwButtons, caps.dwPOVs, Joystick.bJoyNeedPoll, Joystick.bGamepadStyle); - - // Set the data format to "simple joystick" - a predefined data format - // - // A data format specifies which controls on a device we - // are interested in, and how they should be reported. - // - // This tells DirectInput that we will be passing a - // DIJOYSTATE structure to IDirectInputDevice::GetDeviceState. - if (IDirectInputDevice_SetDataFormat (pdev, &c_dfDIJoystick) != DI_OK) - { - I_OutputMsg("DIEnumJoysticks(): SetDataFormat FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // Set the cooperativity level to let DirectInput know how - // this device should interact with the system and with other - // DirectInput applications. - if (IDirectInputDevice_SetCooperativeLevel (pdev, hWndMain, - DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) - { - I_OutputMsg("DIEnumJoysticks(): SetCooperativeLevel FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // set the range of the joystick axis - diprg.diph.dwSize = sizeof (DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof (DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.lMin = -JOYAXISRANGE; // value for extreme left - diprg.lMax = +JOYAXISRANGE; // value for extreme right - - diprg.diph.dwObj = DIJOFS_X; // set the x-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //goto SetPropFail; - JoyInfo.X = FALSE; - } - else JoyInfo.X = TRUE; - - diprg.diph.dwObj = DIJOFS_Y; // set the y-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { -//SetPropFail: -// I_OutputMsg("DIEnumJoysticks(): SetProperty FAILED\n"); -// IDirectInputDevice_Release (pdev); -// return DIENUM_CONTINUE; - JoyInfo.Y = FALSE; - } - else JoyInfo.Y = TRUE; - - diprg.diph.dwObj = DIJOFS_Z; // set the z-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_Z not found\n"); - JoyInfo.Z = FALSE; - } - else JoyInfo.Z = TRUE; - - diprg.diph.dwObj = DIJOFS_RX; // set the x-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RX (x-rudder) not found\n"); - JoyInfo.Rx = FALSE; - } - else JoyInfo.Rx = TRUE; - - diprg.diph.dwObj = DIJOFS_RY; // set the y-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RY (y-rudder) not found\n"); - JoyInfo.Ry = FALSE; - } - else JoyInfo.Ry = TRUE; - - diprg.diph.dwObj = DIJOFS_RZ; // set the z-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RZ (z-rudder) not found\n"); - JoyInfo.Rz = FALSE; - } - else JoyInfo.Rz = TRUE; - diprg.diph.dwObj = DIJOFS_SLIDER(0); // set the x-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RZ (x-misc) not found\n"); - JoyInfo.U = FALSE; - } - else JoyInfo.U = TRUE; - - diprg.diph.dwObj = DIJOFS_SLIDER(1); // set the y-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RZ (y-misc) not found\n"); - JoyInfo.V = FALSE; - } - else JoyInfo.V = TRUE; - - // set X axis dead zone to 25% (to avoid accidental turning) - if (!Joystick.bGamepadStyle) - { - if (JoyInfo.X) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_X, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for X DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Y) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Y, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for Y DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Z) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Z, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for Z DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Rx) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_RX, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for RX DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Ry) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_RY, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for RY DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Rz) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_RZ, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for RZ DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.U) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(0), - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for U DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.V) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(1), - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks(): couldn't SetProperty for V DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - } - - // query for IDirectInputDevice2 - we need this to poll the joystick - if (bDX0300) - { - FFType i = EvilForce; - // we won't use the poll - lpDIJA = NULL; - for (i = 0; i > NumberofForces; i++) - lpDIE[i] = NULL; - } - else - { - LPDIRECTINPUTDEVICE2A *rp = &lpDIJA; - LPVOID *tp = (LPVOID *)rp; - if (FAILED(IDirectInputDevice_QueryInterface(pdev, &IID_IDirectInputDevice2, tp))) - { - I_OutputMsg("DIEnumJoysticks(): QueryInterface FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - if (lpDIJA && JoyInfo.ForceAxises != -1) - { - // Since we will be playing force feedback effects, we should disable the - // auto-centering spring. - if (FAILED(SetDIDwordProperty(pdev, DIPROP_AUTOCENTER, 0, DIPH_DEVICE, FALSE))) - { - //NOP - } - - // Enumerate and count the axes of the joystick - if (FAILED(IDirectInputDevice_EnumObjects(pdev, EnumAxesCallback, - (LPVOID)&JoyInfo.ForceAxises, DIDFT_AXIS))) - { - JoyInfo.ForceAxises = -1; - } - else - { - SetupAllForces(lpDIJA,lpDIE,JoyInfo.ForceAxises); - } - } - } - - // we successfully created an IDirectInputDevice. So stop looking - // for another one. - lpDIJ = pdev; - return DIENUM_STOP; -} - -// -------------- -// I_InitJoystick -// This is called everytime the 'use_joystick' variable changes -// It is normally called at least once at startup when the config is loaded -// -------------- -void I_InitJoystick(void) -{ - HRESULT hr; - - // cleanup - I_ShutdownJoystick(); - - //joystick detection can be skipped by setting use_joystick to 0 - if (!lpDI || M_CheckParm("-nojoy")) - { - CONS_Printf(M_GetText("Joystick disabled\n")); - return; - } - else - // don't do anything at the registration of the joystick cvar, - // until config is loaded - if (!strcmp(cv_usejoystick.string, "0")) - return; - - // acquire the joystick only once - if (!lpDIJ) - { - joystick_detected = false; - - CONS_Printf(M_GetText("Looking for joystick devices:\n")); - iJoyNum = 0; - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, DIEnumJoysticks, - (void *)&cv_usejoystick, // our user parameter is joystick number - DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - { - CONS_Alert(CONS_WARNING, M_GetText("Joystick initialize failed.\n")); - cv_usejoystick.value = 0; - return; - } - - if (!lpDIJ) - { - if (!iJoyNum) - CONS_Printf(M_GetText("none found\n")); - else - { - CONS_Printf(M_GetText("none used\n")); - if (cv_usejoystick.value > 0 && cv_usejoystick.value > iJoyNum) - { - CONS_Alert(CONS_WARNING, M_GetText("Set the use_joystick variable to one of the enumerated joystick numbers\n")); - } - } - cv_usejoystick.value = 0; - return; - } - - I_AddExitFunc(I_ShutdownJoystick); - - // set coop level - if (FAILED(IDirectInputDevice_SetCooperativeLevel(lpDIJ, hWndMain, - DISCL_NONEXCLUSIVE|DISCL_FOREGROUND))) - { - I_Error("I_InitJoystick: SetCooperativeLevel FAILED"); - } - } - else - CONS_Printf(M_GetText("Joystick already initialized\n")); - - // we don't unacquire joystick, so let's just pretend we re-acquired it - joystick_detected = true; -} -//Joystick 2 - -// --------------- -// DIEnumJoysticks2 -// There is no such thing as a 'system' joystick, contrary to mouse, -// we must enumerate and choose one joystick device to use -// --------------- -static BOOL CALLBACK DIEnumJoysticks2 (LPCDIDEVICEINSTANCEA lpddi, - LPVOID pvRef) //cv_usejoystick -{ - LPDIRECTINPUTDEVICEA pdev; - DIPROPRANGE diprg; - DIDEVCAPS caps; - BOOL bUseThisOne = FALSE; - - iJoy2Num++; - - //faB: if cv holds a string description of joystick, the value from atoi() is 0 - // else, the value was probably set by user at console to one of the previsouly - // enumerated joysticks - if (((consvar_t *)pvRef)->value == iJoy2Num || !strcmp(((consvar_t *)pvRef)->string, lpddi->tszProductName)) - bUseThisOne = TRUE; - - //I_OutputMsg(" cv joy2 is %s\n", ((consvar_t *)pvRef)->string); - - // print out device name - CONS_Printf("%c%d: %s\n", - (bUseThisOne) ? '\2' : ' ', // show name in white if this is the one we will use - iJoy2Num, - //(GET_DIDEVICE_SUBTYPE(lpddi->dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD) ? "Gamepad " : "Joystick", - lpddi->tszProductName); //, lpddi->tszInstanceName); - - // use specified joystick (cv_usejoystick.value in pvRef) - if (!bUseThisOne) - return DIENUM_CONTINUE; - - ((consvar_t *)pvRef)->value = iJoy2Num; - if (IDirectInput_CreateDevice (lpDI, &lpddi->guidInstance, - &pdev, NULL) != DI_OK) - { - // if it failed, then we can't use this joystick for some - // bizarre reason. (Maybe the user unplugged it while we - // were in the middle of enumerating it.) So continue enumerating - I_OutputMsg("DIEnumJoysticks2(): CreateDevice FAILED\n"); - return DIENUM_CONTINUE; - } - - - // get the Device capabilities - // - caps.dwSize = sizeof (DIDEVCAPS_DX3); - if (FAILED(IDirectInputDevice_GetCapabilities (pdev, &caps))) - { - I_OutputMsg("DIEnumJoysticks2(): GetCapabilities FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - if (!(caps.dwFlags & DIDC_ATTACHED)) // should be, since we enumerate only attached devices - return DIENUM_CONTINUE; - - Joystick2.bJoyNeedPoll = ((caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0); - - if (caps.dwFlags & DIDC_FORCEFEEDBACK) - JoyInfo2.ForceAxises = 0; - else - JoyInfo2.ForceAxises = -1; - - Joystick2.bGamepadStyle = (GET_DIDEVICE_SUBTYPE(caps.dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD); - //I_OutputMsg("Gamepad: %d\n", Joystick2.bGamepadStyle); - - CONS_Printf(M_GetText("Capabilities: %lu axes, %lu buttons, %lu POVs, poll %u, Gamepad %d\n"), caps.dwAxes, caps.dwButtons, caps.dwPOVs, Joystick2.bJoyNeedPoll, Joystick2.bGamepadStyle); - - // Set the data format to "simple joystick" - a predefined data format - // - // A data format specifies which controls on a device we - // are interested in, and how they should be reported. - // - // This tells DirectInput that we will be passing a - // DIJOYSTATE structure to IDirectInputDevice::GetDeviceState. - if (IDirectInputDevice_SetDataFormat (pdev, &c_dfDIJoystick) != DI_OK) - { - I_OutputMsg("DIEnumJoysticks2(): SetDataFormat FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // Set the cooperativity level to let DirectInput know how - // this device should interact with the system and with other - // DirectInput applications. - if (IDirectInputDevice_SetCooperativeLevel (pdev, hWndMain, - DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) - { - I_OutputMsg("DIEnumJoysticks2(): SetCooperativeLevel FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // set the range of the joystick axis - diprg.diph.dwSize = sizeof (DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof (DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.lMin = -JOYAXISRANGE; // value for extreme left - diprg.lMax = +JOYAXISRANGE; // value for extreme right - - diprg.diph.dwObj = DIJOFS_X; // set the x-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //goto SetPropFail; - JoyInfo2.X = FALSE; - } - else JoyInfo2.X = TRUE; - - diprg.diph.dwObj = DIJOFS_Y; // set the y-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { -//SetPropFail: -// I_OutputMsg("DIEnumJoysticks(): SetProperty FAILED\n"); -// IDirectInputDevice_Release (pdev); -// return DIENUM_CONTINUE; - JoyInfo2.Y = FALSE; - } - else JoyInfo2.Y = TRUE; - - diprg.diph.dwObj = DIJOFS_Z; // set the z-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_Z not found\n"); - JoyInfo2.Z = FALSE; - } - else JoyInfo2.Z = TRUE; - - diprg.diph.dwObj = DIJOFS_RX; // set the x-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RX (x-rudder) not found\n"); - JoyInfo2.Rx = FALSE; - } - else JoyInfo2.Rx = TRUE; - - diprg.diph.dwObj = DIJOFS_RY; // set the y-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RY (y-rudder) not found\n"); - JoyInfo2.Ry = FALSE; - } - else JoyInfo2.Ry = TRUE; - - diprg.diph.dwObj = DIJOFS_RZ; // set the z-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RZ (z-rudder) not found\n"); - JoyInfo2.Rz = FALSE; - } - else JoyInfo2.Rz = TRUE; - diprg.diph.dwObj = DIJOFS_SLIDER(0); // set the x-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RZ (x-misc) not found\n"); - JoyInfo2.U = FALSE; - } - else JoyInfo2.U = TRUE; - - diprg.diph.dwObj = DIJOFS_SLIDER(1); // set the y-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //I_OutputMsg("DIJOFS_RZ (y-misc) not found\n"); - JoyInfo2.V = FALSE; - } - else JoyInfo2.V = TRUE; - - // set X axis dead zone to 25% (to avoid accidental turning) - if (!Joystick2.bGamepadStyle) - { - if (JoyInfo2.X) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_X, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for X DEAD ZONE"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Y) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Y, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for Y DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Z) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Z, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for Z DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Rx) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_RX, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for RX DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Ry) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_RY, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for RY DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Rz) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_RZ, - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for RZ DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.U) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(0), - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for U DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.V) - if (FAILED(SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(1), - DIPH_BYOFFSET, DIDEADZONE))) - { - I_OutputMsg("DIEnumJoysticks2(): couldn't SetProperty for V DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - } - - // query for IDirectInputDevice2 - we need this to poll the joystick - if (bDX0300) - { - FFType i = EvilForce; - // we won't use the poll - lpDIJA = NULL; - for (i = 0; i > NumberofForces; i++) - lpDIE[i] = NULL; - } - else - { - LPDIRECTINPUTDEVICE2A *rp = &lpDIJ2A; - LPVOID *tp = (LPVOID *)rp; - if (FAILED(IDirectInputDevice_QueryInterface(pdev, &IID_IDirectInputDevice2, tp))) - { - I_OutputMsg("DIEnumJoysticks2(): QueryInterface FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - if (lpDIJ2A && JoyInfo2.ForceAxises != -1) - { - // Since we will be playing force feedback effects, we should disable the - // auto-centering spring. - if (FAILED(SetDIDwordProperty(pdev, DIPROP_AUTOCENTER, 0, DIPH_DEVICE, FALSE))) - { - //NOP - } - - // Enumerate and count the axes of the joystick - if (FAILED(IDirectInputDevice_EnumObjects(pdev, EnumAxesCallback, - (LPVOID)&JoyInfo2.ForceAxises, DIDFT_AXIS))) - { - JoyInfo2.ForceAxises = -1; - } - else - { - SetupAllForces(lpDIJ2A,lpDIE2,JoyInfo2.ForceAxises); - } - } - } - - // we successfully created an IDirectInputDevice. So stop looking - // for another one. - lpDIJ2 = pdev; - return DIENUM_STOP; -} - - -// -------------- -// I_InitJoystick2 -// This is called everytime the 'use_joystick2' variable changes -// It is normally called at least once at startup when the config is loaded -// -------------- -void I_InitJoystick2 (void) -{ - HRESULT hr; - - // cleanup - I_ShutdownJoystick2 (); - - joystick2_detected = false; - - // joystick detection can be skipped by setting use_joystick to 0 - if (!lpDI || M_CheckParm("-nojoy")) - { - CONS_Printf(M_GetText("Joystick2 disabled\n")); - return; - } - else - // don't do anything at the registration of the joystick cvar, - // until config is loaded - if (!strcmp(cv_usejoystick2.string, "0")) - return; - - // acquire the joystick only once - if (!lpDIJ2) - { - joystick2_detected = false; - - CONS_Printf(M_GetText("Looking for joystick devices:\n")); - iJoy2Num = 0; - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, - DIEnumJoysticks2, - (LPVOID)&cv_usejoystick2, // our user parameter is joystick number - DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - { - CONS_Alert(CONS_WARNING, M_GetText("Joystick initialize failed.\n")); - cv_usejoystick2.value = 0; - return; - } - - if (!lpDIJ2) - { - if (iJoy2Num == 0) - CONS_Printf(M_GetText("none found\n")); - else - { - CONS_Printf(M_GetText("none used\n")); - if (cv_usejoystick2.value > 0 && - cv_usejoystick2.value > iJoy2Num) - { - CONS_Alert(CONS_WARNING, M_GetText("Set the use_joystick2 variable to one of the enumerated joysticks number\n")); - } - } - cv_usejoystick2.value = 0; - return; - } - - I_AddExitFunc (I_ShutdownJoystick2); - - // set coop level - if (FAILED(IDirectInputDevice_SetCooperativeLevel (lpDIJ2, hWndMain, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND))) - I_Error("I_InitJoystick2: SetCooperativeLevel FAILED"); - - // later - //if (FAILED(IDirectInputDevice_Acquire (lpDIJ2))) - // I_Error("Couldn't acquire Joystick2"); - - joystick2_detected = true; - } - else - CONS_Printf(M_GetText("Joystick already initialized\n")); - - //faB: we don't unacquire joystick, so let's just pretend we re-acquired it - joystick2_detected = true; -} - -/** \brief Joystick 1 buttons states -*/ -static UINT64 lastjoybuttons = 0; - -/** \brief Joystick 1 hats state -*/ -static UINT64 lastjoyhats = 0; - -static VOID I_ShutdownJoystick(VOID) -{ - int i; - event_t event; - - lastjoybuttons = lastjoyhats = 0; - - event.type = ev_keyup; - - // emulate the up of all joystick buttons - for (i = 0;i < JOYBUTTONS;i++) - { - event.data1 = 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; - D_PostEvent(&event); - } - - // reset joystick position - event.type = ev_joystick; - for (i = 0;i < JOYAXISSET; i++) - { - event.data1 = i; - D_PostEvent(&event); - } - - if (joystick_detected) - CONS_Printf("I_ShutdownJoystick()\n"); - - for (i = 0; i > NumberofForces; i++) - { - if (lpDIE[i]) - { - IDirectInputEffect_Release(lpDIE[i]); - lpDIE[i] = NULL; - - } - } - if (lpDIJ) - { - IDirectInputDevice_Unacquire(lpDIJ); - IDirectInputDevice_Release(lpDIJ); - lpDIJ = NULL; - } - if (lpDIJA) - { - IDirectInputDevice2_Release(lpDIJA); - lpDIJA = NULL; - } - joystick_detected = false; -} - -/** \brief Joystick 2 buttons states -*/ -static UINT64 lastjoy2buttons = 0; - -/** \brief Joystick 2 hats state -*/ -static UINT64 lastjoy2hats = 0; - -static VOID I_ShutdownJoystick2(VOID) -{ - int i; - event_t event; - - lastjoy2buttons = lastjoy2hats = 0; - - event.type = ev_keyup; - - // emulate the up of all joystick buttons - for (i = 0;i < JOYBUTTONS;i++) - { - event.data1 = 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; - D_PostEvent(&event); - } - - // reset joystick position - event.type = ev_joystick2; - for (i = 0;i < JOYAXISSET; i++) - { - event.data1 = i; - D_PostEvent(&event); - } - - if (joystick2_detected) - CONS_Printf("I_ShutdownJoystick2()\n"); - - for (i = 0; i > NumberofForces; i++) - { - if (lpDIE2[i]) - { - IDirectInputEffect_Release(lpDIE2[i]); - lpDIE2[i] = NULL; - } - } - if (lpDIJ2) - { - IDirectInputDevice_Unacquire(lpDIJ2); - IDirectInputDevice_Release(lpDIJ2); - lpDIJ2 = NULL; - } - if (lpDIJ2A) - { - IDirectInputDevice2_Release(lpDIJ2A); - lpDIJ2A = NULL; - } - joystick2_detected = false; -} - -// ------------------- -// I_GetJoystickEvents -// Get current joystick axis and button states -// ------------------- -void I_GetJoystickEvents(void) -{ - HRESULT hr; - DIJOYSTATE js; // DirectInput joystick state - int i; - UINT64 joybuttons = 0; - UINT64 joyhats = 0; - event_t event; - - if (!lpDIJ) - return; - - // if input is lost then acquire and keep trying - for (;;) - { - // poll the joystick to read the current state - // if the device doesn't require polling, this function returns almost instantly - if (lpDIJA) - { - hr = IDirectInputDevice2_Poll(lpDIJA); - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - goto acquire; - else if (FAILED(hr)) - { - I_OutputMsg("I_GetJoystickEvents(): Poll FAILED\n"); - return; - } - } - - // get the input's device state, and put the state in dims - hr = IDirectInputDevice_GetDeviceState(lpDIJ, sizeof (DIJOYSTATE), &js); - - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - // DirectInput is telling us that the input stream has - // been interrupted. We aren't tracking any state - // between polls, so we don't have any special reset - // that needs to be done. We just re-acquire and - // try again. - goto acquire; - } - else if (FAILED(hr)) - { - I_OutputMsg("I_GetJoystickEvents(): GetDeviceState FAILED\n"); - return; - } - - break; -acquire: - if (FAILED(IDirectInputDevice_Acquire(lpDIJ))) - return; - } - - // look for as many buttons as g_input code supports, we don't use the others - for (i = JOYBUTTONS_MIN - 1; i >= 0; i--) - { - joybuttons <<= 1; - if (js.rgbButtons[i]) - joybuttons |= 1; - } - - for (i = JOYHATS_MIN -1; i >=0; i--) - { - if (js.rgdwPOV[i] != 0xffff && js.rgdwPOV[i] != 0xffffffff) - { - if (js.rgdwPOV[i] > 270 * DI_DEGREES || js.rgdwPOV[i] < 90 * DI_DEGREES) - joyhats |= (UINT64)1<<(0 + 4*(UINT64)i); // UP - else if (js.rgdwPOV[i] > 90 * DI_DEGREES && js.rgdwPOV[i] < 270 * DI_DEGREES) - joyhats |= (UINT64)1<<(1 + 4*(UINT64)i); // DOWN - if (js.rgdwPOV[i] > 0 * DI_DEGREES && js.rgdwPOV[i] < 180 * DI_DEGREES) - joyhats |= (UINT64)1<<(3 + 4*(UINT64)i); // LEFT - else if (js.rgdwPOV[i] > 180 * DI_DEGREES && js.rgdwPOV[i] < 360 * DI_DEGREES) - joyhats |= (UINT64)1<<(2 + 4*(UINT64)i); // RIGHT - } - } - - if (joybuttons != lastjoybuttons) - { - UINT64 j = 1; // keep only bits that changed since last time - UINT64 newbuttons = joybuttons ^ lastjoybuttons; - lastjoybuttons = joybuttons; - - for (i = 0; i < JOYBUTTONS_MIN; i++, j <<= 1) - { - if (newbuttons & j) // button changed state? - { - if (joybuttons & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_JOY1 + i; - D_PostEvent(&event); - } - } - } - - if (joyhats != lastjoyhats) - { - UINT64 j = 1; // keep only bits that changed since last time - UINT64 newhats = joyhats ^ lastjoyhats; - lastjoyhats = joyhats; - - for (i = 0; i < JOYHATS_MIN*4; i++, j <<= 1) - { - if (newhats & j) // button changed state? - { - if (joyhats & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_HAT1 + i; - D_PostEvent(&event); - } - } - - } - - // send joystick axis positions - event.type = ev_joystick; - event.data1 = event.data2 = event.data3 = 0; - - if (Joystick.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo.X) - { - if (js.lX < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lX > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.Y) - { - if (js.lY < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lY > JOYAXISRANGE/2) - event.data3 = 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 - } - - D_PostEvent(&event); -#if JOYAXISSET > 1 - event.data1 = 1; - event.data2 = event.data3 = 0; - - if (Joystick.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo.Z) - { - if (js.lZ < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lZ > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.Rx) - { - if (js.lRx < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRx > JOYAXISRANGE/2) - event.data3 = 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 - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 2 - event.data1 = 2; - event.data2 = event.data3 = 0; - - if (Joystick.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo.Rx) - { - if (js.lRy < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lRy > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.Rz) - { - if (js.lRz < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRz > JOYAXISRANGE/2) - event.data3 = 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 - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 3 - event.data1 = 3; - event.data2 = event.data3 = 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; - else if (js.rglSlider[0] > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.V) - { - if (js.rglSlider[1] < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.rglSlider[1] > JOYAXISRANGE/2) - event.data3 = 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 - } - D_PostEvent(&event); -#endif -} - -// ------------------- -// I_GetJoystickEvents -// Get current joystick axis and button states -// ------------------- -void I_GetJoystick2Events(void) -{ - HRESULT hr; - DIJOYSTATE js; // DirectInput joystick state - int i; - UINT64 joybuttons = 0; - UINT64 joyhats = 0; - event_t event; - - if (!lpDIJ2) - return; - - // if input is lost then acquire and keep trying - for (;;) - { - // poll the joystick to read the current state - // if the device doesn't require polling, this function returns almost instantly - if (lpDIJ2A) - { - hr = IDirectInputDevice2_Poll(lpDIJ2A); - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - goto acquire; - else if (FAILED(hr)) - { - I_OutputMsg("I_GetJoystick2Events(): Poll FAILED\n"); - return; - } - } - - // get the input's device state, and put the state in dims - hr = IDirectInputDevice_GetDeviceState(lpDIJ2, sizeof (DIJOYSTATE), &js); - - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - // DirectInput is telling us that the input stream has - // been interrupted. We aren't tracking any state - // between polls, so we don't have any special reset - // that needs to be done. We just re-acquire and - // try again. - goto acquire; - } - else if (FAILED(hr)) - { - I_OutputMsg("I_GetJoystickEvents2(): GetDeviceState FAILED\n"); - return; - } - - break; -acquire: - if (FAILED(IDirectInputDevice_Acquire(lpDIJ2))) - return; - } - - // look for as many buttons as g_input code supports, we don't use the others - for (i = JOYBUTTONS_MIN - 1; i >= 0; i--) - { - joybuttons <<= 1; - if (js.rgbButtons[i]) - joybuttons |= 1; - } - - for (i = JOYHATS_MIN -1; i >=0; i--) - { - if (js.rgdwPOV[i] != 0xffff && js.rgdwPOV[i] != 0xffffffff) - { - if (js.rgdwPOV[i] > 270 * DI_DEGREES || js.rgdwPOV[i] < 90 * DI_DEGREES) - joyhats |= (UINT64)1<<(0 + 4*(UINT64)i); // UP - else if (js.rgdwPOV[i] > 90 * DI_DEGREES && js.rgdwPOV[i] < 270 * DI_DEGREES) - joyhats |= (UINT64)1<<(1 + 4*(UINT64)i); // DOWN - if (js.rgdwPOV[i] > 0 * DI_DEGREES && js.rgdwPOV[i] < 180 * DI_DEGREES) - joyhats |= (UINT64)1<<(3 + 4*(UINT64)i); // LEFT - else if (js.rgdwPOV[i] > 180 * DI_DEGREES && js.rgdwPOV[i] < 360 * DI_DEGREES) - joyhats |= (UINT64)1<<(2 + 4*(UINT64)i); // RIGHT - } - } - - if (joybuttons != lastjoy2buttons) - { - UINT64 j = 1; // keep only bits that changed since last time - UINT64 newbuttons = joybuttons ^ lastjoy2buttons; - lastjoy2buttons = joybuttons; - - for (i = 0; i < JOYBUTTONS_MIN; i++, j <<= 1) - { - if (newbuttons & j) // button changed state? - { - if (joybuttons & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_2JOY1 + i; - D_PostEvent(&event); - } - } - } - - if (joyhats != lastjoy2hats) - { - UINT64 j = 1; // keep only bits that changed since last time - UINT64 newhats = joyhats ^ lastjoy2hats; - lastjoy2hats = joyhats; - - for (i = 0; i < JOYHATS_MIN*4; i++, j <<= 1) - { - if (newhats & j) // button changed state? - { - if (joyhats & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_2HAT1 + i; - D_PostEvent(&event); - } - } - - } - - // send joystick axis positions - event.type = ev_joystick2; - event.data1 = event.data2 = event.data3 = 0; - - if (Joystick2.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo2.X) - { - if (js.lX < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lX > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.Y) - { - if (js.lY < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lY > JOYAXISRANGE/2) - event.data3 = 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 - } - - D_PostEvent(&event); -#if JOYAXISSET > 1 - event.data1 = 1; - event.data2 = event.data3 = 0; - - if (Joystick2.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo2.Z) - { - if (js.lZ < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lZ > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.Rx) - { - if (js.lRx < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRx > JOYAXISRANGE/2) - event.data3 = 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 - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 2 - event.data1 = 2; - event.data2 = event.data3 = 0; - - if (Joystick2.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo2.Rx) - { - if (js.lRy < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lRy > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.Rz) - { - if (js.lRz < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRz > JOYAXISRANGE/2) - event.data3 = 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 - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 3 - event.data1 = 3; - event.data2 = event.data3 = 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; - else if (js.rglSlider[0] > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.V) - { - if (js.rglSlider[1] < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.rglSlider[1] > JOYAXISRANGE/2) - event.data3 = 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 - } - D_PostEvent(&event); -#endif -} - -static int numofjoy = 0; -static char joyname[MAX_PATH]; -static int needjoy = -1; - -static BOOL CALLBACK DIEnumJoysticksCount (LPCDIDEVICEINSTANCEA lpddi, - LPVOID pvRef) //joyname -{ - numofjoy++; - if (needjoy == numofjoy && pvRef && pvRef == (void *)joyname && lpddi - && lpddi->tszProductName) - { - sprintf(joyname,"%s",lpddi->tszProductName); - return DIENUM_STOP; - } - //else I_OutputMsg("DIEnumJoysticksCount need help!\n"); - return DIENUM_CONTINUE; -} - -INT32 I_NumJoys(void) -{ - HRESULT hr; - needjoy = -1; - numofjoy = 0; - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, - DIEnumJoysticksCount, (LPVOID)&numofjoy, DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - { - I_OutputMsg("\nI_NumJoys(): EnumDevices FAILED\n"); - } - return numofjoy; - -} - -const char *I_GetJoyName(INT32 joyindex) -{ - HRESULT hr; - needjoy = joyindex; - numofjoy = 0; - ZeroMemory(joyname,sizeof (joyname)); - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, - DIEnumJoysticksCount, (LPVOID)joyname, DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - { - I_OutputMsg("\nI_GetJoyName(): EnumDevices FAILED\n"); - } - if (joyname[0] == 0) return NULL; - return joyname; -} - -#ifndef NOMUMBLE -// Best Mumble positional audio settings: -// Minimum distance 3.0 m -// Bloom 175% -// Maximum distance 80.0 m -// Minimum volume 50% -#define DEG2RAD (0.017453292519943295769236907684883l) // TAU/360 or PI/180 -#define MUMBLEUNIT (64.0f) // FRACUNITS in a Meter - -static struct { - UINT32 uiVersion; - DWORD uiTick; - float fAvatarPosition[3]; - float fAvatarFront[3]; - float fAvatarTop[3]; // defaults to Y-is-up (only used for leaning) - wchar_t name[256]; // game name - float fCameraPosition[3]; - float fCameraFront[3]; - float fCameraTop[3]; // defaults to Y-is-up (only used for leaning) - wchar_t identity[256]; // player id - UINT32 context_len; - unsigned char context[256]; // server/team - wchar_t description[2048]; // game description -} *mumble = NULL; - -static inline void I_SetupMumble(void) -{ - HANDLE hMap = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink"); - if (!hMap) - return; - - mumble = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*mumble)); - if (!mumble) - CloseHandle(hMap); -} - -void I_UpdateMumble(const mobj_t *mobj, const listener_t listener) -{ - double angle; - fixed_t anglef; - - if (!mumble) - return; - - if(mumble->uiVersion != 2) { - wcsncpy(mumble->name, L"SRB2 "VERSIONSTRINGW, 256); - wcsncpy(mumble->description, L"Sonic Robo Blast 2 with integrated Mumble Link support.", 2048); - mumble->uiVersion = 2; - } - mumble->uiTick++; - - if (!netgame || gamestate != GS_LEVEL) { // Zero out, but never delink. - mumble->fAvatarPosition[0] = mumble->fAvatarPosition[1] = mumble->fAvatarPosition[2] = 0.0f; - mumble->fAvatarFront[0] = 1.0f; - mumble->fAvatarFront[1] = mumble->fAvatarFront[2] = 0.0f; - mumble->fCameraPosition[0] = mumble->fCameraPosition[1] = mumble->fCameraPosition[2] = 0.0f; - mumble->fCameraFront[0] = 1.0f; - mumble->fCameraFront[1] = mumble->fCameraFront[2] = 0.0f; - return; - } - - { - UINT8 *p = mumble->context; - WRITEMEM(p, server_context, 8); - WRITEINT16(p, gamemap); - mumble->context_len = p - mumble->context; - } - - if (mobj) { - mumble->fAvatarPosition[0] = FIXED_TO_FLOAT(mobj->x) / MUMBLEUNIT; - mumble->fAvatarPosition[1] = FIXED_TO_FLOAT(mobj->z) / MUMBLEUNIT; - mumble->fAvatarPosition[2] = FIXED_TO_FLOAT(mobj->y) / MUMBLEUNIT; - - anglef = AngleFixed(mobj->angle); - angle = FIXED_TO_FLOAT(anglef)*DEG2RAD; - mumble->fAvatarFront[0] = (float)cos(angle); - mumble->fAvatarFront[1] = 0.0f; - mumble->fAvatarFront[2] = (float)sin(angle); - } else { - mumble->fAvatarPosition[0] = mumble->fAvatarPosition[1] = mumble->fAvatarPosition[2] = 0.0f; - mumble->fAvatarFront[0] = 1.0f; - mumble->fAvatarFront[1] = mumble->fAvatarFront[2] = 0.0f; - } - - mumble->fCameraPosition[0] = FIXED_TO_FLOAT(listener.x) / MUMBLEUNIT; - mumble->fCameraPosition[1] = FIXED_TO_FLOAT(listener.z) / MUMBLEUNIT; - mumble->fCameraPosition[2] = FIXED_TO_FLOAT(listener.y) / MUMBLEUNIT; - - anglef = AngleFixed(listener.angle); - angle = FIXED_TO_FLOAT(anglef)*DEG2RAD; - mumble->fCameraFront[0] = (float)cos(angle); - mumble->fCameraFront[1] = 0.0f; - mumble->fCameraFront[2] = (float)sin(angle); -} -#endif - -// =========================================================================================== -// DIRECT INPUT KEYBOARD -// =========================================================================================== - -static UINT8 ASCIINames[256] = -{ - // 0 1 2 3 4 5 6 7 - // 8 9 A B C D E F - 0, 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', KEY_MINUS,KEY_EQUALS,KEY_BACKSPACE, KEY_TAB, - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']',KEY_ENTER,KEY_LCTRL,'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'', '`', KEY_LSHIFT,'\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', KEY_RSHIFT,'*', - KEY_LALT,KEY_SPACE,KEY_CAPSLOCK,KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5, - KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,KEY_NUMLOCK,KEY_SCROLLLOCK,KEY_KEYPAD7, - KEY_KEYPAD8,KEY_KEYPAD9,KEY_MINUSPAD,KEY_KEYPAD4,KEY_KEYPAD5,KEY_KEYPAD6,KEY_PLUSPAD,KEY_KEYPAD1, - KEY_KEYPAD2,KEY_KEYPAD3,KEY_KEYPAD0,KEY_KPADDEL,0,0,0, KEY_F11, - KEY_F12,0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - // 0 1 2 3 4 5 6 7 - // 8 9 A B C D E F - - 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_ENTER,KEY_RCTRL,0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, KEY_KPADDEL, 0,KEY_KPADSLASH,0, 0, - KEY_RALT, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, KEY_HOME, // 0xc0 - KEY_UPARROW,KEY_PGUP,0,KEY_LEFTARROW,0,KEY_RIGHTARROW,0,KEY_END, - KEY_DOWNARROW,KEY_PGDN, KEY_INS,KEY_DEL,0,0,0,0, - 0, 0, 0,KEY_LEFTWIN,KEY_RIGHTWIN,KEY_MENU, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0 - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -// Return a key that has been pushed, or 0 (replace getchar() at game startup) -// -INT32 I_GetKey(void) -{ - event_t *ev; - - if (eventtail != eventhead) - { - ev = &events[eventtail]; - eventtail = (eventtail+1) & (MAXEVENTS-1); - if (ev->type == ev_keydown || ev->type == ev_console) - return ev->data1; - else - return 0; - } - return 0; -} - -// ----------------- -// I_StartupKeyboard -// Installs DirectInput keyboard -// ----------------- -#define DI_KEYBOARD_BUFFERSIZE 32 // number of data elements in keyboard buffer - -static void I_StartupKeyboard(void) -{ - DIPROPDWORD dip; - - if (dedicated || !lpDI) - return; - - // make sure the app window has the focus or DirectInput acquire keyboard won't work - if (hWndMain) - { - SetFocus(hWndMain); - ShowWindow(hWndMain, SW_SHOW); - UpdateWindow(hWndMain); - } - - // detect error - if (lpDIK) - { - I_OutputMsg("I_StartupKeyboard(): called twice\n"); - return; - } - - CreateDevice2A(lpDI, &GUID_SysKeyboard, &lpDIK, NULL); - - if (lpDIK) - { - if (FAILED(IDirectInputDevice_SetDataFormat(lpDIK, &c_dfDIKeyboard))) - I_Error("Couldn't set keyboard data format"); - - // create buffer for buffered data - dip.diph.dwSize = sizeof (dip); - dip.diph.dwHeaderSize = sizeof (dip.diph); - dip.diph.dwObj = 0; - dip.diph.dwHow = DIPH_DEVICE; - dip.dwData = DI_KEYBOARD_BUFFERSIZE; - if (FAILED(IDirectInputDevice_SetProperty(lpDIK, DIPROP_BUFFERSIZE, &dip.diph))) - I_Error("Couldn't set keyboard buffer size"); - - if (FAILED(IDirectInputDevice_SetCooperativeLevel(lpDIK, hWndMain, - DISCL_NONEXCLUSIVE|DISCL_FOREGROUND))) - { - I_Error("Couldn't set keyboard coop level"); - } - } - else - I_Error("Couldn't create keyboard input"); - - I_AddExitFunc(I_ShutdownKeyboard); - hacktics = 0; // see definition - keyboard_started = true; -} - -// ------------------ -// I_ShutdownKeyboard -// Release DirectInput keyboard. -// ------------------ -static VOID I_ShutdownKeyboard(VOID) -{ - if (!keyboard_started) - return; - - CONS_Printf("I_ShutdownKeyboard()\n"); - - if (lpDIK) - { - IDirectInputDevice_Unacquire(lpDIK); - IDirectInputDevice_Release(lpDIK); - lpDIK = NULL; - } - - keyboard_started = false; -} - -// ------------------- -// I_GetKeyboardEvents -// Get buffered data from the keyboard -// ------------------- -static VOID I_GetKeyboardEvents(VOID) -{ - static BOOL KeyboardLost = false; - - // simply repeat the last pushed key every xx tics, - // make more user friendly input for Console and game Menus -#define KEY_REPEAT_DELAY (NEWTICRATE/17) // TICRATE tics, repeat every 1/3 second - static LONG RepeatKeyTics = 0; - static int RepeatKeyCode = 0; - - DIDEVICEOBJECTDATA rgdod[DI_KEYBOARD_BUFFERSIZE]; - DWORD dwItems, d; - HRESULT hr; - int ch; - - event_t event; - ZeroMemory(&event,sizeof (event)); - - if (!keyboard_started) - return; - - if (!appActive && RepeatKeyCode) // Stop when lost focus - { - event.type = ev_keyup; - event.data1 = RepeatKeyCode; - D_PostEvent(&event); - RepeatKeyCode = 0; - } -getBufferedData: - dwItems = DI_KEYBOARD_BUFFERSIZE; - hr = IDirectInputDevice_GetDeviceData(lpDIK, sizeof (DIDEVICEOBJECTDATA), rgdod, &dwItems, 0); - - // If data stream was interrupted, reacquire the device and try again. - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - // why it succeeds to acquire just after I don't understand.. so I set the flag BEFORE - KeyboardLost = true; - - hr = IDirectInputDevice_Acquire(lpDIK); - if (SUCCEEDED(hr)) - goto getBufferedData; - return; - } - - // we lost data, get device actual state to recover lost information - if (hr == DI_BUFFEROVERFLOW) - { - /// \note either uncomment or delete block - //I_Error("DI buffer overflow (keyboard)"); - //I_RecoverKeyboardState (); - - //hr = IDirectInputDevice_GetDeviceState (lpDIM, sizeof (keys), &diMouseState); - } - - // We got buffered input, act on it - if (SUCCEEDED(hr)) - { - // if we previously lost keyboard data, recover its current state - if (KeyboardLost) - { - /// \bug hack simply clears the keys so we don't have the last pressed keys - /// still active.. to have to re-trigger it is not much trouble for the user. - ZeroMemory(gamekeydown, NUMKEYS); - KeyboardLost = false; - } - - // dwItems contains number of elements read (could be 0) - for (d = 0; d < dwItems; d++) - { - // dwOfs member is DIK_* value - // dwData member 0x80 bit set press down, clear is release - - if (rgdod[d].dwData & 0x80) - event.type = ev_keydown; - else - event.type = ev_keyup; - - ch = rgdod[d].dwOfs & 0xFF; - if (ASCIINames[ch]) - event.data1 = ASCIINames[ch]; - else - event.data1 = 0x80; - - D_PostEvent(&event); - } - - // Key Repeat - if (dwItems) - { - // new key events, so stop repeating key - RepeatKeyCode = 0; - // 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; - } - else - { - // no new keys, repeat last pushed key after some time - if (RepeatKeyCode && hacktics - RepeatKeyTics > KEY_REPEAT_DELAY) - { - event.type = ev_keydown; - event.data1 = RepeatKeyCode; - D_PostEvent(&event); - - RepeatKeyTics = hacktics; - } - } - } -} - -static HINSTANCE DInputDLL = NULL; -typedef HRESULT (WINAPI *DICreateA)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter); -static DICreateA pfnDirectInputCreateA = NULL; - -BOOL LoadDirectInput(VOID) -{ - // load dinput.dll - DInputDLL = LoadLibraryA("DINPUT.DLL"); - if (DInputDLL == NULL) - return false; - pfnDirectInputCreateA = (DICreateA)(LPVOID)GetProcAddress(DInputDLL, "DirectInputCreateA"); - if (pfnDirectInputCreateA == NULL) - return false; - return true; -} - -static inline VOID UnLoadDirectInput(VOID) -{ - if (!DInputDLL) - return; - FreeLibrary(DInputDLL); - pfnDirectInputCreateA = NULL; - DInputDLL = NULL; -} - - -// -// Closes DirectInput -// -static VOID I_ShutdownDirectInput(VOID) -{ - if (lpDI) - IDirectInput_Release(lpDI); - lpDI = NULL; - UnLoadDirectInput(); -} - -// This stuff should get rid of the exception and page faults when -// SRB2 bugs out with an error. Now it should exit cleanly. -// -INT32 I_StartupSystem(void) -{ - HRESULT hr; - HINSTANCE myInstance = GetModuleHandle(NULL); - - // some 'more global than globals' things to initialize here ? - graphics_started = keyboard_started = sound_started = cdaudio_started = false; - - I_StartupKeyboard(); - -#ifdef NDEBUG - -#ifdef BUGTRAP - if(!IsBugTrapLoaded()) - { -#endif - signal(SIGABRT, signal_handler); - signal(SIGFPE, signal_handler); - signal(SIGILL, signal_handler); - signal(SIGSEGV, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); -#ifdef BUGTRAP - } -#endif - -#endif - -#ifndef NOMUMBLE - I_SetupMumble(); -#endif - - if (!pfnDirectInputCreateA) - return 1; - // create DirectInput - so that I_StartupKeyboard/Mouse can be called later on - // from D_SRB2Main just like DOS version - hr = pfnDirectInputCreateA(myInstance, DIRECTINPUT_VERSION, &lpDI, NULL); - - if (SUCCEEDED(hr)) - bDX0300 = FALSE; - else - { - // try opening DirectX3 interface for NT compatibility - hr = pfnDirectInputCreateA(myInstance, DXVERSION_NTCOMPATIBLE, &lpDI, NULL); - - if (FAILED(hr)) - { - const char *sErr; - switch (hr) - { - case DIERR_BETADIRECTINPUTVERSION: - sErr = "DIERR_BETADIRECTINPUTVERSION"; - break; - case DIERR_INVALIDPARAM: - sErr = "DIERR_INVALIDPARAM"; - break; - case DIERR_OLDDIRECTINPUTVERSION : - sErr = "DIERR_OLDDIRECTINPUTVERSION"; - break; - case DIERR_OUTOFMEMORY: - sErr = "DIERR_OUTOFMEMORY"; - break; - default: - sErr = "UNKNOWN"; - break; - } - I_Error("Couldn't create DirectInput (reason: %s)", sErr); - } - else - CONS_Printf("\x82%s", M_GetText("Using DirectX3 interface\n")); - - // only use DirectInput3 compatible structures and calls - bDX0300 = TRUE; - } - I_AddExitFunc(I_ShutdownDirectInput); - return 0; -} - -// Closes down everything. This includes restoring the initial -// palette and video mode, and removing whatever mouse, keyboard, and -// timer routines have been installed. -// -/// \bug doesn't restore wave/midi device volume -// -// Shutdown user funcs are effectively called in reverse order. -// -void I_ShutdownSystem(void) -{ - int c; - - for (c = MAX_QUIT_FUNCS - 1; c >= 0; c--) - if (quit_funcs[c]) - (*quit_funcs[c])(); -} - -// my god how win32 suck -typedef BOOL (WINAPI *p_GetDiskFreeSpaceExA)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); - -void I_GetDiskFreeSpace(INT64* freespace) -{ - static p_GetDiskFreeSpaceExA pfnGetDiskFreeSpaceEx = NULL; - static boolean testwin95 = false; - ULARGE_INTEGER usedbytes, lfreespace; - - if (!testwin95) - { - pfnGetDiskFreeSpaceEx = (p_GetDiskFreeSpaceExA)(LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetDiskFreeSpaceExA"); - testwin95 = true; - } - if (pfnGetDiskFreeSpaceEx) - { - if (pfnGetDiskFreeSpaceEx(NULL, &lfreespace, &usedbytes, NULL)) - *freespace = lfreespace.QuadPart; - else - *freespace = INT32_MAX; - } - else - { - DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters; - GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector, - &NumberOfFreeClusters, &TotalNumberOfClusters); - *freespace = BytesPerSector * SectorsPerCluster * NumberOfFreeClusters; - } -} - -char *I_GetUserName(void) -{ - static char username[MAXPLAYERNAME+1]; - char *p; - DWORD i = MAXPLAYERNAME; - - if (!GetUserNameA(username, &i)) - { - p = getenv("USER"); - if (!p) - { - p = getenv("user"); - if (!p) - { - p = getenv("USERNAME"); - if (!p) - { - p = getenv("username"); - if (!p) - { - return NULL; - } - } - } - } - strlcpy(username, p, sizeof (username)); - } - - if (!strlen(username)) - return NULL; - return username; -} - -INT32 I_mkdir(const char *dirname, INT32 unixright) -{ - UNREFERENCED_PARAMETER(unixright); /// \todo should implement ntright under nt... - return CreateDirectoryA(dirname, NULL); -} - -char * I_GetEnv(const char *name) -{ - return getenv(name); -} - -INT32 I_PutEnv(char *variable) -{ - return putenv(variable); -} - -INT32 I_ClipboardCopy(const char *data, size_t size) -{ - (void)data; - (void)size; - return -1; -} - -const char *I_ClipboardPaste(void) -{ - return NULL; -} - -typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD); - -const CPUInfoFlags *I_CPUInfo(void) -{ - static CPUInfoFlags WIN_CPUInfo; - SYSTEM_INFO SI; - p_IsProcessorFeaturePresent pfnCPUID = (p_IsProcessorFeaturePresent)(LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsProcessorFeaturePresent"); - - ZeroMemory(&WIN_CPUInfo,sizeof (WIN_CPUInfo)); - if (pfnCPUID) - { - WIN_CPUInfo.FPPE = pfnCPUID( 0); //PF_FLOATING_POINT_PRECISION_ERRATA - WIN_CPUInfo.FPE = pfnCPUID( 1); //PF_FLOATING_POINT_EMULATED - WIN_CPUInfo.cmpxchg = pfnCPUID( 2); //PF_COMPARE_EXCHANGE_DOUBLE - WIN_CPUInfo.MMX = pfnCPUID( 3); //PF_MMX_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.PPCMM64 = pfnCPUID( 4); //PF_PPC_MOVEMEM_64BIT_OK - WIN_CPUInfo.ALPHAbyte = pfnCPUID( 5); //PF_ALPHA_BYTE_INSTRUCTIONS - WIN_CPUInfo.SSE = pfnCPUID( 6); //PF_XMMI_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.AMD3DNow = pfnCPUID( 7); //PF_3DNOW_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.RDTSC = pfnCPUID( 8); //PF_RDTSC_INSTRUCTION_AVAILABLE - WIN_CPUInfo.PAE = pfnCPUID( 9); //PF_PAE_ENABLED - WIN_CPUInfo.SSE2 = pfnCPUID(10); //PF_XMMI64_INSTRUCTIONS_AVAILABLE - //WIN_CPUInfo.blank = pfnCPUID(11); //PF_SSE_DAZ_MODE_AVAILABLE - WIN_CPUInfo.DEP = pfnCPUID(12); //PF_NX_ENABLED - WIN_CPUInfo.SSE3 = pfnCPUID(13); //PF_SSE3_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.cmpxchg16b = pfnCPUID(14); //PF_COMPARE_EXCHANGE128 - WIN_CPUInfo.cmp8xchg16 = pfnCPUID(15); //PF_COMPARE64_EXCHANGE128 - WIN_CPUInfo.PFC = pfnCPUID(16); //PF_CHANNELS_ENABLED - } - GetSystemInfo(&SI); - WIN_CPUInfo.CPUs = SI.dwNumberOfProcessors; - WIN_CPUInfo.IA64 = (SI.dwProcessorType == 2200); // PROCESSOR_INTEL_IA64 - WIN_CPUInfo.AMD64 = (SI.dwProcessorType == 8664); // PROCESSOR_AMD_X8664 - return &WIN_CPUInfo; -} - -static void CPUAffinity_OnChange(void); -static consvar_t cv_cpuaffinity = CVAR_INIT ("cpuaffinity", "-1", CV_CALL, NULL, CPUAffinity_OnChange); - -typedef HANDLE (WINAPI *p_GetCurrentProcess) (VOID); -static p_GetCurrentProcess pfnGetCurrentProcess = NULL; -typedef BOOL (WINAPI *p_GetProcessAffinityMask) (HANDLE, PDWORD_PTR, PDWORD_PTR); -static p_GetProcessAffinityMask pfnGetProcessAffinityMask = NULL; -typedef BOOL (WINAPI *p_SetProcessAffinityMask) (HANDLE, DWORD_PTR); -static p_SetProcessAffinityMask pfnSetProcessAffinityMask = NULL; - -static inline VOID GetAffinityFuncs(VOID) -{ - HMODULE h = GetModuleHandleA("kernel32.dll"); - pfnGetCurrentProcess = (p_GetCurrentProcess)(LPVOID)GetProcAddress(h, "GetCurrentProcess"); - pfnGetProcessAffinityMask = (p_GetProcessAffinityMask)(LPVOID)GetProcAddress(h, "GetProcessAffinityMask"); - pfnSetProcessAffinityMask = (p_SetProcessAffinityMask)(LPVOID)GetProcAddress(h, "SetProcessAffinityMask"); -} - -static void CPUAffinity_OnChange(void) -{ - DWORD_PTR dwProcMask, dwSysMask; - HANDLE selfpid; - - if (!pfnGetCurrentProcess || !pfnGetProcessAffinityMask || !pfnSetProcessAffinityMask) - return; - else - selfpid = pfnGetCurrentProcess(); - - pfnGetProcessAffinityMask(selfpid, &dwProcMask, &dwSysMask); - - /* If resulting mask is zero, don't change anything and fall back to - * actual mask. - */ - if(dwSysMask & cv_cpuaffinity.value) - { - pfnSetProcessAffinityMask(selfpid, dwSysMask & cv_cpuaffinity.value); - CV_StealthSetValue(&cv_cpuaffinity, (int)(dwSysMask & cv_cpuaffinity.value)); - } - else - CV_StealthSetValue(&cv_cpuaffinity, (int)dwProcMask); -} - -void I_RegisterSysCommands(void) -{ - GetAffinityFuncs(); - CV_RegisterVar(&cv_cpuaffinity); -} -#endif diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c deleted file mode 100644 index 7a33e1931..000000000 --- a/src/win32/win_vid.c +++ /dev/null @@ -1,1113 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -//----------------------------------------------------------------------------- -/// \file -/// \brief win32 video driver for Doom Legacy - -#include "../doomdef.h" - -#ifdef _WINDOWS - -#include -#include - -#include "../d_clisrv.h" -#include "../i_system.h" -#include "../m_argv.h" -#include "../v_video.h" -#include "../st_stuff.h" -#include "../i_video.h" -#include "../z_zone.h" -#include "fabdxlib.h" -#include "../doomstat.h" -#include "win_main.h" -#include "../command.h" -#include "../screen.h" - -#ifdef HWRENDER -#include "win_dll.h" // loading the render DLL -#include "../hardware/hw_drv.h" // calling driver init & shutdown -#include "../hardware/hw_main.h" // calling HWR module init & shutdown -#endif - -// ------- -// Globals -// ------- - -// this is the CURRENT rendermode!! very important: used by w_wad, and much other code -rendermode_t rendermode = render_soft; -rendermode_t chosenrendermode = render_none; // set by command line arguments -static void OnTop_OnChange(void); -// synchronize page flipping with screen refresh -static CV_PossibleValue_t CV_NeverOnOff[] = {{-1, "Never"}, {0, "Off"}, {1, "On"}, {0, NULL}}; -consvar_t cv_vidwait = CVAR_INIT ("vid_wait", "On", CV_SAVE, CV_OnOff, OnTop_OnChange); -static consvar_t cv_stretch = CVAR_INIT ("stretch", "On", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL); -static consvar_t cv_ontop = CVAR_INIT ("ontop", "Never", 0, CV_NeverOnOff, NULL); - -boolean highcolor; - -static BOOL bDIBMode; // means we are using DIB instead of DirectDraw surfaces -static LPBITMAPINFO bmiMain = NULL; -static HDC hDCMain = NULL; - -// ----------------- -// Video modes stuff -// ----------------- - -#define MAX_EXTRA_MODES 36 -static vmode_t extra_modes[MAX_EXTRA_MODES] = {{NULL, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, 0}}; -static char names[MAX_EXTRA_MODES][10]; - -static INT32 numvidmodes; // total number of DirectDraw display modes -static vmode_t *pvidmodes; // start of videomodes list. -static vmode_t *pcurrentmode; // the current active videomode. -static BOOL bWinParm; -static INT32 WINAPI VID_SetWindowedDisplayMode(viddef_t *lvid, vmode_t *currentmode); - -// this holds description of the startup video mode, -// the resolution is 320x200, windowed on the desktop -static char winmodenames[NUMSPECIALMODES][11] = { - // W to make sure it's the windowed mode - "320x200W", - "640x400W", - "960x600W", - "1280x800W" -}; -vmode_t specialmodes[NUMSPECIALMODES] = -{ - { - NULL, - winmodenames[0], // hehe - 320, 200, //(200.0/320.0)*(320.0/240.0), - 320, 1, // rowbytes, bytes per pixel - 1, 2, // windowed (TRUE), numpages - NULL, - VID_SetWindowedDisplayMode, 0 - }, - { - NULL, - winmodenames[1], // haha - 640, 400, - 640, 1, // rowbytes, bytes per pixel - 1, 2, // windowed (TRUE), numpages - NULL, - VID_SetWindowedDisplayMode, 0 - }, - { - NULL, - winmodenames[2], // hihi? - 960, 600, - 960, 1, // rowbytes, bytes per pixel - 1, 2, // windowed (TRUE), numpages - NULL, - VID_SetWindowedDisplayMode, 0 - }, - { - NULL, - winmodenames[3], // hoho! - 1280, 800, - 1280, 1, // rowbytes, bytes per pixel - 1, 2, // windowed (TRUE), numpages - NULL, - VID_SetWindowedDisplayMode, 0 - } -}; - -// ------ -// Protos -// ------ -static void VID_Command_NumModes_f(void); -static void VID_Command_ModeInfo_f(void); -static void VID_Command_ModeList_f(void); -static void VID_Command_Mode_f(void); -static INT32 WINAPI VID_SetDirectDrawMode(viddef_t *lvid, vmode_t *currentmode); -static vmode_t *VID_GetModePtr(int modenum); -static VOID VID_Init(VOID); -static BOOL VID_FreeAndAllocVidbuffer(viddef_t *lvid); - -#if 0 - // Disable Composition in Vista DWM (Desktop Window Manager) ---------------- -static HMODULE DMdll = NULL; -typedef HRESULT (CALLBACK *P_DwmIsCompositionEnabled) (BOOL *pfEnabled); -static P_DwmIsCompositionEnabled pfnDwmIsCompositionEnabled = NULL; -typedef HRESULT (CALLBACK *P_DwmEnableComposition) (BOOL fEnable); -static P_DwmEnableComposition pfnDwmEnableComposition = NULL; -static BOOL AeroWasEnabled = FALSE; - -static inline VOID UnloadDM(VOID) -{ - pfnDwmEnableComposition = NULL; - pfnDwmIsCompositionEnabled = NULL; - if (DMdll) FreeLibrary(DMdll); - DMdll = NULL; -} - -static inline BOOL LoadDM(VOID) -{ - if (DMdll) - return TRUE; - - DMdll = LoadLibraryA("dwmapi.dll"); - if (DMdll) - I_OutputMsg("dmwapi.dll loaded, Vista's Desktop Window Manager API\n"); - else - return FALSE; - - pfnDwmIsCompositionEnabled = (P_DwmIsCompositionEnabled)GetProcAddress(DMdll, "DwmIsCompositionEnabled"); - if (pfnDwmIsCompositionEnabled) - I_OutputMsg("Composition Aero API found, DwmIsCompositionEnabled\n"); - - pfnDwmEnableComposition = (P_DwmEnableComposition)GetProcAddress(DMdll, "DwmEnableComposition"); - if (pfnDwmEnableComposition) - I_OutputMsg("Composition Aero API found, DwmEnableComposition\n"); - - return TRUE; -} - -static inline VOID DisableAero(VOID) -{ - BOOL pfnDwmEnableCompositiond = FALSE; - AeroWasEnabled = FALSE; - - if (!LoadDM()) - return; - - if (pfnDwmIsCompositionEnabled && SUCCEEDED(pfnDwmIsCompositionEnabled(&pfnDwmEnableCompositiond))) - I_OutputMsg("Got the result of DwmIsCompositionEnabled, %i\n", pfnDwmEnableCompositiond); - else - return; - - if ((AeroWasEnabled = pfnDwmEnableCompositiond)) - I_OutputMsg("Disable the Aero rendering\n"); - else - return; - - if (pfnDwmEnableComposition && SUCCEEDED(pfnDwmEnableComposition(FALSE))) - I_OutputMsg("Aero rendering disabled\n"); - else - I_OutputMsg("We failed to disable the Aero rendering\n"); -} - -static inline VOID ResetAero(VOID) -{ - if (pfnDwmEnableComposition && AeroWasEnabled) - { - if (SUCCEEDED(pfnDwmEnableComposition(AeroWasEnabled))) - I_OutputMsg("Aero rendering setting restored\n"); - else - I_OutputMsg("We failed to restore Aero rendering\n"); - } - UnloadDM(); -} -#endif - -// ----------------- -// I_StartupGraphics -// Initialize video mode, setup dynamic screen size variables, -// and allocate screens. -// ----------------- -void I_StartupGraphics(void) -{ - if (graphics_started) - return; - -#ifdef HWRENDER - else if (M_CheckParm("-opengl")) - rendermode = render_opengl; - else -#endif - rendermode = render_soft; - - if (dedicated) - rendermode = render_none; - else - VID_Init(); - - // register exit code for graphics - I_AddExitFunc(I_ShutdownGraphics); - if (!dedicated) graphics_started = true; -} - -void VID_StartupOpenGL(void){} - -// ------------------ -// I_ShutdownGraphics -// Close the screen, restore previous video mode. -// ------------------ -void I_ShutdownGraphics(void) -{ -#ifdef HWRENDER - const rendermode_t oldrendermode = rendermode; -#endif - -// This is BAD because it makes the I_Error box screw up! -// rendermode = render_none; - - if (!graphics_started) - return; - - CONS_Printf("I_ShutdownGraphics: "); - - //FreeConsole(); - - //ResetAero(); - - // release windowed startup stuff - if (hDCMain) - { - ReleaseDC(hWndMain, hDCMain); - hDCMain = NULL; - } - if (bmiMain) - { - GlobalFree(bmiMain); - bmiMain = NULL; - } - -#ifdef HWRENDER - if (oldrendermode != render_soft) - { - HWR_Shutdown(); // free stuff from the hardware renderer - HWD.pfnShutdown(); // close 3d card display - Shutdown3DDriver(); // free the driver DLL - } -#endif - - // free the last video mode screen buffers - if (vid.buffer) - { - GlobalFree(vid.buffer); - vid.buffer = NULL; - } - -#ifdef HWRENDER - if (rendermode == render_soft) -#endif - CloseDirectDraw(); - - graphics_started = false; -} - -// -------------- -// I_UpdateNoBlit -// -------------- -void I_UpdateNoBlit(void) -{ - // what is this? -} - -// I_SkipFrame -// -// Returns true if it thinks we can afford to skip this frame -// from PrBoom's src/SDL/i_video.c -static inline boolean I_SkipFrame(void) -{ - static boolean skip = false; - - if (render_soft != rendermode) - return false; - - skip = !skip; - switch (gamestate) - { - case GS_LEVEL: - if (!paused) - return false; - //case GS_TIMEATTACK: -- sorry optimisation but now we have a cool level platter and that being laggardly looks terrible -#ifndef NONET - /* FALLTHRU */ - case GS_WAITINGPLAYERS: -#endif - return skip; // Skip odd frames - default: - return false; - } -} - -static void OnTop_OnChange(void) -{ - const UINT uFlags = SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER; - RECT bounds; - int x = 0, y = 0, w = 0, h = 0; - - if (!hWndMain || bAppFullScreen || cv_ontop.value == -1) - return; - - GetWindowRect(hWndMain, &bounds); - AdjustWindowRectEx(&bounds, GetWindowLong(hWndMain, GWL_STYLE), 0, 0); - w = bounds.right - (x = bounds.left); h = bounds.bottom - (y = bounds.top); - - if (cv_ontop.value && !paused) - SetWindowPos(hWndMain, HWND_TOP , x, y, w, h, uFlags); - else - SetWindowPos(hWndMain, HWND_NOTOPMOST, x, y, w, h, uFlags); -} - -// -------------- -// I_FinishUpdate -// -------------- -void I_FinishUpdate(void) -{ - if (rendermode == render_none) - return; - - if (I_SkipFrame()) - return; - - if (marathonmode) - SCR_DisplayMarathonInfo(); - - // draw captions if enabled - if (cv_closedcaptioning.value) - SCR_ClosedCaptions(); - - // display a graph of ticrate - if (cv_ticrate.value) - SCR_DisplayTicRate(); - - if (cv_showping.value && netgame && consoleplayer != serverplayer) - SCR_DisplayLocalPing(); - - // - if (bDIBMode) - { - // paranoia - if (!hDCMain || !bmiMain || !vid.buffer) - return; - // main game loop, still in a window (-win parm) - SetDIBitsToDevice(hDCMain, 0, 0, vid.width, vid.height, 0, 0, 0, vid.height, vid.buffer, bmiMain, - DIB_RGB_COLORS); - } - else -#ifdef HWRENDER - if (rendermode != render_soft) - HWD.pfnFinishUpdate(cv_vidwait.value); - else -#endif - { - // DIRECT DRAW - // copy virtual screen to real screen - // can fail when not active (alt-tab) - if (LockScreen()) - { - /// \todo use directX blit here!!? a blit might use hardware with access - /// to main memory on recent hardware, and software blit of directX may be - /// optimized for p2 or mmx?? - if (ScreenHeight > vid.height) - { - UINT8 *ptr = (UINT8 *)ScreenPtr; - size_t half_excess = ScreenPitch*(ScreenHeight-vid.height)/2; - memset(ptr, 0x1F, half_excess); - ptr += half_excess; - VID_BlitLinearScreen(screens[0], ptr, vid.width*vid.bpp, vid.height, - vid.width*vid.bpp, ScreenPitch); - ptr += vid.height*ScreenPitch; - memset(ptr, 0x1F, half_excess); - } - else - VID_BlitLinearScreen(screens[0], (UINT8 *)ScreenPtr, vid.width*vid.bpp, vid.height, - vid.width*vid.bpp, ScreenPitch); - - UnlockScreen(); - - // swap screens - ScreenFlip(cv_vidwait.value); - } - } -} - -// --------------- -// I_UpdateNoVsync -// --------------- -void I_UpdateNoVsync(void) -{ - int real_vidwait = cv_vidwait.value; - cv_vidwait.value = 0; - I_FinishUpdate(); - cv_vidwait.value = real_vidwait; -} - -// -// This is meant to be called only by CONS_Printf() while game startup -// -void I_LoadingScreen(LPCSTR msg) -{ - RECT rect; - - // paranoia - if (!hDCMain || !bmiMain || !vid.buffer) - return; - - GetClientRect(vid.WndParent, &rect); - - SetDIBitsToDevice(hDCMain, 0, 0, vid.width, vid.height, 0, 0, 0, vid.height, vid.buffer, bmiMain, DIB_RGB_COLORS); - - if (msg) - { - if (rect.bottom - rect.top > 32) - rect.top = rect.bottom - 32; // put msg on bottom of window - SetBkMode(hDCMain, TRANSPARENT); - SetTextColor(hDCMain, RGB(0x00, 0x00, 0x00)); - DrawTextA(hDCMain, msg, -1, &rect, DT_WORDBREAK|DT_CENTER); - } -} - -// ------------ -// I_ReadScreen -// ------------ -void I_ReadScreen(UINT8 *scr) -{ - // DEBUGGING - if (rendermode != render_soft) - I_Error("I_ReadScreen: called while in non-software mode"); - VID_BlitLinearScreen(screens[0], scr, vid.width*vid.bpp, vid.height, vid.width*vid.bpp, - vid.rowbytes); -} - -// ------------ -// I_SetPalette -// ------------ -void I_SetPalette(RGBA_t *palette) -{ - int i; - - if (bDIBMode) - { - // set palette in RGBQUAD format, NOT THE SAME ORDER as PALETTEENTRY, grmpf! - RGBQUAD *pColors; - pColors = (RGBQUAD *)((LPBYTE)bmiMain + bmiMain->bmiHeader.biSize); - ZeroMemory(pColors, sizeof (RGBQUAD)*256); - for (i = 0; i < 256; i++, pColors++, palette++) - { - pColors->rgbRed = palette->s.red; - pColors->rgbGreen = palette->s.green; - pColors->rgbBlue = palette->s.blue; - } - } - else -#ifdef HWRENDER - if (rendermode == render_soft) -#endif - { - PALETTEENTRY mainpal[256]; - - // this clears the 'flag' for each color in palette - ZeroMemory(mainpal, sizeof mainpal); - - // set palette in PALETTEENTRY format - for (i = 0; i < 256; i++, palette++) - { - mainpal[i].peRed = palette->s.red; - mainpal[i].peGreen = palette->s.green; - mainpal[i].peBlue = palette->s.blue; - } - SetDDPalette(mainpal); // set DirectDraw palette - } -} - -// -// return number of video modes in pvidmodes list -// MODES ARE ZERO INDEXED. DO NOT USE (n > nummodes). USE >= INSTEAD. -// -INT32 VID_NumModes(void) -{ - return numvidmodes; -} - -// return a video mode number from the dimensions -// returns any available video mode if the mode was not found -INT32 VID_GetModeForSize(INT32 w, INT32 h) -{ - vmode_t *pv = pvidmodes; - int modenum = 0; - - // Fullscreen resolutions exist - if (numvidmodes > NUMSPECIALMODES) - { - // skip the special modes so that it finds only fullscreen modes - for (; pv && modenum < NUMSPECIALMODES; pv = pv->pnext, ++modenum); - for (; pv; pv = pv->pnext, ++modenum) - if (pv->width == (unsigned)w && pv->height == (unsigned)h) - return modenum; - - // Try default video mode first - if (w != cv_scr_width.value || h != cv_scr_height.value) - return VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value); - - // didn't find, return first fullscreen mode - return NUMSPECIALMODES; - } - - // rely only on special (windowed) modes - for (; pv && modenum < NUMSPECIALMODES; pv = pv->pnext, ++modenum) - if (pv->width == (unsigned)w && pv->height == (unsigned)h) - return modenum; - - // Try default video mode first - if (w != cv_scr_width.value || h != cv_scr_height.value) - return VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value); - - // didn't find, return first windowed mode - return 0; -} - -// -// Enumerate DirectDraw modes available -// -static int nummodes = 0; -static BOOL GetExtraModesCallback(int width, int height, int bpp) -{ -#ifdef _DEBUG - CONS_Printf("mode %d x %d x %d bpp\n", width, height, bpp); -#endif - - // skip all unwanted modes - if (highcolor && bpp != 15) - goto skip; - if (!highcolor && bpp != 8) - goto skip; - - if (bpp > 16 || width > MAXVIDWIDTH || height > MAXVIDHEIGHT) - goto skip; - - // check if we have space for this mode - if (nummodes >= MAX_EXTRA_MODES) - { -#ifdef _DEBUG - CONS_Printf("mode skipped (too many)\n"); -#endif - return FALSE; - } - - // store mode info - extra_modes[nummodes].pnext = &extra_modes[nummodes+1]; - memset(names[nummodes], 0, 10); - snprintf(names[nummodes], 9, "%dx%d", width, height); - - extra_modes[nummodes].name = names[nummodes]; - extra_modes[nummodes].width = width; - extra_modes[nummodes].height = height; - - // exactly, the current FinishUdpate() gets the rowbytes itself after locking the video buffer - // so for now we put anything here - extra_modes[nummodes].rowbytes = width; - extra_modes[nummodes].windowed = false; - extra_modes[nummodes].misc = 0; // unused - extra_modes[nummodes].pextradata = NULL; - extra_modes[nummodes].setmode = VID_SetDirectDrawMode; - - extra_modes[nummodes].numpages = 3; // triple-buffer (but this value is unused) - - extra_modes[nummodes].bytesperpixel = (bpp+1)>>3; - - nummodes++; -skip: - return TRUE; -} - -// -// Collect info about DirectDraw display modes we use -// -static inline VOID VID_GetExtraModes(VOID) -{ - nummodes = 0; - EnumDirectDrawDisplayModes(GetExtraModesCallback); - - // add the extra modes (not 320x200) at the start of the mode list (if there are any) - if (nummodes) - { - extra_modes[nummodes-1].pnext = NULL; - pvidmodes = &extra_modes[0]; - numvidmodes += nummodes; - } -} - -// --------------- -// WindowMode_Init -// Add windowed modes to the start of the list, -// mode 0 is used for windowed console startup (works on all computers with no DirectX) -// --------------- -static VOID WindowMode_Init(VOID) -{ - int modenum; - - for (modenum = 0; modenum < NUMSPECIALMODES - 1; modenum++) - specialmodes[modenum].pnext = &specialmodes[modenum + 1]; - specialmodes[NUMSPECIALMODES-1].pnext = pvidmodes; - - pvidmodes = specialmodes; - numvidmodes += NUMSPECIALMODES; -} - -// ************************************************************************************* -// VID_Init -// Initialize Video modes subsystem -// ************************************************************************************* -static VOID VID_Init(VOID) -{ -#ifdef _DEBUG - vmode_t *pv; - int iMode; -#endif - - // if '-win' is specified on the command line, do not add DirectDraw modes - bWinParm = M_CheckParm("-win"); - - COM_AddCommand("vid_nummodes", VID_Command_NumModes_f); - COM_AddCommand("vid_modeinfo", VID_Command_ModeInfo_f); - COM_AddCommand("vid_modelist", VID_Command_ModeList_f); - COM_AddCommand("vid_mode", VID_Command_Mode_f); - - CV_RegisterVar(&cv_vidwait); - CV_RegisterVar(&cv_stretch); - CV_RegisterVar(&cv_ontop); - - // setup the videmodes list, - // note that mode 0 must always be VGA mode 0x13 - pvidmodes = pcurrentmode = NULL; - numvidmodes = 0; - - //DisableAero(); - - // store the main window handle in viddef struct - SetWindowPos(hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_NOMOVE); - vid.WndParent = hWndMain; - vid.buffer = NULL; - - // we startup in windowed mode using DIB bitmap - // we will use DirectDraw when switching fullScreen and entering main game loop - bDIBMode = TRUE; - bAppFullScreen = FALSE; - -#ifdef HWRENDER - // initialize the appropriate display device - if (rendermode != render_soft) - { - const char *drvname = NULL; - - switch (rendermode) - { - case render_opengl: - drvname = "r_opengl.dll"; - break; - default: - I_Error("Unknown hardware render mode"); - } - - // load the DLL - if (drvname && Init3DDriver(drvname)) - { - int hwdversion = HWD.pfnGetRenderVersion(); - if (hwdversion != VERSION) - CONS_Alert(CONS_WARNING, M_GetText("This r_opengl version is not supported, use it at your own risk!\n")); - - // perform initialisations - HWD.pfnInit(I_Error); - // get available display modes for the device - HWD.pfnGetModeList(&pvidmodes, &numvidmodes); - } - else - { - switch (rendermode) - { - case render_opengl: - I_Error("Error initializing OpenGL"); - default: - break; - } - rendermode = render_soft; - } - } - - if (rendermode == render_soft) -#endif - if (!bWinParm) - { - if (!CreateDirectDrawInstance()) - bWinParm = TRUE; - else // get available display modes for the device - VID_GetExtraModes(); - } - - // the game boots in 320x200 standard VGA, but - // we need a highcolor mode to run the game in highcolor - if (highcolor && !numvidmodes) - I_Error("Cannot run in highcolor - No 15bit highcolor DirectX video mode found."); - - // add windowed mode at the start of the list, very important! - WindowMode_Init(); - - if (!numvidmodes) - I_Error("No display modes available."); - -#ifdef _DEBUG // DEBUG - for (iMode = 0, pv = pvidmodes; pv; pv = pv->pnext, iMode++) - I_OutputMsg("#%02d: %dx%dx%dbpp (desc: '%s')\n", iMode, pv->width, pv->height, pv->bytesperpixel, pv->name); -#endif - - // set the startup screen in a window - VID_SetMode(0); -} - -// -------------------------- -// VID_SetWindowedDisplayMode -// Display the startup 320x200 console screen into a window on the desktop, -// switching to fullscreen display only when we will enter the main game loop. -// - we can display error message boxes for startup errors -// - we can set the last used resolution only once, when entering the main game loop -// -------------------------- -static INT32 WINAPI VID_SetWindowedDisplayMode(viddef_t *lvid, vmode_t *currentmode) -{ - RECT bounds; - int x = 0, y = 0, w = 0, h = 0; - - UNREFERENCED_PARAMETER(currentmode); - - I_OutputMsg("VID_SetWindowedDisplayMode()\n"); - - - lvid->u.numpages = 1; // not used - lvid->direct = NULL; // DOS remains - lvid->buffer = NULL; - - // allocate screens - if (!VID_FreeAndAllocVidbuffer(lvid)) - return -1; - - // lvid->buffer should be NULL here! - - bmiMain = GlobalAlloc(GPTR, sizeof (BITMAPINFO) + (sizeof (RGBQUAD)*256)); - if (!bmiMain) - I_Error("VID_SWDM(): No mem"); - - // setup a BITMAPINFO to allow copying our video buffer to the desktop, - // with color conversion as needed - bmiMain->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); - bmiMain->bmiHeader.biWidth = lvid->width; - bmiMain->bmiHeader.biHeight= -(lvid->height); - bmiMain->bmiHeader.biPlanes = 1; - bmiMain->bmiHeader.biBitCount = 8; - bmiMain->bmiHeader.biCompression = BI_RGB; - - // center window on the desktop - bounds.left = 0; - bounds.right = lvid->width; - bounds.top = 0; - bounds.bottom = lvid->height; - AdjustWindowRectEx(&bounds, GetWindowLong(hWndMain, GWL_STYLE), FALSE, GetWindowLong(hWndMain, GWL_EXSTYLE)); - - w = bounds.right-bounds.left; - h = bounds.bottom-bounds.top; - x = (GetSystemMetrics(SM_CXSCREEN)-w)/2; - y = (GetSystemMetrics(SM_CYSCREEN)-h)/2; - - if (devparm) - MoveWindow(hWndMain, x<<1, y<<1, w, h, TRUE); - else - MoveWindow(hWndMain, x, y, w, h, TRUE); - - SetFocus(hWndMain); - ShowWindow(hWndMain, SW_SHOW); - - hDCMain = GetDC(hWndMain); - if (!hDCMain) - I_Error("VID_SWDM(): GetDC FAILED"); - - return 1; -} - -// ======================================================================== -// Returns a vmode_t from the video modes list, given a video mode number. -// ======================================================================== -vmode_t *VID_GetModePtr(int modenum) -{ - vmode_t *pv; - - pv = pvidmodes; - if (!pv) - I_Error("VID_error: No video mode found\n"); - - while (modenum--) - { - pv = pv->pnext; - if (!pv) - I_Error("VID_error: Mode not available\n"); - } - return pv; -} - -// -// return the name of a video mode -// -const char *VID_GetModeName(INT32 modenum) -{ - return (VID_GetModePtr(modenum))->name; -} - -// ======================================================================== -// Sets a video mode -// ======================================================================== -INT32 VID_SetMode(INT32 modenum) -{ - int vstat; - vmode_t *pnewmode; - - if (dedicated) - return 0; - - I_OutputMsg("VID_SetMode(%d)\n", modenum); - - // if mode 0 (windowed) we must not be fullscreen already, - // if other mode, check it is not mode 0 and existing - if (modenum >= numvidmodes) - { - if (!pcurrentmode) - modenum = 0; // revert to the default base vid mode - else - I_Error("Unknown video mode: %d\n", modenum); - } - else if (bAppFullScreen && modenum < NUMSPECIALMODES) - I_Error("Tried to switch from fullscreen back to windowed mode %d\n", modenum); - - pnewmode = VID_GetModePtr(modenum); - - // dont switch to the same display mode - if (pnewmode == pcurrentmode) - return 1; - - // initialize the new mode - pcurrentmode = pnewmode; - - // initialize vidbuffer size for setmode - vid.width = pcurrentmode->width; - vid.height = pcurrentmode->height; - vid.rowbytes = pcurrentmode->rowbytes; - vid.bpp = pcurrentmode->bytesperpixel; - if (modenum) // if not 320x200 windowed mode, it's actually a hack - { - if (rendermode == render_opengl) - { - // don't accept depth < 16 for OpenGL mode (too much ugly) - if (cv_scr_depth.value < 16) - CV_SetValue(&cv_scr_depth, 16); - vid.bpp = cv_scr_depth.value/8; - vid.u.windowed = (bWinParm || !cv_fullscreen.value); - pcurrentmode->bytesperpixel = vid.bpp; - pcurrentmode->windowed = vid.u.windowed; - } - } - - vstat = (*pcurrentmode->setmode)(&vid, pcurrentmode); - - if (vstat == -1) - I_Error("Not enough mem for VID_SetMode\n"); - else if (vstat == -2) - I_Error("Couldn't set video mode because it failed the test\n"); - else if (vstat == -3) - I_Error("Couldn't set video mode because it failed the change?\n"); - else if (!vstat) - I_Error("Couldn't set video mode %d (%dx%d %d bits)\n", modenum, vid.width, vid.height, (vid.bpp*8));// hardware could not setup mode - else - CONS_Printf(M_GetText("Mode changed to %d (%s)\n"), modenum, pcurrentmode->name); - - vid.modenum = modenum; - - // tell game engine to recalc all tables and realloc buffers based on new values - vid.recalc = 1; - - if (modenum < NUMSPECIALMODES) - { - // we are in startup windowed mode - bAppFullScreen = FALSE; - bDIBMode = TRUE; - } - else - { - // we switch to fullscreen - bAppFullScreen = TRUE; - bDIBMode = FALSE; -#ifdef HWRENDER - if (rendermode != render_soft) - { - // purge all patch graphics stored in software format - //Z_FreeTags (PU_PURGELEVEL, PU_PURGELEVEL+100); - HWR_Startup(); - } -#endif - } - - I_RestartSysMouse(); - return 1; -} - -boolean VID_CheckRenderer(void) -{ - return false; -} - -void VID_CheckGLLoaded(rendermode_t oldrender) -{ - (void)oldrender; -} - -// ======================================================================== -// Free the video buffer of the last video mode, -// allocate a new buffer for the video mode to set. -// ======================================================================== -static BOOL VID_FreeAndAllocVidbuffer(viddef_t *lvid) -{ - const DWORD vidbuffersize = (lvid->width * lvid->height * lvid->bpp * NUMSCREENS); - - // free allocated buffer for previous video mode - if (lvid->buffer) - GlobalFree(lvid->buffer); - - // allocate & clear the new screen buffer - lvid->buffer = GlobalAlloc(GPTR, vidbuffersize); - if (!lvid->buffer) - return FALSE; - - ZeroMemory(lvid->buffer, vidbuffersize); - I_OutputMsg("VID_FreeAndAllocVidbuffer done, vidbuffersize: %x\n",(UINT32)vidbuffersize); - - return TRUE; -} - -// ======================================================================== -// Set video mode routine for DirectDraw display modes -// Out: 1 ok, -// 0 hardware could not set mode, -// -1 no mem -// ======================================================================== -static INT32 WINAPI VID_SetDirectDrawMode(viddef_t *lvid, vmode_t *currentmode) -{ - UNREFERENCED_PARAMETER(currentmode); - - I_OutputMsg("VID_SetDirectDrawMode...\n"); - - - // DD modes do double-buffer page flipping, but the game engine doesn't need this.. - lvid->u.numpages = 2; - - // release ddraw surfaces etc.. - ReleaseChtuff(); - - // clean up any old vid buffer lying around, alloc new if needed - if (!VID_FreeAndAllocVidbuffer(lvid)) - return -1; // no mem - - // should clear video mem here - - // note use lvid->bpp instead of 8...will this be needed? will we support other than 256color - // in software ? - if (!InitDirectDrawe(hWndMain, lvid->width, lvid->height, 8, TRUE)) // TRUE currently always full screen - return 0; // could not set mode - - // this is NOT used with DirectDraw modes, game engine should never use this directly - // but rather render to memory bitmap buffer - lvid->direct = NULL; - - if (!cv_stretch.value && fabsf((float)vid.width/vid.height - ((float)BASEVIDWIDTH/BASEVIDHEIGHT)) > 1.0E-36f) - vid.height = (int)(vid.width * ((float)BASEVIDHEIGHT/BASEVIDWIDTH));// Adjust the height to match - - return 1; -} - -// ======================================================================== -// VIDEO MODE CONSOLE COMMANDS -// ======================================================================== - -// vid_nummodes -// -static void VID_Command_NumModes_f(void) -{ - CONS_Printf(M_GetText("%d video mode(s) available(s)\n"), VID_NumModes()); -} - -// vid_modeinfo -// -static void VID_Command_ModeInfo_f(void) -{ - vmode_t *pv; - int modenum; - - if (COM_Argc() != 2) - modenum = vid.modenum; // describe the current mode - else - modenum = atoi(COM_Argv(1)); // the given mode number - - if (modenum >= VID_NumModes() - || (!bWinParm && modenum < NUMSPECIALMODES)) // don't accept the windowed modes - { - CONS_Printf(M_GetText("Video mode not present\n")); - return; - } - - pv = VID_GetModePtr(modenum); - - CONS_Printf("\x82" "%s\n", VID_GetModeName(modenum)); - CONS_Printf(M_GetText("width: %d\nheight: %d\n"), - pv->width, pv->height); - if (rendermode == render_soft) - CONS_Printf(M_GetText("bytes per scanline: %d\nbytes per pixel: %d\nnumpages: %d\n"), - pv->rowbytes, pv->bytesperpixel, pv->numpages); -} - -// vid_modelist -// -static void VID_Command_ModeList_f(void) -{ - int i, numodes; - const char *pinfo; - vmode_t *pv; - - numodes = VID_NumModes(); - - // hide windowed modes unless using them - i = (!bWinParm) ? NUMSPECIALMODES : 0; - - for (; i < numodes; i++) - { - pv = VID_GetModePtr(i); - pinfo = VID_GetModeName(i); - - if (pv->bytesperpixel == 1) - CONS_Printf("%d: %s\n", i, pinfo); - else - CONS_Printf("%d: %s (hicolor)\n", i, pinfo); - } -} - -// vid_mode -// -static void VID_Command_Mode_f(void) -{ - int modenum; - - if (COM_Argc() != 2) - { - CONS_Printf(M_GetText("vid_mode : set video mode, current video mode %i\n"), vid.modenum); - return; - } - - modenum = atoi(COM_Argv(1)); - - if (modenum >= VID_NumModes() - || (!bWinParm && modenum < NUMSPECIALMODES)) // don't accept the windowed modes - CONS_Printf(M_GetText("Video mode not present\n")); - else - setmodeneeded = modenum + 1; // request vid mode change -} -#endif diff --git a/src/y_inter.c b/src/y_inter.c index 061cbb5e1..34e58494f 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2004-2020 by Sonic Team Junior. +// Copyright (C) 2004-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -212,7 +212,89 @@ static void Y_IntermissionTokenDrawer(void) calc = (lowy - y)*2; if (calc > 0) - V_DrawCroppedPatch(32<width, calc); + V_DrawCroppedPatch(32<width<interscreen[0] != '#') + interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); + else // no interscreen? use default background + bgpatch = W_CachePatchName("INTERSCR", PU_PATCH); + break; + } + case int_spec: + { + for (i = 0; i < 2; ++i) + data.spec.bonuspatches[i] = W_CachePatchName(data.spec.bonuses[i].patch, PU_PATCH); + + data.spec.pscore = W_CachePatchName("YB_SCORE", PU_PATCH); + data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_PATCH); + + // grab an interscreen if appropriate + if (mapheaderinfo[gamemap-1]->interscreen[0] != '#') + interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); + else // no interscreen? use default background + bgtile = W_CachePatchName("SPECTILE", PU_PATCH); + break; + } + case int_ctf: + case int_teammatch: + { + if (!rflagico) //prevent a crash if we haven't cached our team graphics yet + { + rflagico = W_CachePatchName("RFLAGICO", PU_HUDGFX); + bflagico = W_CachePatchName("BFLAGICO", PU_HUDGFX); + rmatcico = W_CachePatchName("RMATCICO", PU_HUDGFX); + bmatcico = W_CachePatchName("BMATCICO", PU_HUDGFX); + } + + data.match.redflag = (intertype == int_ctf) ? rflagico : rmatcico; + data.match.blueflag = (intertype == int_ctf) ? bflagico : bmatcico; + } + /* FALLTHRU */ + case int_match: + case int_race: + case int_comp: + { + if (intertype == int_match || intertype == int_race) + { + // get RESULT header + data.match.result = W_CachePatchName("RESULT", PU_PATCH); + } + + // get background tile + bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); + break; + } + case int_none: + default: + break; + } } // @@ -347,7 +429,7 @@ void Y_IntermissionDrawer(void) else if (bgtile) V_DrawPatchFill(bgtile); - LUAh_IntermissionHUD(); + LUA_HUDHOOK(intermission); if (!LUA_HudEnabled(hud_intermissiontally)) goto skiptallydrawer; @@ -388,14 +470,17 @@ void Y_IntermissionDrawer(void) } } - // draw the "got through act" lines and act number - V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1); + if (LUA_HudEnabled(hud_intermissiontitletext)) { - INT32 h = V_LevelNameHeight(data.coop.passed2); - V_DrawLevelTitle(data.coop.passedx2, 49+h+2, 0, data.coop.passed2); + // draw the "got through act" lines and act number + V_DrawLevelTitle(data.coop.passedx1, 49, 0, data.coop.passed1); + { + INT32 h = V_LevelNameHeight(data.coop.passed2); + V_DrawLevelTitle(data.coop.passedx2, 49+h+2, 0, data.coop.passed2); - if (data.coop.actnum) - V_DrawLevelActNum(244, 42+h, 0, data.coop.actnum); + if (data.coop.actnum) + V_DrawLevelActNum(244, 42+h, 0, data.coop.actnum); + } } bonusy = 150; @@ -479,37 +564,44 @@ void Y_IntermissionDrawer(void) if (drawsection == 1) { - const char *ringtext = "\x82" "50 rings, no shield"; - const char *tut1text = "\x82" "press " "\x80" "spin"; - const char *tut2text = "\x82" "mid-" "\x80" "jump"; - ttheight = 8; - V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); - ttheight += V_LevelNameHeight(data.spec.passed3) + 2; - V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3); - ttheight += V_LevelNameHeight(data.spec.passed4) + 2; - V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4); + if (LUA_HudEnabled(hud_intermissiontitletext)) + { + const char *ringtext = "\x82" "50 rings, no shield"; + const char *tut1text = "\x82" "press " "\x80" "spin"; + const char *tut2text = "\x82" "mid-" "\x80" "jump"; + ttheight = 8; + V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); + ttheight += V_LevelNameHeight(data.spec.passed3) + 2; + V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3); + ttheight += V_LevelNameHeight(data.spec.passed4) + 2; + V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4); - ttheight = 108; - V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset4 - (V_LevelNameWidth(ringtext)/2), ttheight, 0, ringtext); - ttheight += V_LevelNameHeight(tut1text) + 2; - V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text); - ttheight += V_LevelNameHeight(tut2text) + 2; - V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset6 - (V_LevelNameWidth(tut2text)/2), ttheight, 0, tut2text); + ttheight = 108; + V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset4 - (V_LevelNameWidth(ringtext)/2), ttheight, 0, ringtext); + ttheight += V_LevelNameHeight(tut1text) + 2; + V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset5 - (V_LevelNameWidth(tut1text)/2), ttheight, 0, tut1text); + ttheight += V_LevelNameHeight(tut2text) + 2; + V_DrawLevelTitle(BASEVIDWIDTH/2 + xoffset6 - (V_LevelNameWidth(tut2text)/2), ttheight, 0, tut2text); + } } else { INT32 yoffset = 0; - if (data.spec.passed1[0] != '\0') + + if (LUA_HudEnabled(hud_intermissiontitletext)) { - ttheight = 24; - V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); - ttheight += V_LevelNameHeight(data.spec.passed2) + 2; - V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2); - } - else - { - ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2; - V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); + if (data.spec.passed1[0] != '\0') + { + ttheight = 24; + V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1); + ttheight += V_LevelNameHeight(data.spec.passed2) + 2; + V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2); + } + else + { + ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2; + V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2); + } } V_DrawScaledPatch(152 + xoffset3, 108, 0, data.spec.bonuspatches[0]); @@ -555,6 +647,7 @@ void Y_IntermissionDrawer(void) // draw the emeralds //if (intertic & 1) + if (LUA_HudEnabled(hud_intermissionemeralds)) { boolean drawthistic = !(ALL7EMERALDS(emeralds) && (intertic & 1)); INT32 emeraldx = 152 - 3*28; @@ -927,7 +1020,8 @@ void Y_Ticker(void) if (paused || P_AutoPause()) return; - LUAh_IntermissionThinker(); + LUA_HookBool(intertype == int_spec && stagefailed, + HOOK(IntermissionThinker)); intertic++; @@ -1181,10 +1275,9 @@ void Y_DetermineIntermissionType(void) // // Called by G_DoCompleted. Sets up data for intermission drawer/ticker. // +// void Y_StartIntermission(void) { - INT32 i; - intertic = -1; #ifdef PARANOIA @@ -1228,20 +1321,12 @@ void Y_StartIntermission(void) // setup time data data.coop.tics = players[consoleplayer].realtime; - for (i = 0; i < 4; ++i) - data.coop.bonuspatches[i] = W_CachePatchName(data.coop.bonuses[i].patch, PU_PATCH); - data.coop.ptotal = W_CachePatchName("YB_TOTAL", PU_PATCH); - // get act number data.coop.actnum = mapheaderinfo[gamemap-1]->actnum; - // get background patches - bgpatch = W_CachePatchName("INTERSCR", PU_PATCH); - // grab an interscreen if appropriate if (mapheaderinfo[gamemap-1]->interscreen[0] != '#') { - interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); useinterpic = true; usebuffer = false; } @@ -1256,24 +1341,40 @@ void Y_StartIntermission(void) usetile = false; // set up the "got through act" message according to skin name - // too long so just show "YOU GOT THROUGH THE ACT" - if (strlen(skins[players[consoleplayer].skin].realname) > 13) + if (stagefailed) { - strcpy(data.coop.passed1, "you got"); - strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act"); + strcpy(data.coop.passed1, mapheaderinfo[gamemap-1]->lvlttl); + + if (mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) + { + data.spec.passed2[0] = '\0'; + } + else + { + strcpy(data.coop.passed2, "Zone"); + } } - // long enough that "X GOT" won't fit so use "X PASSED THE ACT" - else if (strlen(skins[players[consoleplayer].skin].realname) > 8) - { - strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname); - strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act"); - } - // length is okay for normal use else { - snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got", - skins[players[consoleplayer].skin].realname); - strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act"); + // too long so just show "YOU GOT THROUGH THE ACT" + if (strlen(skins[players[consoleplayer].skin].realname) > 13) + { + strcpy(data.coop.passed1, "you got"); + strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act"); + } + // long enough that "X GOT" won't fit so use "X PASSED THE ACT" + else if (strlen(skins[players[consoleplayer].skin].realname) > 8) + { + strcpy(data.coop.passed1, skins[players[consoleplayer].skin].realname); + strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "passed act" : "passed the act"); + } + // length is okay for normal use + else + { + snprintf(data.coop.passed1, sizeof data.coop.passed1, "%s got", + skins[players[consoleplayer].skin].realname); + strcpy(data.coop.passed2, (mapheaderinfo[gamemap-1]->actnum) ? "through act" : "through the act"); + } } // set X positions @@ -1290,6 +1391,13 @@ void Y_StartIntermission(void) // The above value is not precalculated because it needs only be computed once // at the start of intermission, and precalculating it would preclude mods // changing the font to one of a slightly different width. + + if ((stagefailed) && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE)) + { + // Bit of a hack, offset so that the "Zone" text is right aligned like title cards. + data.coop.passedx2 = (data.coop.passedx1 + V_LevelNameWidth(data.coop.passed1)) - V_LevelNameWidth(data.coop.passed2); + } + break; } @@ -1298,21 +1406,9 @@ void Y_StartIntermission(void) // give out ring bonuses Y_AwardSpecialStageBonus(); - for (i = 0; i < 2; ++i) - data.spec.bonuspatches[i] = W_CachePatchName(data.spec.bonuses[i].patch, PU_PATCH); - - data.spec.pscore = W_CachePatchName("YB_SCORE", PU_PATCH); - data.spec.pcontinues = W_CachePatchName("YB_CONTI", PU_PATCH); - - // get background tile - bgtile = W_CachePatchName("SPECTILE", PU_PATCH); - // grab an interscreen if appropriate if (mapheaderinfo[gamemap-1]->interscreen[0] != '#') - { - interpic = W_CachePatchName(mapheaderinfo[gamemap-1]->interscreen, PU_PATCH); useinterpic = true; - } else useinterpic = false; @@ -1405,11 +1501,6 @@ void Y_StartIntermission(void) data.match.levelstring[sizeof data.match.levelstring - 1] = '\0'; - // get RESULT header - data.match.result = - W_CachePatchName("RESULT", PU_PATCH); - - bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1434,10 +1525,6 @@ void Y_StartIntermission(void) data.match.levelstring[sizeof data.match.levelstring - 1] = '\0'; - // get RESULT header - data.match.result = W_CachePatchName("RESULT", PU_PATCH); - - bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1463,18 +1550,6 @@ void Y_StartIntermission(void) data.match.levelstring[sizeof data.match.levelstring - 1] = '\0'; - if (intertype == int_ctf) - { - data.match.redflag = rflagico; - data.match.blueflag = bflagico; - } - else // team match - { - data.match.redflag = rmatcico; - data.match.blueflag = bmatcico; - } - - bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1499,8 +1574,6 @@ void Y_StartIntermission(void) data.competition.levelstring[sizeof data.competition.levelstring - 1] = '\0'; - // get background tile - bgtile = W_CachePatchName("SRB2BACK", PU_PATCH); usetile = true; useinterpic = false; break; @@ -1733,7 +1806,6 @@ static void Y_SetNullBonus(player_t *player, y_bonus_t *bstruct) { (void)player; memset(bstruct, 0, sizeof(y_bonus_t)); - strncpy(bstruct->patch, "MISSING", sizeof(bstruct->patch)); } // @@ -1746,21 +1818,30 @@ static void Y_SetTimeBonus(player_t *player, y_bonus_t *bstruct) strncpy(bstruct->patch, "YB_TIME", sizeof(bstruct->patch)); bstruct->display = true; - // calculate time bonus - secs = player->realtime / TICRATE; - if (secs < 30) /* :30 */ bonus = 50000; - else if (secs < 60) /* 1:00 */ bonus = 10000; - else if (secs < 90) /* 1:30 */ bonus = 5000; - else if (secs < 120) /* 2:00 */ bonus = 4000; - else if (secs < 180) /* 3:00 */ bonus = 3000; - else if (secs < 240) /* 4:00 */ bonus = 2000; - else if (secs < 300) /* 5:00 */ bonus = 1000; - else if (secs < 360) /* 6:00 */ bonus = 500; - else if (secs < 420) /* 7:00 */ bonus = 400; - else if (secs < 480) /* 8:00 */ bonus = 300; - else if (secs < 540) /* 9:00 */ bonus = 200; - else if (secs < 600) /* 10:00 */ bonus = 100; - else /* TIME TAKEN: TOO LONG */ bonus = 0; + if (stagefailed == true) + { + // Time Bonus would be very easy to cheese by failing immediately. + bonus = 0; + } + else + { + // calculate time bonus + secs = player->realtime / TICRATE; + if (secs < 30) /* :30 */ bonus = 50000; + else if (secs < 60) /* 1:00 */ bonus = 10000; + else if (secs < 90) /* 1:30 */ bonus = 5000; + else if (secs < 120) /* 2:00 */ bonus = 4000; + else if (secs < 180) /* 3:00 */ bonus = 3000; + else if (secs < 240) /* 4:00 */ bonus = 2000; + else if (secs < 300) /* 5:00 */ bonus = 1000; + else if (secs < 360) /* 6:00 */ bonus = 500; + else if (secs < 420) /* 7:00 */ bonus = 400; + else if (secs < 480) /* 8:00 */ bonus = 300; + else if (secs < 540) /* 9:00 */ bonus = 200; + else if (secs < 600) /* 10:00 */ bonus = 100; + else /* TIME TAKEN: TOO LONG */ bonus = 0; + } + bstruct->points = bonus; } @@ -1813,12 +1894,21 @@ static void Y_SetGuardBonus(player_t *player, y_bonus_t *bstruct) strncpy(bstruct->patch, "YB_GUARD", sizeof(bstruct->patch)); bstruct->display = true; - if (player->timeshit == 0) bonus = 10000; - else if (player->timeshit == 1) bonus = 5000; - else if (player->timeshit == 2) bonus = 1000; - else if (player->timeshit == 3) bonus = 500; - else if (player->timeshit == 4) bonus = 100; - else bonus = 0; + if (stagefailed == true) + { + // "No-hit" runs would be very easy to cheese by failing immediately. + bonus = 0; + } + else + { + if (player->timeshit == 0) bonus = 10000; + else if (player->timeshit == 1) bonus = 5000; + else if (player->timeshit == 2) bonus = 1000; + else if (player->timeshit == 3) bonus = 500; + else if (player->timeshit == 4) bonus = 100; + else bonus = 0; + } + bstruct->points = bonus; } @@ -1933,7 +2023,7 @@ static void Y_AwardCoopBonuses(void) for (i = 0; i < MAXPLAYERS; ++i) { - if (!playeringame[i] || players[i].lives < 1) // not active or game over + if (!playeringame[i] || players[i].lives < 1 || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN) // not active, game over or tails bot bonusnum = 0; // all null else bonusnum = mapheaderinfo[prevmap]->bonustype + 1; // -1 is none @@ -1983,7 +2073,7 @@ static void Y_AwardSpecialStageBonus(void) { oldscore = players[i].score; - if (!playeringame[i] || players[i].lives < 1) // not active or game over + if (!playeringame[i] || players[i].lives < 1 || players[i].bot == BOT_2PAI || players[i].bot == BOT_2PHUMAN) // not active, game over or tails bot { Y_SetNullBonus(&players[i], &localbonuses[0]); Y_SetNullBonus(&players[i], &localbonuses[1]); @@ -2031,7 +2121,8 @@ static void Y_AwardSpecialStageBonus(void) // void Y_EndIntermission(void) { - Y_UnloadData(); + if (!dedicated) + Y_UnloadData(); endtic = -1; intertype = int_none; diff --git a/src/y_inter.h b/src/y_inter.h index 859144b1d..74183066e 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -1,6 +1,6 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- -// Copyright (C) 2004-2020 by Sonic Team Junior. +// Copyright (C) 2004-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -14,6 +14,7 @@ extern boolean usebuffer; void Y_IntermissionDrawer(void); void Y_Ticker(void); +void Y_LoadIntermissionData(void); void Y_StartIntermission(void); void Y_EndIntermission(void); diff --git a/src/z_zone.c b/src/z_zone.c index ad64a3a07..b949730e3 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -1,7 +1,7 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2006 by Graue. -// Copyright (C) 2006-2020 by Sonic Team Junior. +// Copyright (C) 2006-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -813,12 +813,12 @@ static void Command_Memfree_f(void) #ifdef HWRENDER if (rendermode == render_opengl) { - CONS_Printf(M_GetText("Patch info headers: %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHINFO)>>10)); - CONS_Printf(M_GetText("Mipmap patches : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHCOLMIPMAP)>>10)); - CONS_Printf(M_GetText("HW Texture cache : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRCACHE)>>10)); - CONS_Printf(M_GetText("Plane polygons : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPLANE)>>10)); - CONS_Printf(M_GetText("HW model textures : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRMODELTEXTURE)>>10)); - CONS_Printf(M_GetText("HW Texture used : %7d KB\n"), HWR_GetTextureUsed()>>10); + CONS_Printf(M_GetText("Patch info headers : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHINFO)>>10)); + CONS_Printf(M_GetText("Cached textures : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRCACHE)>>10)); + CONS_Printf(M_GetText("Texture colormaps : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPATCHCOLMIPMAP)>>10)); + CONS_Printf(M_GetText("Model textures : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRMODELTEXTURE)>>10)); + CONS_Printf(M_GetText("Plane polygons : %7s KB\n"), sizeu1(Z_TagUsage(PU_HWRPLANE)>>10)); + CONS_Printf(M_GetText("All GPU textures : %7d KB\n"), HWR_GetTextureUsed()>>10); } #endif diff --git a/src/z_zone.h b/src/z_zone.h index e80a45e7f..d7e1ed528 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1998-2000 by DooM Legacy Team. -// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 1999-2022 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. @@ -39,6 +39,7 @@ enum // Tags < PU_LEVEL are not purged until freed explicitly. PU_STATIC = 1, // static entire execution time PU_LUA = 2, // static entire execution time -- used by lua so it doesn't get caught in loops forever + PU_PERFSTATS = 3, // static between changes to ps_samplesize cvar PU_SOUND = 11, // static while playing PU_MUSIC = 12, // static while playing @@ -68,8 +69,7 @@ enum PU_HWRCACHE_UNLOCKED = 102, // 'unlocked' PU_HWRCACHE memory: // 'second-level' cache for graphics // stored in hardware format and downloaded as needed - PU_HWRPATCHINFO_UNLOCKED = 103, // 'unlocked' PU_HWRPATCHINFO memory - PU_HWRMODELTEXTURE_UNLOCKED = 104, // 'unlocked' PU_HWRMODELTEXTURE memory + PU_HWRMODELTEXTURE_UNLOCKED = 103, // 'unlocked' PU_HWRMODELTEXTURE memory }; // diff --git a/tools/PHP/RSS1.0.php b/tools/PHP/RSS1.0.php deleted file mode 100644 index 30eb32585..000000000 --- a/tools/PHP/RSS1.0.php +++ /dev/null @@ -1,55 +0,0 @@ -'; -echo "\n"; -echo ''; -echo "\n"; -echo "\n"; -echo ' '; -echo "\n"; -echo ' SRB2 Master Server RSS Feed'; -echo "\n"; -echo ' http://srb2.servegame.org/'; -echo "\n"; -echo ' Playing around with RSS'; -echo "\n"; -//echo ' en-us'; -//echo "\n"; - $fd = fsockopen("srb2.servegame.org", 28900, $errno, $errstr, 5); -// $fd = 0; - if ($fd) - { - $buff = "000012400000"; - fwrite($fd, $buff); - while (1) - { - $content=fgets($fd, 13); // skip 13 first bytes - $content=fgets($fd, 1024); - echo "$content"; - if (feof($fd)) break; - } - fclose($fd); - } - else - { - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo "\n"; - echo ' '; - echo 'No master serverThe master server is not running'; - } -?> - \ No newline at end of file diff --git a/tools/PHP/RSS92.php b/tools/PHP/RSS92.php deleted file mode 100644 index 4dd194089..000000000 --- a/tools/PHP/RSS92.php +++ /dev/null @@ -1,37 +0,0 @@ -'; -echo "\n"; -echo ''; -echo "\n"; -echo ' '; -echo "\n"; -echo ' SRB2 Master Server RSS Feed'; -echo "\n"; -echo ' Playing around with RSS'; -echo "\n"; -echo ' http://srb2.servegame.org/'; -echo "\n"; -echo ' en-us'; -echo "\n"; - $fd = fsockopen("srb2.servegame.org", 28900, $errno, $errstr, 5); - if ($fd) - { - $buff = "000012380000"; - fwrite($fd, $buff); - while (1) - { - $content=fgets($fd, 13); // skip the next 13 bytes - $content=fgets($fd, 1024); - echo "$content"; - if (feof($fd)) break; - } - fclose($fd); - } - else - { - echo "No master serverThe master server is not running"; - } -?> - - \ No newline at end of file diff --git a/tools/PHP/index.php b/tools/PHP/index.php deleted file mode 100644 index 93bb7c92b..000000000 --- a/tools/PHP/index.php +++ /dev/null @@ -1,90 +0,0 @@ - - - - -SRB2 Master Server Status - - -
- - - - - - - - - -
-
- SRB2 logo. -
- SRB2's HomePage
-
-
-
- Chompy World logo. -
- Chompy World
-
-
-
- SRB2 World logo. -
- SRB2 World
-
-
- -
-
-
- -SRB2 Master Server Status\nCurrent host: $host_addr
"; - $buff = "000043210000"; - fwrite($fd, $buff); - while (1) - { - $content=fgets($fd, 13); // skip 13 first bytes - $content=fgets($fd, 1024); - echo "$content"; - if (feof($fd)) break; - } - fclose($fd); - - } - else - { - echo 'The master server is not running
'; - echo "ERROR: $errno - $errstr
\n"; - } -?> -
-

Info:

-Win32 SRB2MSLauncher Great job, "Gregor Dick"/Oogaland of Gregorsoft Software -
-

-

Version Info:

-srb2dos.exe (DOS/Allegro/WATTCP32 version)
-srb2.exe (Windows/DirectX/FMOD version)
-srb2sdl.exe (Windows/SDL/SDL_mixer version)
-lsdlsrb2 (GNU/Linux/SDL/SDL_mixer version)
-
-Srb2win.exe v1.09.4 (use Internet search menu)
- - - diff --git a/tools/PHP/text.php b/tools/PHP/text.php deleted file mode 100644 index 282b812b7..000000000 --- a/tools/PHP/text.php +++ /dev/null @@ -1,24 +0,0 @@ - diff --git a/tools/SDL-1.2.14-gc/README b/tools/SDL-1.2.14-gc/README deleted file mode 100644 index 8ce488fa9..000000000 --- a/tools/SDL-1.2.14-gc/README +++ /dev/null @@ -1 +0,0 @@ -Once patched, run autogen.sh, configure with "./configure --without-x --disable-video-x11 --disable-video-fbcon --disable-video-aalib --disable-video-directfb --disable-video-opengl --enable-video-gc" and then compile. diff --git a/tools/SDL-1.2.14-gc/SDL-1.2.14-gc.patch b/tools/SDL-1.2.14-gc/SDL-1.2.14-gc.patch deleted file mode 100644 index 5b2b2cfa0..000000000 --- a/tools/SDL-1.2.14-gc/SDL-1.2.14-gc.patch +++ /dev/null @@ -1,641 +0,0 @@ -From 8e6ada7bc33e3cc4e1c17821ea171bf0815a505d Mon Sep 17 00:00:00 2001 -From: Alam Arias -Date: Tue, 1 Dec 2009 19:31:57 -0500 -Subject: [PATCH] SDL GC hack - ---- - configure.in | 17 ++ - include/SDL_config.h.in | 1 + - src/video/fbcon/SDL_fbgc.c | 471 +++++++++++++++++++++++++++++++++++++++++ - src/video/fbcon/SDL_fbgc.h | 35 +++ - src/video/fbcon/SDL_fbvideo.c | 10 + - src/video/fbcon/SDL_fbvideo.h | 11 + - 6 files changed, 545 insertions(+), 0 deletions(-) - create mode 100644 src/video/fbcon/SDL_fbgc.c - create mode 100644 src/video/fbcon/SDL_fbgc.h - -diff --git a/configure.in b/configure.in -index a7e9b18..a8961ba 100644 ---- a/configure.in -+++ b/configure.in -@@ -1227,6 +1227,22 @@ AC_HELP_STRING([--enable-video-fbcon], [use framebuffer console video driver [[d - fi - } - -+dnl See if we're running on Linux for the Nintendo GameCube/Wii -+dnl FIXME, perform a real test here... -+CheckGC() -+{ -+ AC_ARG_ENABLE(video-gc, -+AC_HELP_STRING([--enable-video-gc], [enable GameCube video support in FB [[default=no]]]), -+ , enable_video_gc=no) -+ if test x$enable_video = xyes -a x$enable_video_gc = xyes -a x$video_fbcon = xyes; then -+ video_gc=yes -+ AC_MSG_RESULT($video_gc) -+ if test x$video_gc = xyes; then -+ AC_DEFINE(SDL_VIDEO_DRIVER_GC) -+ fi -+ fi -+} -+ - dnl Find DirectFB - CheckDirectFB() - { -@@ -2322,6 +2338,7 @@ case "$host" in - CheckX11 - CheckNANOX - CheckFBCON -+ CheckGC - CheckDirectFB - CheckPS2GS - CheckPS3 -diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in -index 58593ca..e523e9b 100644 ---- a/include/SDL_config.h.in -+++ b/include/SDL_config.h.in -@@ -262,6 +262,7 @@ - #undef SDL_VIDEO_DRIVER_DUMMY - #undef SDL_VIDEO_DRIVER_FBCON - #undef SDL_VIDEO_DRIVER_GAPI -+#undef SDL_VIDEO_DRIVER_GC - #undef SDL_VIDEO_DRIVER_GEM - #undef SDL_VIDEO_DRIVER_GGI - #undef SDL_VIDEO_DRIVER_IPOD -diff --git a/src/video/fbcon/SDL_fbgc.c b/src/video/fbcon/SDL_fbgc.c -new file mode 100644 -index 0000000..b3b72bb ---- /dev/null -+++ b/src/video/fbcon/SDL_fbgc.c -@@ -0,0 +1,471 @@ -+/* -+ SDL - Simple DirectMedia Layer -+ Copyright (C) 1997-2009 Sam Lantinga -+ -+ This library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ This library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with this library; if not, write to the Free Software -+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ -+ Sam Lantinga -+ slouken@libsdl.org -+*/ -+#include "SDL_config.h" -+ -+#ifdef SDL_VIDEO_DRIVER_GC -+#include -+#include "SDL_video.h" -+#include "../SDL_blit.h" -+#include "SDL_fbgc.h" -+ -+static Uint32 r_Yr[256]; -+static Uint32 g_Yg_[256]; -+static Uint32 b_Yb[256]; -+static Uint32 r_Ur[256]; -+static Uint32 g_Ug_[256]; -+static Uint32 b_Ub[256]; -+/* static Uint32 r_Vr[256]; // space and cache optimisation */ -+#define r_Vr b_Ub -+static Uint32 g_Vg_[256]; -+static Uint32 b_Vb[256]; -+ -+static Uint8 RGB16toY[1 << 16]; -+static Uint8 RGB16toU[1 << 16]; -+static Uint8 RGB16toV[1 << 16]; -+ -+#ifndef FBIOFLIPHACK -+#define FBIOFLIPHACK 0x4623 /* gc-linux */ -+#endif -+ -+#ifndef GC_BLACK -+#define GC_BLACK 0x00800080 -+#endif -+ -+#ifdef GC_DEBUG -+# define GC_DPRINTF(fmt, args...) \ -+ fprintf(stderr,"DDD|%s: " fmt, __FUNCTION__ , ## args) -+#else -+# define GC_DPRINTF(fmt, args...) -+#endif -+ -+SDL_bool GC_Test(_THIS) -+{ -+ int fliptest; -+ if (ioctl(console_fd, FBIOFLIPHACK, &fliptest)) -+ return SDL_TRUE; -+ return SDL_FALSE; -+} -+ -+SDL_bool GC_Available(void) -+{ -+ if (access("/sys/bus/of_platform/drivers/gcn-vifb", 0) == 0) -+ return SDL_TRUE; -+ -+ return SDL_FALSE; -+} -+ -+/* -+ * -+ * Color space handling. -+ */ -+ -+#define RGB2YUV_SHIFT 16 -+#define RGB2YUV_LUMA 16 -+#define RGB2YUV_CHROMA 128 -+ -+#define Yr ((int)( 0.299*(1< y) ? y : z)) -+ -+static void GC_InitRGB2YUVTables(void) -+{ -+ unsigned int i; -+ unsigned int r, g, b; -+ -+ for (i = 0; i < 256; i++) { -+ r_Yr[i] = Yr * i; -+ g_Yg_[i] = Yg * i + (RGB2YUV_LUMA << RGB2YUV_SHIFT); -+ b_Yb[i] = Yb * i; -+ r_Ur[i] = Ur * i; -+ g_Ug_[i] = Ug * i + (RGB2YUV_CHROMA << RGB2YUV_SHIFT); -+ b_Ub[i] = Ub * i; -+ r_Vr[i] = Vr * i; -+ g_Vg_[i] = Vg * i + (RGB2YUV_CHROMA << RGB2YUV_SHIFT); -+ b_Vb[i] = Vb * i; -+ } -+ -+ for (i = 0; i < 1 << 16; i++) { -+ /* RGB565 */ -+ r = ((i >> 8) & 0xf8); -+ g = ((i >> 3) & 0xfc); -+ b = ((i << 3) & 0xf8); -+ /* extend to 8bit */ -+ r |= (r >> 5); -+ g |= (g >> 6); -+ b |= (b >> 5); -+ -+ RGB16toY[i] = -+ clamp(16, 235, -+ (r_Yr[r] + g_Yg_[g] + b_Yb[b]) >> RGB2YUV_SHIFT); -+ RGB16toU[i] = -+ clamp(16, 240, -+ (r_Ur[r] + g_Ug_[g] + b_Ub[b]) >> RGB2YUV_SHIFT); -+ RGB16toV[i] = -+ clamp(16, 240, -+ (r_Vr[r] + g_Vg_[g] + b_Vb[b]) >> RGB2YUV_SHIFT); -+ } -+} -+ -+static inline Uint32 rgbrgb16toyuy2(Uint16 rgb1, Uint16 rgb2) -+{ -+ register int Y1, Cb, Y2, Cr; -+ Uint16 rgb; -+ -+ /* fast path, thanks to bohdy */ -+ if (!(rgb1 | rgb2)) { -+ return GC_BLACK; /* black, black */ -+ } -+ -+ if (rgb1 == rgb2) { -+ /* fast path, thanks to isobel */ -+ Y1 = Y2 = RGB16toY[rgb1]; -+ Cb = RGB16toU[rgb1]; -+ Cr = RGB16toV[rgb1]; -+ } else { -+ Y1 = RGB16toY[rgb1]; -+ Y2 = RGB16toY[rgb2]; -+ -+ /* RGB565 average */ -+ rgb = ((rgb1 >> 1) & 0xFBEF) + ((rgb2 >> 1) & 0xFBEF) + -+ ((rgb1 & rgb2) & 0x0821); -+ -+ Cb = RGB16toU[rgb]; -+ Cr = RGB16toV[rgb]; -+ } -+ -+ return (((char)Y1) << 24) | (((char)Cb) << 16) | (((char)Y2) << 8) -+ | (((char)Cr) << 0); -+} -+ -+/* -+ * -+ * Blitters. -+ */ -+static void GC_UpdateRectRGB16(_THIS, SDL_Rect * rect, int pitch) -+{ -+ int width, height, left, i, mod, mod32; -+ Uint8 *src, *dst; -+ Uint32 *src32, *dst32; -+ Uint16 *rgb; -+ -+ /* XXX case width < 2 needs special treatment */ -+ -+ /* in pixel units */ -+ left = rect->x & ~1; /* 2 pixel align */ -+ width = (rect->w + 1) & ~1; /* 2 pixel align in excess */ -+ height = rect->h; -+ -+ /* in bytes, src and dest are 16bpp */ -+ src = shadow_mem + (rect->y * pitch) + left * 2; -+ dst = flip_address[back_page] + page_offset + -+ (rect->y * pitch) + left * 2; -+ mod = pitch - width * 2; -+ -+ src32 = (Uint32 *) src; -+ dst32 = (Uint32 *) dst; -+ mod32 = mod / 4; -+ -+ while (height--) { -+ i = width / 2; -+ -+ while (i--) { -+ rgb = (Uint16 *) src32; -+ *dst32++ = rgbrgb16toyuy2(rgb[0], rgb[1]); -+ src32++; -+ } -+ src32 += mod32; -+ dst32 += mod32; -+ } -+} -+ -+void GC_Init(_THIS, SDL_PixelFormat *vformat) -+{ -+ GC_InitRGB2YUVTables(); -+ -+ /* 16 bits per pixel */ -+ vformat->BitsPerPixel = 16; -+ vformat->BytesPerPixel = 2; -+ /* RGB565 */ -+ vformat->Rmask = 0x0000f800; -+ vformat->Gmask = 0x000007e0; -+ vformat->Bmask = 0x0000001f; -+ -+ shadow_fb = 1; -+} -+ -+/* -+ * -+ * Video mode handling. -+ */ -+ -+/* only 640x480 16bpp is currently supported */ -+const static SDL_Rect RECT_640x480 = { 0, 0, 640, 480 }; -+const static SDL_Rect *vid_modes[] = { -+ &RECT_640x480, -+ NULL -+}; -+ -+static SDL_Rect **GC_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags) -+{ -+ switch (format->BitsPerPixel) { -+ case 16: -+ return (SDL_Rect **) vid_modes; -+ default: -+ return NULL; -+ } -+} -+ -+SDL_Surface *GC_SetVideoMode(_THIS, SDL_Surface * current, -+ int width, int height, int bpp, Uint32 flags) -+{ -+ struct fb_fix_screeninfo finfo; -+ struct fb_var_screeninfo vinfo; -+ int i; -+ Uint32 Rmask; -+ Uint32 Gmask; -+ Uint32 Bmask; -+ Uint32 *p, *q; -+ Uint32 yres; -+ -+ GC_DPRINTF("Setting %dx%d %dbpp %smode\n", width, height, bpp, -+ (flags & SDL_DOUBLEBUF)?"(doublebuf) ":""); -+ -+ /* Set the terminal into graphics mode */ -+ if (FB_EnterGraphicsMode(this) < 0) { -+ return (NULL); -+ } -+ -+ /* Restore the original palette */ -+ //FB_RestorePalette(this); -+ -+ /* Set the video mode and get the final screen format */ -+ if (ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) { -+ SDL_SetError("Couldn't get console screen info"); -+ return (NULL); -+ } -+ -+ yres = vinfo.yres; -+ -+ /* hack to center 640x480 resolution on PAL cubes */ -+ if (vinfo.xres == 640 && vinfo.yres == 576) { -+ page_offset = ((576 - 480) / 2) * 640 * ((bpp + 7) / 8); -+ } else { -+ page_offset = 0; -+ } -+ -+ /* clear all video memory */ -+ p = (Uint32 *)mapped_mem; -+ q = (Uint32 *)(mapped_mem + mapped_memlen); -+ while (p < q) -+ *p++ = GC_BLACK; -+ -+ if ((vinfo.xres != width) || (vinfo.yres != height) || -+ (vinfo.bits_per_pixel != bpp)) { -+ vinfo.activate = FB_ACTIVATE_NOW; -+ vinfo.accel_flags = 0; -+ vinfo.bits_per_pixel = bpp; -+ vinfo.xres = width; -+ vinfo.xres_virtual = width; -+ /* do not modify yres*, we use a fake 640x480 mode in PAL */ -+ //vinfo.yres = height; -+ //vinfo.yres_virtual = 2*height; -+ vinfo.xoffset = 0; -+ vinfo.yoffset = 0; -+ vinfo.red.length = vinfo.red.offset = 0; -+ vinfo.green.length = vinfo.green.offset = 0; -+ vinfo.blue.length = vinfo.blue.offset = 0; -+ vinfo.transp.length = vinfo.transp.offset = 0; -+ -+ if (ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) { -+ SDL_SetError("Couldn't set console screen info"); -+ return (NULL); -+ } -+ } else { -+ int maxheight; -+ -+ /* Figure out how much video memory is available */ -+ maxheight = 2*yres; -+ if (vinfo.yres_virtual > maxheight) { -+ vinfo.yres_virtual = maxheight; -+ } -+ } -+ cache_vinfo = vinfo; -+ -+ Rmask = 0; -+ for (i = 0; i < vinfo.red.length; ++i) { -+ Rmask <<= 1; -+ Rmask |= (0x00000001 << vinfo.red.offset); -+ } -+ Gmask = 0; -+ for (i = 0; i < vinfo.green.length; ++i) { -+ Gmask <<= 1; -+ Gmask |= (0x00000001 << vinfo.green.offset); -+ } -+ Bmask = 0; -+ for (i = 0; i < vinfo.blue.length; ++i) { -+ Bmask <<= 1; -+ Bmask |= (0x00000001 << vinfo.blue.offset); -+ } -+ if (!SDL_ReallocFormat(current, bpp, Rmask, Gmask, Bmask, 0)) { -+ return (NULL); -+ } -+ -+ /* Get the fixed information about the console hardware. -+ This is necessary since finfo.line_length changes. -+ */ -+ if (ioctl(console_fd, FBIOGET_FSCREENINFO, &finfo) < 0) { -+ SDL_SetError("Couldn't get console hardware info"); -+ return (NULL); -+ } -+ -+ /* Save hardware palette, if needed */ -+ //FB_SavePalette(this, &finfo, &vinfo); -+ -+ /* Set up the new mode framebuffer */ -+ current->flags = SDL_FULLSCREEN; -+ current->w = width; -+ current->h = height; -+ current->pitch = width * ((bpp + 7) / 8); -+ current->pixels = shadow_mem; -+ -+ flip_address[0] = mapped_mem; -+ flip_address[1] = mapped_mem + current->pitch * yres; -+ -+ back_page = 1; -+ if (flags & SDL_DOUBLEBUF) { -+ current->flags |= SDL_DOUBLEBUF; -+ flip_pending = 1; -+ } else { -+ flip_pending = 0; -+ /* make page 0 both the visible and back page */ -+ back_page = ioctl(console_fd, FBIOFLIPHACK, &back_page); -+ if (back_page < 0) -+ back_page = 0; -+ } -+ -+ /* Set the update rectangle function */ -+ switch (bpp) { -+ case 16: -+ GC_DPRINTF("Using 16bpp blitter\n"); -+ this->hidden->UpdateRect = GC_UpdateRectRGB16; -+ break; -+ default: -+ GC_DPRINTF("Using NO blitter\n"); -+ this->hidden->UpdateRect = NULL; -+ break; -+ } -+ -+ /* Handle OpenGL support */ -+#ifdef HAVE_OPENGL -+ if (flags & SDL_OPENGL) { -+ if (GC_GL_CreateWindow(this, width, height) == 0) { -+ current->flags |= (SDL_OPENGL | SDL_FULLSCREEN); -+ } else { -+ current = NULL; -+ } -+ } -+#endif /* HAVE_OPENGL */ -+ -+ /* We're done */ -+ return (current); -+} -+ -+static int GC_FlipHWSurface(_THIS, SDL_Surface * surface) -+{ -+ if (flip_pending) { -+ /* SDL_UpdateRect was not called */ -+ SDL_UpdateRect(this->screen, 0, 0, 0, 0); -+ } -+ -+ /* flip video page as soon as possible */ -+ ioctl(console_fd, FBIOFLIPHACK, NULL); -+ flip_pending = 1; -+ -+ return (0); -+} -+ -+static void GC_WaitForFlipCompletion(_THIS) -+{ -+ int visible_page; -+ int result; -+ -+ if (flip_pending) { -+ flip_pending = 0; -+ back_page ^= 1; -+ visible_page = back_page; -+ while (visible_page == back_page) { -+ /* wait until back_page is not visible */ -+ result = ioctl(console_fd, FBIOFLIPHACK, &back_page); -+ if (result < 0) { -+ if ((errno == EINTR) || (errno == EAGAIN)) -+ continue; -+ return; /* ioctl unsupported ... */ -+ } -+ visible_page = result; -+ } -+ /* -+ * At this point the back_page is not visible. We can safely -+ * write to it without tearing. -+ */ -+ } -+} -+ -+static void GC_UpdateRects(_THIS, int numrects, SDL_Rect * rects) -+{ -+ SDL_Surface *screen; -+ int pitch; -+ -+ /* external yuy2 fb is 16bpp */ -+ -+ screen = this->screen; -+ pitch = screen->pitch; /* this is the pitch of the shadow buffer */ -+ -+ if (this->hidden->UpdateRect) { -+ GC_WaitForFlipCompletion(this); -+ while (numrects--) { -+ if (rects->w <= 0 || rects->h <= 0) -+ continue; -+ this->hidden->UpdateRect(this, rects, pitch); -+ rects++; -+ } -+ } -+} -+ -+void GC_CreateDevice(SDL_VideoDevice *this) -+{ -+ this->ListModes = GC_ListModes; -+ this->SetVideoMode = GC_SetVideoMode; -+ this->FlipHWSurface = GC_FlipHWSurface; -+ this->UpdateRects = GC_UpdateRects; -+} -+ -+#endif -diff --git a/src/video/fbcon/SDL_fbgc.h b/src/video/fbcon/SDL_fbgc.h -new file mode 100644 -index 0000000..534a73e ---- /dev/null -+++ b/src/video/fbcon/SDL_fbgc.h -@@ -0,0 +1,35 @@ -+/* -+ SDL - Simple DirectMedia Layer -+ Copyright (C) 1997-2009 Sam Lantinga -+ -+ This library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ This library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with this library; if not, write to the Free Software -+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ -+ Sam Lantinga -+ slouken@libsdl.org -+*/ -+#include "SDL_config.h" -+ -+ -+#ifdef SDL_VIDEO_DRIVER_GC -+/* Gamecube/Wii hardware setup for the SDL framebuffer console driver */ -+ -+#include "SDL_fbvideo.h" -+ -+extern SDL_bool GC_Available(void); -+extern void GC_CreateDevice(SDL_VideoDevice *this); -+ -+extern SDL_bool GC_Test(_THIS); -+extern void GC_Init(_THIS, SDL_PixelFormat *vformat); -+#endif -diff --git a/src/video/fbcon/SDL_fbvideo.c b/src/video/fbcon/SDL_fbvideo.c -index 81a89da..328790e 100644 ---- a/src/video/fbcon/SDL_fbvideo.c -+++ b/src/video/fbcon/SDL_fbvideo.c -@@ -272,6 +272,11 @@ static SDL_VideoDevice *FB_CreateDevice(int devindex) - - this->free = FB_DeleteDevice; - -+#ifdef SDL_VIDEO_DRIVER_GC -+ if (GC_Available(this)) -+ GC_CreateDevice(this); -+#endif -+ - return this; - } - -@@ -784,6 +789,11 @@ static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat) - } - } - -+#ifdef SDL_VIDEO_DRIVER_GC -+ if (GC_Test(this)) -+ GC_Init(this, vformat); -+#endif -+ - if (shadow_fb) { - shadow_mem = (char *)SDL_malloc(mapped_memlen); - if (shadow_mem == NULL) { -diff --git a/src/video/fbcon/SDL_fbvideo.h b/src/video/fbcon/SDL_fbvideo.h -index 03b9e94..74d1460 100644 ---- a/src/video/fbcon/SDL_fbvideo.h -+++ b/src/video/fbcon/SDL_fbvideo.h -@@ -106,6 +106,12 @@ struct SDL_PrivateVideoData { - - void (*wait_vbl)(_THIS); - void (*wait_idle)(_THIS); -+#ifdef SDL_VIDEO_DRIVER_GC -+ void (*UpdateRect) (_THIS, SDL_Rect * rect, int pitch); -+ int back_page; -+ int page_offset; -+ int flip_pending; -+#endif - }; - /* Old variable names */ - #define console_fd (this->hidden->console_fd) -@@ -147,6 +153,11 @@ struct SDL_PrivateVideoData { - #define screen_palette (this->hidden->screen_palette) - #define wait_vbl (this->hidden->wait_vbl) - #define wait_idle (this->hidden->wait_idle) -+#ifdef SDL_VIDEO_DRIVER_GC -+#define back_page (this->hidden->back_page) -+#define page_offset (this->hidden->page_offset) -+#define flip_pending (this->hidden->flip_pending) -+#endif - - /* Accelerator types that are supported by the driver, but are not - necessarily in the kernel headers on the system we compile on. --- -1.6.5 - diff --git a/tools/SDL1.2.7_CE/SDL-1.27_CE.diff b/tools/SDL1.2.7_CE/SDL-1.27_CE.diff deleted file mode 100644 index 196329b84..000000000 --- a/tools/SDL1.2.7_CE/SDL-1.27_CE.diff +++ /dev/null @@ -1,2260 +0,0 @@ -diff -ruN SDL-1.2.7-orig/src/audio/windib/SDL_dibaudio.c SDL-1.2.7/src/audio/windib/SDL_dibaudio.c ---- SDL-1.2.7-orig/src/audio/windib/SDL_dibaudio.c Wed Feb 18 09:22:00 2004 -+++ SDL-1.2.7/src/audio/windib/SDL_dibaudio.c Thu Nov 18 12:07:29 2004 -@@ -146,8 +146,16 @@ - - /* Set high priority for the audio thread */ - static void DIB_ThreadInit(_THIS) --{ -- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); -+{ -+#ifdef _WIN32_WCE -+#ifdef SH3 -+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); -+#else -+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); -+#endif -+#else -+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); -+#endif - } - - void DIB_WaitAudio(_THIS) -diff -ruN SDL-1.2.7-orig/src/cpuinfo/SDL_cpuinfo.c SDL-1.2.7/src/cpuinfo/SDL_cpuinfo.c ---- SDL-1.2.7-orig/src/cpuinfo/SDL_cpuinfo.c Tue Feb 10 07:31:36 2004 -+++ SDL-1.2.7/src/cpuinfo/SDL_cpuinfo.c Fri Nov 19 20:53:01 2004 -@@ -38,6 +38,10 @@ - - #ifdef MACOSX - #include /* For AltiVec check */ -+#endif -+ -+#if defined(_MSC_VER) && (defined(ARM) || defined(MIPS) || defined(SHx)) -+#undef _MSC_VER - #endif - - #define CPU_HAS_RDTSC 0x00000001 -diff -ruN SDL-1.2.7-orig/src/joystick/win32/SDL_mmjoystick.c SDL-1.2.7/src/joystick/win32/SDL_mmjoystick.c ---- SDL-1.2.7-orig/src/joystick/win32/SDL_mmjoystick.c Wed Feb 18 09:22:02 2004 -+++ SDL-1.2.7/src/joystick/win32/SDL_mmjoystick.c Fri Nov 19 20:47:22 2004 -@@ -37,6 +37,7 @@ - - #include - #include -+#include - - #define MAX_JOYSTICKS 16 - #define MAX_AXES 6 /* each joystick can have up to 6 axes */ -@@ -51,6 +52,7 @@ - /* array to hold joystick ID values */ - static UINT SYS_JoystickID[MAX_JOYSTICKS]; - static JOYCAPS SYS_Joystick[MAX_JOYSTICKS]; -+static char *SYS_JoystickName[MAX_JOYSTICKS]; - - /* The private structure used to keep track of a joystick */ - struct joystick_hwdata -@@ -69,6 +71,78 @@ - /* Convert a win32 Multimedia API return code to a text message */ - static void SetMMerror(char *function, int code); - -+static char *GetJoystickName(int index, const char *szRegKey) -+{ -+ /* added 7/24/2004 by Eckhard Stolberg */ -+ /* -+ see if there is a joystick for the current -+ index (1-16) listed in the registry -+ */ -+ char *name = NULL; -+ HKEY hKey; -+ DWORD regsize; -+ LONG regresult; -+ unsigned char regkey[256]; -+ unsigned char regvalue[256]; -+ unsigned char regname[256]; -+ -+ sprintf(regkey, "%s\\%s\\%s", -+ REGSTR_PATH_JOYCONFIG, -+ szRegKey, -+ REGSTR_KEY_JOYCURR); -+ regresult = RegOpenKeyExA(HKEY_LOCAL_MACHINE, -+ (LPTSTR) ®key, 0, KEY_READ, &hKey); -+ if (regresult == ERROR_SUCCESS) -+ { -+ /* -+ find the registry key name for the -+ joystick's properties -+ */ -+ regsize = sizeof(regname); -+ sprintf(regvalue, -+ "Joystick%d%s", index+1, -+ REGSTR_VAL_JOYOEMNAME); -+ regresult = RegQueryValueExA(hKey, -+ regvalue, 0, 0, (LPBYTE) ®name, -+ (LPDWORD) ®size); -+ RegCloseKey(hKey); -+ if (regresult == ERROR_SUCCESS) -+ { -+ /* open that registry key */ -+ sprintf(regkey, "%s\\%s", -+ REGSTR_PATH_JOYOEM, regname); -+ regresult = RegOpenKeyExA(HKEY_LOCAL_MACHINE, -+ regkey, 0, KEY_READ, &hKey); -+ if (regresult == ERROR_SUCCESS) -+ { -+ /* find the size for the OEM name text */ -+ regsize = sizeof(regvalue); -+ regresult = -+ RegQueryValueExA(hKey, -+ REGSTR_VAL_JOYOEMNAME, -+ 0, 0, NULL, -+ (LPDWORD) ®size); -+ if (regresult == ERROR_SUCCESS) -+ { -+ /* -+ allocate enough memory -+ for the OEM name text ... -+ */ -+ name = (char *) malloc(regsize); -+ /* ... and read it from the registry */ -+ regresult = -+ RegQueryValueExA(hKey, -+ REGSTR_VAL_JOYOEMNAME, 0, 0, -+ (LPBYTE) name, -+ (LPDWORD) ®size); -+ RegCloseKey(hKey); -+ } -+ } -+ } -+ } -+ return(name); -+} -+ - - /* Function to scan the system for joysticks. - * This function should set SDL_numjoysticks to the number of available -@@ -94,6 +168,7 @@ - - for ( i = 0; i < MAX_JOYSTICKS; i++ ) { - SYS_JoystickID[i] = JOYSTICKID1 + i; -+ SYS_JoystickName[i] = NULL; - } - - -@@ -110,6 +185,7 @@ - if ( result == JOYERR_NOERROR ) { - SYS_JoystickID[numdevs] = SYS_JoystickID[i]; - SYS_Joystick[numdevs] = joycaps; -+ SYS_JoystickName[numdevs] = GetJoystickName(numdevs, joycaps.szRegKey); - numdevs++; - } - } -@@ -120,8 +196,11 @@ - /* Function to get the device-dependent name of a joystick */ - const char *SDL_SYS_JoystickName(int index) - { -- /***-> test for invalid index ? */ -+ if ( SYS_JoystickName[index] != NULL ) { -+ return(SYS_JoystickName[index]); -+ } else { - return(SYS_Joystick[index].szPname); -+ } - } - - /* Function to open a joystick for use. -@@ -292,7 +371,12 @@ - /* Function to perform any system-specific joystick related cleanup */ - void SDL_SYS_JoystickQuit(void) - { -- return; -+ int i; -+ for (i = 0; i < MAX_JOYSTICKS; i++) { -+ if ( SYS_JoystickName[i] != NULL ) { -+ free(SYS_JoystickName[i]); -+ } -+ } - } - - -diff -ruN SDL-1.2.7-orig/src/video/SDL_sysvideo.h SDL-1.2.7/src/video/SDL_sysvideo.h ---- SDL-1.2.7-orig/src/video/SDL_sysvideo.h Wed Feb 18 09:22:04 2004 -+++ SDL-1.2.7/src/video/SDL_sysvideo.h Thu Nov 18 12:08:48 2004 -@@ -361,6 +361,9 @@ - #endif - #ifdef ENABLE_WINDIB - extern VideoBootStrap WINDIB_bootstrap; -+#endif -+#ifdef ENABLE_WINGAPI -+extern VideoBootStrap WINGAPI_bootstrap; - #endif - #ifdef ENABLE_DIRECTX - extern VideoBootStrap DIRECTX_bootstrap; -diff -ruN SDL-1.2.7-orig/src/video/SDL_video.c SDL-1.2.7/src/video/SDL_video.c ---- SDL-1.2.7-orig/src/video/SDL_video.c Wed Feb 18 09:22:04 2004 -+++ SDL-1.2.7/src/video/SDL_video.c Thu Nov 18 12:11:01 2004 -@@ -80,6 +80,9 @@ - #endif - #ifdef ENABLE_DIRECTX - &DIRECTX_bootstrap, -+#endif -+#ifdef ENABLE_WINGAPI -+ &WINGAPI_bootstrap, - #endif - #ifdef ENABLE_WINDIB - &WINDIB_bootstrap, -diff -ruN SDL-1.2.7-orig/src/video/wincommon/SDL_sysevents.c SDL-1.2.7/src/video/wincommon/SDL_sysevents.c ---- SDL-1.2.7-orig/src/video/wincommon/SDL_sysevents.c Wed Feb 18 09:22:10 2004 -+++ SDL-1.2.7/src/video/wincommon/SDL_sysevents.c Thu Nov 18 12:28:03 2004 -@@ -40,6 +40,9 @@ - #include "SDL_lowvideo.h" - #include "SDL_syswm_c.h" - #include "SDL_main.h" -+#ifdef _WIN32_CE -+#include "SDL_dibvideo.h" -+#endif - - #ifdef WMMSG_DEBUG - #include "wmmsg.h" -@@ -173,6 +176,39 @@ - SDL_SetModState(state); - #endif /* !NO_GETKEYBOARDSTATE */ - } -+ -+#ifdef _WIN32_CE -+void transform(SDL_RotateAttr rotate, char ozone, Sint16 *x, Sint16 *y) { -+ Sint16 rotatedX; -+ Sint16 rotatedY; -+ -+ if (ozone) { -+ *x = *x * 2; -+ *y = *y * 2; -+ } -+ -+ switch(rotate) { -+ case SDL_ROTATE_NONE: -+ break; -+ case SDL_ROTATE_LEFT: -+ if (!SDL_VideoSurface) -+ break; -+ rotatedX = SDL_VideoSurface->w - *y; -+ rotatedY = *x; -+ *x = rotatedX; -+ *y = rotatedY; -+ break; -+ case SDL_ROTATE_RIGHT: -+ if (!SDL_VideoSurface) -+ break; -+ rotatedX = *y; -+ rotatedY = SDL_VideoSurface->h - *x; -+ *x = rotatedX; -+ *y = rotatedY; -+ break; -+ } -+} -+#endif - - /* The main Win32 event handler - DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it -@@ -273,7 +309,11 @@ - SetCursorPos(center.x, center.y); - posted = SDL_PrivateMouseMotion(0, 1, x, y); - } -- } else { -+ } else { -+#ifdef _WIN32_CE -+ if (SDL_VideoSurface) -+ transform(rotation, ozoneHack, &x, &y); -+#endif - posted = SDL_PrivateMouseMotion(0, 0, x, y); - } - } -@@ -361,8 +401,16 @@ - x = 0; y = 0; - } else { - x = (Sint16)LOWORD(lParam); -- y = (Sint16)HIWORD(lParam); -- } -+ y = (Sint16)HIWORD(lParam); -+#ifdef _WIN32_CE -+ if (SDL_VideoSurface) -+ transform(rotation, ozoneHack, &x, &y); -+#endif -+ } -+#ifdef _WIN32_WCE -+ /* Since stylus movements are not continuous */ -+ posted = SDL_PrivateMouseMotion(0, 0, x, y); -+#endif - posted = SDL_PrivateMouseButton( - state, button, x, y); - } -diff -ruN SDL-1.2.7-orig/src/video/wincommon/SDL_sysmouse.c SDL-1.2.7/src/video/wincommon/SDL_sysmouse.c ---- SDL-1.2.7-orig/src/video/wincommon/SDL_sysmouse.c Sat Aug 30 13:13:12 2003 -+++ SDL-1.2.7/src/video/wincommon/SDL_sysmouse.c Thu Nov 18 12:29:20 2004 -@@ -250,12 +250,16 @@ - - /* Check to see if we need to enter or leave mouse relative mode */ - void WIN_CheckMouseMode(_THIS) --{ -+{ -+#ifdef _WIN32_WCE -+ mouse_relative = 0; -+#else - /* If the mouse is hidden and input is grabbed, we use relative mode */ - if ( !(SDL_cursorstate & CURSOR_VISIBLE) && - (this->input_grab != SDL_GRAB_OFF) ) { - mouse_relative = 1; - } else { - mouse_relative = 0; -- } -+ } -+#endif - } -diff -ruN SDL-1.2.7-orig/src/video/windib/SDL_dibevents.c SDL-1.2.7/src/video/windib/SDL_dibevents.c ---- SDL-1.2.7-orig/src/video/windib/SDL_dibevents.c Wed Feb 18 09:22:10 2004 -+++ SDL-1.2.7/src/video/windib/SDL_dibevents.c Thu Nov 18 13:12:28 2004 -@@ -58,6 +58,29 @@ - /* DJM: If the user setup the window for us, we want to save his window proc, - and give him a chance to handle some messages. */ - static WNDPROC userWindowProc = NULL; -+ -+#ifdef _WIN32_WCE -+ -+WPARAM rotateKey(WPARAM key, SDL_RotateAttr direction) { -+ if (direction != SDL_ROTATE_LEFT) -+ return key; -+ -+ switch (key) { -+ case 0x26: /* up */ -+ return 0x27; -+ case 0x27: /* right */ -+ return 0x28; -+ case 0x28: /* down */ -+ return 0x25; -+ case 0x25: /* left */ -+ return 0x26; -+ } -+ -+ return key; -+} -+ -+#endif -+ - - /* The main Win32 event handler */ - LONG -@@ -69,6 +92,16 @@ - case WM_SYSKEYDOWN: - case WM_KEYDOWN: { - SDL_keysym keysym; -+ -+#ifdef _WIN32_WCE -+ // Drop GAPI artefacts -+ if (wParam == 0x84 || wParam == 0x5B) -+ return 0; -+ -+ // Rotate key if necessary -+ if (rotation != SDL_ROTATE_NONE) -+ wParam = rotateKey(wParam, rotation); -+#endif - - /* Ignore repeated keys */ - if ( lParam&REPEATED_KEYMASK ) { -@@ -129,6 +162,16 @@ - case WM_KEYUP: { - SDL_keysym keysym; - -+#ifdef _WIN32_WCE -+ // Drop GAPI artefacts -+ if (wParam == 0x84 || wParam == 0x5B) -+ return 0; -+ -+ // Rotate key if necessary -+ if (rotation != SDL_ROTATE_NONE) -+ wParam = rotateKey(wParam, rotation); -+#endif -+ - switch (wParam) { - case VK_CONTROL: - if ( lParam&EXTENDED_KEYMASK ) -@@ -333,7 +376,16 @@ - VK_keymap[VK_APPS] = SDLK_MENU; - - prev_shiftstates[0] = FALSE; -- prev_shiftstates[1] = FALSE; -+ prev_shiftstates[1] = FALSE; -+ -+#ifdef _WIN32_WCE -+ /* Hardcode the 4 magic keys to F1 F2 F3 F4 - the actual location of the keys varies ... */ -+ VK_keymap[0xC1] = SDLK_F1; -+ VK_keymap[0xC2] = SDLK_F2; -+ VK_keymap[0xC3] = SDLK_F3; -+ VK_keymap[0xC4] = SDLK_F4; -+#endif -+ - } - - static SDL_keysym *TranslateKey(UINT vkey, UINT scancode, SDL_keysym *keysym, int pressed) -@@ -364,9 +416,15 @@ - { - #ifndef CS_BYTEALIGNCLIENT - #define CS_BYTEALIGNCLIENT 0 -+#endif -+#ifdef _WIN32_CE -+ SDL_RegisterApp("SDL_app", CS_BYTEALIGNCLIENT | CS_HREDRAW | CS_VREDRAW, 0); -+#else -+ SDL_RegisterApp("SDL_app", CS_BYTEALIGNCLIENT, 0); - #endif -- SDL_RegisterApp("SDL_app", CS_BYTEALIGNCLIENT, 0); -- if ( SDL_windowid ) { -+ if ( SDL_windowid ) { -+// FIXME -+#ifndef _WIN32_WCE - SDL_Window = (HWND)strtol(SDL_windowid, NULL, 0); - - /* DJM: we want all event's for the user specified -@@ -375,11 +433,19 @@ - if (SDL_Window) { - userWindowProc = (WNDPROC)GetWindowLong(SDL_Window, GWL_WNDPROC); - SetWindowLong(SDL_Window, GWL_WNDPROC, (LONG)WinMessage); -- } -- } else { -+ } -+ #endif -+ } else { -+#ifdef _WIN32_WCE -+ -+ SDL_Window = CreateWindow(SDL_Appname, SDL_Appname, (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX), -+ 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), -+ NULL, NULL, SDL_Instance, NULL); -+#else - SDL_Window = CreateWindow(SDL_Appname, SDL_Appname, - (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX), -- CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL); -+ CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, SDL_Instance, NULL); -+#endif - if ( SDL_Window == NULL ) { - SDL_SetError("Couldn't create window"); - return(-1); -diff -ruN SDL-1.2.7-orig/src/video/windib/SDL_dibvideo.c SDL-1.2.7/src/video/windib/SDL_dibvideo.c ---- SDL-1.2.7-orig/src/video/windib/SDL_dibvideo.c Wed Feb 18 09:22:10 2004 -+++ SDL-1.2.7/src/video/windib/SDL_dibvideo.c Mon Aug 8 18:27:52 2005 -@@ -29,15 +29,26 @@ - #include - #include - #include --#if defined(WIN32_PLATFORM_PSPC) -+#if (defined (UNDER_CE) && (UNDER_CE >= 420)) - #include // Add Pocket PC includes - #pragma comment( lib, "aygshell" ) // Link Pocket PC library - #endif -+ -+#ifdef _MSC_VER -+#pragma warning(disable: 4244) -+#define inline __inline -+#endif -+ - - /* Not yet in the mingw32 cross-compile headers */ - #ifndef CDS_FULLSCREEN - #define CDS_FULLSCREEN 4 - #endif -+ -+#ifndef WS_THICKFRAME -+#define WS_THICKFRAME 0 -+#endif -+ - - #include "SDL.h" - #include "SDL_mutex.h" -@@ -55,7 +66,18 @@ - #ifdef _WIN32_WCE - #define NO_GETDIBITS - #define NO_CHANGEDISPLAYSETTINGS --#define NO_GAMMA_SUPPORT -+#define NO_GAMMA_SUPPORT -+ -+/* uncomment this line if you target WinCE 3.x platform: */ -+//#define NO_SETDIBCOLORTABLE -+ -+/* these 2 variables are used to suport paletted DIBs on WinCE 3.x that -+ does not implement SetDIBColorTable, and when SetDIBColorTable is not working. -+ Slow. DIB is recreated every time. -+*/ -+static BITMAPINFO *last_bitmapinfo; -+static void** last_bits; -+ - #endif - #ifndef WS_MAXIMIZE - #define WS_MAXIMIZE 0 -@@ -96,6 +118,13 @@ - - /* helper fn */ - static int DIB_SussScreenDepth(); -+ -+#ifdef _WIN32_WCE -+void DIB_ShowTaskBar(BOOL taskBarShown); -+#ifdef ENABLE_WINGAPI -+extern void GAPI_GrabHardwareKeys(BOOL grab); -+#endif -+#endif - - /* DIB driver bootstrap functions */ - -@@ -352,6 +381,9 @@ - - /* Fill in some window manager capabilities */ - this->info.wm_available = 1; -+ -+ /* Rotation information */ -+ rotation = SDL_ROTATE_NONE; - - /* We're done! */ - return(0); -@@ -370,7 +402,43 @@ - } - #endif - } -- -+ -+#ifdef _WIN32_WCE -+ -+void DIB_ShowTaskBar(BOOL taskBarShown) { -+#if (UNDER_CE < 420) -+ // Hide taskbar, WinCE 2.x style - from EasyCE -+ HKEY hKey=0; -+ DWORD dwValue = 0; -+ unsigned long lSize = sizeof( DWORD ); -+ DWORD dwType = REG_DWORD; -+ HWND hWnd; -+ -+ RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("\\software\\microsoft\\shell"), 0, KEY_ALL_ACCESS, &hKey ); -+ RegQueryValueEx( hKey, TEXT("TBOpt"), 0, &dwType, (BYTE*)&dwValue, &lSize ); -+ if (taskBarShown) -+ dwValue &= 0xFFFFFFFF - 8; // reset bit to show taskbar -+ else -+ dwValue |= 8; // set bit to hide taskbar -+ RegSetValueEx( hKey, TEXT("TBOpt"), 0, REG_DWORD, (BYTE*)&dwValue, lSize ); -+ hWnd = FindWindow( TEXT("HHTaskBar"), NULL ); -+ SendMessage(hWnd, WM_COMMAND, 0x03EA, 0 ); -+ SetForegroundWindow(SDL_Window); -+#else -+ if (taskBarShown) -+ SHFullScreen(SDL_Window, SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON | SHFS_SHOWSTARTICON); -+ else -+ SHFullScreen(SDL_Window, SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON); -+#endif -+ if (FindWindow(TEXT("HHTaskBar"), NULL)) { // is it valid for HPC ? -+ if (taskBarShown) -+ ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOWNORMAL); -+ else -+ ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE); -+ } -+} -+ -+#endif - - /* - Helper fn to work out which screen depth windows is currently using. -@@ -444,7 +512,8 @@ - - - /* Various screen update functions available */ --static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects); -+static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects); -+static void DIB_RotatedUpdate(_THIS, int numrects, SDL_Rect *rects); - - SDL_Surface *DIB_SetVideoMode(_THIS, SDL_Surface *current, - int width, int height, int bpp, Uint32 flags) -@@ -463,12 +532,20 @@ - HDC hdc; - RECT bounds; - int x, y; -- Uint32 Rmask, Gmask, Bmask; -- -+ Uint32 Rmask, Gmask, Bmask; -+#ifdef _WIN32_CE -+ int screenWidth, screenHeight; -+#endif -+#ifdef UNDER_CE -+ int i; -+#endif -+ -+#ifdef HAVE_OPENGL - /* Clean up any GL context that may be hanging around */ - if ( current->flags & SDL_OPENGL ) { - WIN_GL_ShutDown(this); -- } -+ } -+#endif - - /* Recalculate the bitmasks if necessary */ - if ( bpp == current->format->BitsPerPixel ) { -@@ -517,20 +594,16 @@ - video->h = height; - video->pitch = SDL_CalculatePitch(video); - --#ifdef WIN32_PLATFORM_PSPC -+#ifdef _WIN32_CE - /* Stuff to hide that $#!^%#$ WinCE taskbar in fullscreen... */ - if ( flags & SDL_FULLSCREEN ) { - if ( !(prev_flags & SDL_FULLSCREEN) ) { -- SHFullScreen(SDL_Window, SHFS_HIDETASKBAR); -- SHFullScreen(SDL_Window, SHFS_HIDESIPBUTTON); -- ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE); -+ DIB_ShowTaskBar(FALSE); - } - video->flags |= SDL_FULLSCREEN; - } else { - if ( prev_flags & SDL_FULLSCREEN ) { -- SHFullScreen(SDL_Window, SHFS_SHOWTASKBAR); -- SHFullScreen(SDL_Window, SHFS_SHOWSIPBUTTON); -- ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOWNORMAL); -+ DIB_ShowTaskBar(TRUE); - } - } - #endif -@@ -640,28 +713,82 @@ - ((Uint32*)binfo->bmiColors)[0] = video->format->Rmask; - ((Uint32*)binfo->bmiColors)[1] = video->format->Gmask; - ((Uint32*)binfo->bmiColors)[2] = video->format->Bmask; -- } else { -+ } else { -+#ifdef UNDER_CE -+ binfo->bmiHeader.biCompression = BI_RGB; /* 332 */ -+ if ( video->format->palette ) { -+ binfo->bmiHeader.biClrUsed = video->format->palette->ncolors; -+ for(i=0; iformat->palette->ncolors; i++) -+ { -+ binfo->bmiColors[i].rgbRed=i&(7<<5); -+ binfo->bmiColors[i].rgbGreen=(i&(7<<2))<<3; -+ binfo->bmiColors[i].rgbBlue=(i&3)<<5; -+ binfo->bmiColors[i].rgbReserved=0; -+ } -+ } -+#else - binfo->bmiHeader.biCompression = BI_RGB; /* BI_BITFIELDS for 565 vs 555 */ - if ( video->format->palette ) { - memset(binfo->bmiColors, 0, - video->format->palette->ncolors*sizeof(RGBQUAD)); -- } -+ } -+#endif - } - - /* Create the offscreen bitmap buffer */ -- hdc = GetDC(SDL_Window); -+ hdc = GetDC(SDL_Window); -+#ifdef _WIN32_CE -+ /* See if we need to rotate the buffer (WinCE specific) */ -+ screenWidth = GetDeviceCaps(hdc, HORZRES); -+ screenHeight = GetDeviceCaps(hdc, VERTRES); -+ rotation = SDL_ROTATE_NONE; -+ work_pixels = NULL; -+ if (rotation_pixels) { -+ free(rotation_pixels); -+ rotation_pixels = NULL; -+ } -+ -+ if ((flags & SDL_FULLSCREEN) && (width>height) && (width > screenWidth) ) { -+ /* OK, we rotate the screen */ -+ video->pixels = malloc(video->h * video->pitch); -+ rotation_pixels = video->pixels; -+ if (video->pixels) -+ rotation = SDL_ROTATE_LEFT; -+ OutputDebugString(TEXT("will rotate\r\n")); -+ } -+ screen_bmp = CreateDIBSection(hdc, binfo, DIB_RGB_COLORS, -+ (rotation == SDL_ROTATE_NONE ? (void **)(&video->pixels) : (void**)&work_pixels), NULL, 0); -+#else - screen_bmp = CreateDIBSection(hdc, binfo, DIB_RGB_COLORS, -- (void **)(&video->pixels), NULL, 0); -- ReleaseDC(SDL_Window, hdc); -- free(binfo); -+ (void **)(&video->pixels), NULL, 0); -+#endif -+ ReleaseDC(SDL_Window, hdc); -+#ifdef UNDER_CE -+/* keep bitmapinfo for palette in 8-bit modes for devices that don't have SetDIBColorTable */ -+ last_bits = (rotation == SDL_ROTATE_NONE ? (void **)(&video->pixels) : (void**)&work_pixels); -+ if(last_bitmapinfo) -+ free(last_bitmapinfo); -+ if(is16bitmode) -+ { -+ last_bitmapinfo = 0; -+ free(binfo); -+ } else -+ last_bitmapinfo = binfo; -+#else -+ free(binfo); -+#endif - if ( screen_bmp == NULL ) { - if ( video != current ) { - SDL_FreeSurface(video); - } - SDL_SetError("Couldn't create DIB section"); - return(NULL); -- } -- this->UpdateRects = DIB_NormalUpdate; -+ } -+#ifdef _WIN32_CE -+ this->UpdateRects = (work_pixels ? DIB_RotatedUpdate : DIB_NormalUpdate); -+#else -+ this->UpdateRects = DIB_NormalUpdate; -+#endif - - /* Set video surface flags */ - if ( bpp <= 8 ) { -@@ -695,7 +822,15 @@ - bounds.left = SDL_windowX; - bounds.top = SDL_windowY; - bounds.right = SDL_windowX+video->w; -- bounds.bottom = SDL_windowY+video->h; -+ bounds.bottom = SDL_windowY+video->h; -+#ifdef UNDER_CE -+ if(rotation != SDL_ROTATE_NONE) -+ { -+ int t=bounds.right; -+ bounds.right = bounds.bottom; -+ bounds.bottom=t; -+ } -+#endif - AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), FALSE, 0); - width = bounds.right-bounds.left; - height = bounds.bottom-bounds.top; -@@ -709,8 +844,10 @@ - x = (GetSystemMetrics(SM_CXSCREEN)-width)/2; - y = (GetSystemMetrics(SM_CYSCREEN)-height)/2; - } else { -- x = y = -1; -- swp_flags |= SWP_NOMOVE; -+ x = y = -1; -+#ifndef UNDER_CE -+ swp_flags |= SWP_NOMOVE; -+#endif - } - if ( y < 0 ) { /* Cover up title bar for more client area */ - y -= GetSystemMetrics(SM_CYCAPTION)/2; -@@ -719,19 +856,44 @@ - top = HWND_TOPMOST; - } else { - top = HWND_NOTOPMOST; -- } -- SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags); -+ } -+#ifdef _WIN32_CE -+ if (flags & SDL_FULLSCREEN) { -+/* When WinCE program switches resolution from larger to smaller we should move its window so it would be visible in fullscreen */ -+// SetWindowPos(SDL_Window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); -+ DIB_ShowTaskBar(FALSE); -+ if(x>0) x=0; // remove space from the left side of a screen in 320x200 mode -+ if(y>0) y=0; -+ SetWindowPos(SDL_Window, HWND_TOPMOST, x, y, width, height, SWP_NOCOPYBITS); -+ ShowWindow(SDL_Window, SW_SHOW); -+ } -+ else -+ SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags); -+#else -+ SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags); -+#endif - SDL_resizing = 0; - SetForegroundWindow(SDL_Window); - } - - /* Set up for OpenGL */ -- if ( flags & SDL_OPENGL ) { -+ if ( flags & SDL_OPENGL ) { -+#ifdef HAVE_OPENGL - if ( WIN_GL_SetupWindow(this) < 0 ) { - return(NULL); - } -- video->flags |= SDL_OPENGL; -- } -+ video->flags |= SDL_OPENGL; -+#else -+ return NULL; -+#endif -+ } -+ -+#ifdef ENABLE_WINGAPI -+ /* Grab hardware keys if necessary */ -+ if ( flags & SDL_FULLSCREEN ) { -+ GAPI_GrabHardwareKeys(TRUE); -+ } -+#endif - - /* We're live! */ - return(video); -@@ -754,22 +916,169 @@ - { - return; - } -+ -+#ifdef _WIN32_CE -+ -+static inline void rotateBlit(unsigned short *src, unsigned short *dest, SDL_Rect *rect, int pitch) { -+ int i=rect->w, j=rect->h; -+ src+=i; -+ -+ for (;i--;) { -+ register unsigned short *S=src--; -+// I use loop unrolling to spedup things a little -+ int cnt = j; -+ if(cnt&1) -+ { -+ *(dest++) = *S; -+ S+=pitch; -+ } -+ cnt>>=1; -+ if(cnt&1) -+ { -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ } -+ cnt>>=1; -+ for (; cnt--; ) { -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ } -+ } -+/* tiny optimization -+ int i, j; -+ src+=rect->w; -+ -+ for (i=0; iw; i++) { -+ register unsigned short *S=src--; -+ for (j=0; jh; j++) { -+ *(dest++) = *S; -+ S+=pitch; -+ } -+ } -+*/ -+/* original unoptimized version -+ int i, j; -+ -+ for (i=0; iw; i++) { -+ for (j=0; jh; j++) { -+ dest[i * rect->h + j] = src[pitch * j + (rect->w - i)]; -+ } -+ } -+*/ -+} -+ -+static inline void rotateBlit8(unsigned char *src, unsigned char *dest, SDL_Rect *rect, int pitch) { -+ int i=rect->w, j=rect->h; -+ src+=i; -+ -+ for (;i--;) { -+ register unsigned char *S=src--; -+// I use loop unrolling to spedup things a little -+ int cnt = j; -+ if(cnt&1) -+ { -+ *(dest++) = *S; -+ S+=pitch; -+ } -+ cnt>>=1; -+ if(cnt&1) -+ { -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ } -+ cnt>>=1; -+ for (; cnt--; ) { -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ *(dest++) = *S; -+ S+=pitch; -+ } -+ } -+} -+ -+static void DIB_RotatedUpdate(_THIS, int numrects, SDL_Rect *rects) -+{ -+ HDC hdc, mdc; -+ HBITMAP hb, old; -+ int i; -+ -+ hdc = GetDC(SDL_Window); -+ if ( screen_pal ) { -+ SelectPalette(hdc, screen_pal, FALSE); -+ } -+ mdc = CreateCompatibleDC(hdc); -+ /*SelectObject(mdc, screen_bmp);*/ -+ if(this->screen->format->BytesPerPixel == 2) { -+ for ( i=0; iscreen->pixels; -+ rotateBlit(src + (this->screen->w * rects[i].y) + rects[i].x, work_pixels, &rects[i], this->screen->w); -+ hb = CreateBitmap(rects[i].h, rects[i].w, 1, 16, work_pixels); -+ old = (HBITMAP)SelectObject(mdc, hb); -+ BitBlt(hdc, rects[i].y, this->screen->w - (rects[i].x + rects[i].w), rects[i].h, rects[i].w, -+ mdc, 0, 0, SRCCOPY); -+ SelectObject(mdc, old); -+ DeleteObject(hb); -+ } -+ } else { -+ if ( screen_pal ) { -+ SelectPalette(mdc, screen_pal, FALSE); -+ } -+ for ( i=0; iscreen->pixels; -+ rotateBlit8(src + (this->screen->w * rects[i].y) + rects[i].x, work_pixels, &rects[i], this->screen->w); -+ hb = CreateBitmap(rects[i].h, rects[i].w, 1, 8, work_pixels); -+ old = (HBITMAP)SelectObject(mdc, hb); -+ BitBlt(hdc, rects[i].y, this->screen->w - (rects[i].x + rects[i].w), rects[i].h, rects[i].w, -+ mdc, 0, 0, SRCCOPY); -+ SelectObject(mdc, old); -+ DeleteObject(hb); -+ } -+ } -+ DeleteDC(mdc); -+ ReleaseDC(SDL_Window, hdc); -+} -+#endif -+ - - static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects) - { - HDC hdc, mdc; -- int i; -+ int i; -+#ifdef _WIN32_CE -+ HBITMAP old; -+#endif - - hdc = GetDC(SDL_Window); - if ( screen_pal ) { - SelectPalette(hdc, screen_pal, FALSE); - } -- mdc = CreateCompatibleDC(hdc); -- SelectObject(mdc, screen_bmp); -+ mdc = CreateCompatibleDC(hdc); -+#ifdef _WIN32_CE -+ old = (HBITMAP)SelectObject(mdc, screen_bmp); -+#else -+ SelectObject(mdc, screen_bmp); -+#endif - for ( i=0; ibmiHeader.biClrUsed=256; -+ for ( i=firstcolor; ibmiColors[i]=pal[i]; -+ screen_bmp = CreateDIBSection(hdc, last_bitmapinfo, DIB_RGB_COLORS, -+ last_bits, NULL, 0); -+ } -+#else - SelectObject(mdc, screen_bmp); -- SetDIBColorTable(mdc, firstcolor, ncolors, pal); -+ SetDIBColorTable(mdc, firstcolor, ncolors, pal); -+#endif -+#ifndef UNDER_CE - BitBlt(hdc, 0, 0, this->screen->w, this->screen->h, -- mdc, 0, 0, SRCCOPY); -+ mdc, 0, 0, SRCCOPY); -+#else -+ { -+ SDL_Rect rect; -+ rect.x=0; rect.y=0; -+ rect.w=this->screen->w; rect.h=this->screen->h; -+// Fixme: screen flickers: (this->UpdateRects)(this, 1, &rect) ; -+ } -+#endif - DeleteDC(mdc); --#endif - ReleaseDC(SDL_Window, hdc); - return(1); - } -@@ -937,27 +1270,27 @@ - - void DIB_VideoQuit(_THIS) - { -- /* Destroy the window and everything associated with it */ -+ /* Destroy the window and everything associated with it */ -+#ifdef _WIN32_CE -+ DIB_ShowTaskBar(TRUE); -+#ifdef ENABLE_WINGAPI -+ GAPI_GrabHardwareKeys(FALSE); -+#endif -+#endif - if ( SDL_Window ) { - /* Delete the screen bitmap (also frees screen->pixels) */ - if ( this->screen ) { --#ifdef WIN32_PLATFORM_PSPC -- if ( this->screen->flags & SDL_FULLSCREEN ) { -- /* Unhide taskbar, etc. */ -- SHFullScreen(SDL_Window, SHFS_SHOWTASKBAR); -- SHFullScreen(SDL_Window, SHFS_SHOWSIPBUTTON); -- ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOWNORMAL); -- } --#endif - #ifndef NO_CHANGEDISPLAYSETTINGS - if ( this->screen->flags & SDL_FULLSCREEN ) { - ChangeDisplaySettings(NULL, 0); - ShowWindow(SDL_Window, SW_HIDE); - } --#endif -+#endif -+#ifdef HAVE_OPENGL - if ( this->screen->flags & SDL_OPENGL ) { - WIN_GL_ShutDown(this); -- } -+ } -+#endif - this->screen->pixels = NULL; - } - if ( screen_bmp ) { -diff -ruN SDL-1.2.7-orig/src/video/windib/SDL_dibvideo.h SDL-1.2.7/src/video/windib/SDL_dibvideo.h ---- SDL-1.2.7-orig/src/video/windib/SDL_dibvideo.h Wed Feb 18 09:22:10 2004 -+++ SDL-1.2.7/src/video/windib/SDL_dibvideo.h Thu Nov 18 13:13:42 2004 -@@ -29,11 +29,26 @@ - #define _SDL_dibvideo_h - - #include -+ -+//#ifdef _WIN32_CE -+/* Rotation direction */ -+typedef enum { -+ SDL_ROTATE_NONE, -+ SDL_ROTATE_LEFT, -+ SDL_ROTATE_RIGHT -+} SDL_RotateAttr; -+//#endif - - /* Private display data */ - struct SDL_PrivateVideoData { - HBITMAP screen_bmp; -- HPALETTE screen_pal; -+ HPALETTE screen_pal; -+//#ifdef _WIN32_CE -+ void *work_pixels; /* if the display needs to be rotated, memory allocated by the API */ -+ void *rotation_pixels; /* if the display needs to be rotated, memory allocated by the code */ -+ SDL_RotateAttr rotation; -+ char ozoneHack; /* force stylus translation if running without Hi Res flag */ -+//#endif - - #define NUM_MODELISTS 4 /* 8, 16, 24, and 32 bits-per-pixel */ - int SDL_nummodes[NUM_MODELISTS]; -@@ -43,6 +58,12 @@ - #define screen_bmp (this->hidden->screen_bmp) - #define screen_pal (this->hidden->screen_pal) - #define SDL_nummodes (this->hidden->SDL_nummodes) --#define SDL_modelist (this->hidden->SDL_modelist) -+#define SDL_modelist (this->hidden->SDL_modelist) -+//#ifdef _WIN32_CE -+#define work_pixels (this->hidden->work_pixels) -+#define rotation (this->hidden->rotation) -+#define rotation_pixels (this->hidden->rotation_pixels) -+#define ozoneHack (this->hidden->ozoneHack) -+//#endif - - #endif /* _SDL_dibvideo_h */ -diff -ruN SDL-1.2.7-orig/src/video/wingapi/SDL_gapivideo.c SDL-1.2.7/src/video/wingapi/SDL_gapivideo.c ---- SDL-1.2.7-orig/src/video/wingapi/SDL_gapivideo.c Wed Dec 31 19:00:00 1969 -+++ SDL-1.2.7/src/video/wingapi/SDL_gapivideo.c Thu Nov 18 13:43:27 2004 -@@ -0,0 +1,956 @@ -+/* -+ SDL - Simple DirectMedia Layer -+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga -+ -+ This library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Library General Public -+ License as published by the Free Software Foundation; either -+ version 2 of the License, or (at your option) any later version. -+ -+ This library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Library General Public License for more details. -+ -+ You should have received a copy of the GNU Library General Public -+ License along with this library; if not, write to the Free -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ Sam Lantinga -+ slouken@libsdl.org -+*/ -+ -+#ifdef SAVE_RCSID -+static char rcsid = -+ "@(#) $Id: SDL_gapivideo.c,v 1.5 2004/02/29 21:54:11 lemure Exp $"; -+#endif -+ -+/* Dummy SDL video driver implementation; this is just enough to make an -+ * SDL-based application THINK it's got a working video driver, for -+ * applications that call SDL_Init(SDL_INIT_VIDEO) when they don't need it, -+ * and also for use as a collection of stubs when porting SDL to a new -+ * platform for which you haven't yet written a valid video driver. -+ * -+ * This is also a great way to determine bottlenecks: if you think that SDL -+ * is a performance problem for a given platform, enable this driver, and -+ * then see if your application runs faster without video overhead. -+ * -+ * Initial work by Ryan C. Gordon (icculus@linuxgames.com). A good portion -+ * of this was cut-and-pasted from Stephane Peter's work in the AAlib -+ * SDL video driver. Renamed to "DUMMY" by Sam Lantinga. -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/* Not yet in the mingw32 cross-compile headers */ -+#ifndef CDS_FULLSCREEN -+#define CDS_FULLSCREEN 4 -+#endif -+ -+#ifndef WS_THICKFRAME -+#define WS_THICKFRAME 0 -+#endif -+ -+#include "SDL.h" -+#include "SDL_mutex.h" -+#include "SDL_syswm.h" -+#include "SDL_sysvideo.h" -+#include "SDL_sysevents.h" -+#include "SDL_events_c.h" -+#include "SDL_pixels_c.h" -+#include "SDL_syswm_c.h" -+#include "SDL_sysmouse_c.h" -+#include "SDL_dibevents_c.h" -+#include "SDL_gapivideo.h" -+ -+#if defined(WIN32_PLATFORM_PSPC) -+#include // Add Pocket PC includes -+#pragma comment( lib, "aygshell" ) // Link Pocket PC library -+#endif -+ -+#ifdef _WIN32_WCE -+extern void DIB_ShowTaskBar(BOOL taskBarShown); -+#endif -+ -+ -+/* Initialization/Query functions */ -+static int GAPI_VideoInit(_THIS, SDL_PixelFormat *vformat); -+static SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); -+static SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); -+static int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors); -+static void GAPI_VideoQuit(_THIS); -+ -+ -+/* Hardware surface functions */ -+static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface); -+static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface); -+static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface); -+static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface); -+ -+/* Windows message handling functions, will not be processed */ -+static void GAPI_RealizePalette(_THIS); -+static void GAPI_PaletteChanged(_THIS, HWND window); -+static void GAPI_WinPAINT(_THIS, HDC hdc); -+ -+static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect *rects); -+/*static void GAPI_UpdateRectsMono(_THIS, int numrects, SDL_Rect *rects);*/ -+ -+static int GAPI_Available(void); -+static SDL_VideoDevice *GAPI_CreateDevice(int devindex); -+ -+void GAPI_GrabHardwareKeys(BOOL grab); -+ -+VideoBootStrap WINGAPI_bootstrap = { -+ "wingapi", "WinCE GAPI", -+ GAPI_Available, GAPI_CreateDevice -+}; -+ -+/* 2003 SE GAPI emulation */ -+ -+#define GETRAWFRAMEBUFFER 0x00020001 -+ -+#define FORMAT_565 1 -+#define FORMAT_555 2 -+#define FORMAT_OTHER 3 -+ -+static void* _OzoneFrameBuffer = NULL; -+static struct GXDisplayProperties _OzoneDisplayProperties; -+static char _OzoneAvailable = 0; -+ -+typedef struct _RawFrameBufferInfo -+{ -+ WORD wFormat; -+ WORD wBPP; -+ VOID *pFramePointer; -+ int cxStride; -+ int cyStride; -+ int cxPixels; -+ int cyPixels; -+} RawFrameBufferInfo; -+ -+ -+struct GXDisplayProperties Ozone_GetDisplayProperties(void) { -+ return _OzoneDisplayProperties; -+} -+ -+int Ozone_OpenDisplay(HWND window, unsigned long flag) { -+ return 1; -+} -+ -+int Ozone_CloseDisplay(void) { -+ return 1; -+} -+ -+void* Ozone_BeginDraw(void) { -+ return _OzoneFrameBuffer; -+} -+ -+int Ozone_EndDraw(void) { -+ return 1; -+} -+ -+int Ozone_Suspend(void) { -+ return 1; -+} -+ -+int Ozone_Resume(void) { -+ return 1; -+} -+ -+static HINSTANCE checkOzone(tGXDisplayProperties *gxGetDisplayProperties, tGXOpenDisplay *gxOpenDisplay, -+ tGXVoidFunction *gxCloseDisplay, tGXBeginDraw *gxBeginDraw, -+ tGXVoidFunction *gxEndDraw, tGXVoidFunction *gxSuspend, tGXVoidFunction *gxResume) { -+#ifdef ARM -+ -+ int result; -+ RawFrameBufferInfo frameBufferInfo; -+ HDC hdc = GetDC(NULL); -+ result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *)&frameBufferInfo); -+ ReleaseDC(NULL, hdc); -+ if (result < 0) -+ return NULL; -+ OutputDebugString(TEXT("Running on Ozone\r\n")); -+ _OzoneAvailable = 1; -+ -+ // Initializing global parameters -+ _OzoneFrameBuffer = frameBufferInfo.pFramePointer; -+ _OzoneDisplayProperties.cBPP = frameBufferInfo.wBPP; -+ _OzoneDisplayProperties.cbxPitch = frameBufferInfo.cxStride; -+ _OzoneDisplayProperties.cbyPitch = frameBufferInfo.cyStride; -+ _OzoneDisplayProperties.cxWidth = frameBufferInfo.cxPixels; -+ _OzoneDisplayProperties.cyHeight = frameBufferInfo.cyPixels; -+ if (frameBufferInfo.wFormat == FORMAT_565) -+ _OzoneDisplayProperties.ffFormat = kfDirect565; -+ else -+ if (frameBufferInfo.wFormat == FORMAT_555) -+ _OzoneDisplayProperties.ffFormat = kfDirect555; -+ else { -+ OutputDebugString(TEXT("Ozone unknown screen format")); -+ return NULL; -+ } -+ -+ if (gxGetDisplayProperties) -+ *gxGetDisplayProperties = Ozone_GetDisplayProperties; -+ if (gxOpenDisplay) -+ *gxOpenDisplay = Ozone_OpenDisplay; -+ if (gxCloseDisplay) -+ *gxCloseDisplay = Ozone_CloseDisplay; -+ if (gxBeginDraw) -+ *gxBeginDraw = Ozone_BeginDraw; -+ if (gxEndDraw) -+ *gxEndDraw = Ozone_EndDraw; -+ if (gxSuspend) -+ *gxSuspend = Ozone_Suspend; -+ if (gxResume) -+ *gxResume = Ozone_Resume; -+ -+ return (HINSTANCE)1; -+ -+#else -+ -+ return NULL; -+ -+#endif -+} -+ -+int getScreenWidth() { -+ return (_OzoneFrameBuffer ? _OzoneDisplayProperties.cxWidth : GetSystemMetrics(SM_CXSCREEN)); -+} -+ -+int getScreenHeight() { -+ return (_OzoneFrameBuffer ? _OzoneDisplayProperties.cyHeight : GetSystemMetrics(SM_CYSCREEN)); -+} -+ -+ -+/* Check GAPI library */ -+ -+#define IMPORT(Handle,Variable,Type,Function, Store) \ -+ Variable = GetProcAddress(Handle, TEXT(Function)); \ -+ if (!Variable) { \ -+ FreeLibrary(Handle); \ -+ return NULL; \ -+ } \ -+ if (Store) \ -+ *Store = (Type)Variable; -+ -+static HINSTANCE checkGAPI(tGXDisplayProperties *gxGetDisplayProperties, tGXOpenDisplay *gxOpenDisplay, -+ tGXVoidFunction *gxCloseDisplay, tGXBeginDraw *gxBeginDraw, -+ tGXVoidFunction *gxEndDraw, tGXVoidFunction *gxSuspend, tGXVoidFunction *gxResume, -+ BOOL bypassOzone) { -+ HMODULE gapiLibrary; -+ FARPROC proc; -+ HINSTANCE result; -+ // FIXME paletted ! -+ tGXDisplayProperties temp_gxGetDisplayProperties; -+ -+ // Workaround for Windows Mobile 2003 SE -+ _OzoneFrameBuffer = NULL; -+ if (!bypassOzone) { -+ result = checkOzone(gxGetDisplayProperties, gxOpenDisplay, gxCloseDisplay, gxBeginDraw, gxEndDraw, gxSuspend, gxResume); -+ if (result) -+ return result; -+ } -+ -+ gapiLibrary = LoadLibrary(TEXT("gx.dll")); -+ if (!gapiLibrary) -+ return NULL; -+ -+ IMPORT(gapiLibrary, proc, tGXDisplayProperties, "?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ", gxGetDisplayProperties) -+ IMPORT(gapiLibrary, proc, tGXOpenDisplay, "?GXOpenDisplay@@YAHPAUHWND__@@K@Z", gxOpenDisplay) -+ IMPORT(gapiLibrary, proc, tGXVoidFunction, "?GXCloseDisplay@@YAHXZ", gxCloseDisplay) -+ IMPORT(gapiLibrary, proc, tGXBeginDraw, "?GXBeginDraw@@YAPAXXZ", gxBeginDraw) -+ IMPORT(gapiLibrary, proc, tGXVoidFunction, "?GXEndDraw@@YAHXZ", gxEndDraw) -+ IMPORT(gapiLibrary, proc, tGXVoidFunction, "?GXSuspend@@YAHXZ", gxSuspend) -+ IMPORT(gapiLibrary, proc, tGXVoidFunction, "?GXResume@@YAHXZ", gxResume) -+ -+ // FIXME paletted ! for the moment we just bail out -+ if (!gxGetDisplayProperties) { -+ IMPORT(gapiLibrary, proc, tGXDisplayProperties, "?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ", &temp_gxGetDisplayProperties) -+ if (temp_gxGetDisplayProperties().ffFormat & kfPalette) { -+ FreeLibrary(gapiLibrary); -+ return NULL; -+ } -+ FreeLibrary(gapiLibrary); -+ gapiLibrary = (HINSTANCE)1; -+ } -+ -+ return gapiLibrary; -+} -+ -+ -+/* GAPI driver bootstrap functions */ -+ -+static int GAPI_Available(void) -+{ -+ /* Check if the GAPI library is available */ -+ -+ if (!checkGAPI(NULL, NULL, NULL, NULL, NULL, NULL, NULL, FALSE)) { -+ OutputDebugString(TEXT("GAPI driver not available\r\n")); -+ return 0; -+ } -+ else { -+ OutputDebugString(TEXT("GAPI driver available\r\n")); -+ return 1; -+ } -+} -+ -+static void GAPI_DeleteDevice(SDL_VideoDevice *device) -+{ -+ if (device && device->hidden && device->hidden->gapiFuncs.dynamicGXCloseDisplay) -+ device->hidden->gapiFuncs.dynamicGXCloseDisplay(); -+ -+ if (device && device->hidden) -+ free(device->hidden); -+ if (device) -+ free(device); -+ -+} -+ -+static SDL_VideoDevice *GAPI_CreateDevice(int devindex) -+{ -+ SDL_VideoDevice *device; -+ -+ /* Initialize all variables that we clean on shutdown */ -+ device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice)); -+ if ( device ) { -+ memset(device, 0, (sizeof *device)); -+ device->hidden = (struct SDL_PrivateVideoData *) -+ malloc((sizeof *device->hidden)); -+ } -+ if ( (device == NULL) || (device->hidden == NULL) ) { -+ SDL_OutOfMemory(); -+ if ( device ) { -+ free(device); -+ } -+ return(0); -+ } -+ memset(device->hidden, 0, (sizeof *device->hidden)); -+ -+ /* Set GAPI pointers */ -+ -+ checkGAPI(&device->hidden->gapiFuncs.dynamicGXGetDisplayProperties, -+ &device->hidden->gapiFuncs.dynamicGXOpenDisplay, -+ &device->hidden->gapiFuncs.dynamicGXCloseDisplay, -+ &device->hidden->gapiFuncs.dynamicGXBeginDraw, -+ &device->hidden->gapiFuncs.dynamicGXEndDraw, -+ &device->hidden->gapiFuncs.dynamicGXSuspend, -+ &device->hidden->gapiFuncs.dynamicGXResume, -+ FALSE); -+ device->hidden->displayProps = device->hidden->gapiFuncs.dynamicGXGetDisplayProperties(); -+ -+ /* Set the function pointers */ -+ -+ device->VideoInit = GAPI_VideoInit; -+ device->ListModes = GAPI_ListModes; -+ device->SetVideoMode = GAPI_SetVideoMode; -+ device->UpdateMouse = WIN_UpdateMouse; -+ device->SetColors = GAPI_SetColors; -+ device->UpdateRects = NULL; -+ device->VideoQuit = GAPI_VideoQuit; -+ device->AllocHWSurface = GAPI_AllocHWSurface; -+ device->CheckHWBlit = NULL; -+ device->FillHWRect = NULL; -+ device->SetHWColorKey = NULL; -+ device->SetHWAlpha = NULL; -+ device->LockHWSurface = GAPI_LockHWSurface; -+ device->UnlockHWSurface = GAPI_UnlockHWSurface; -+ device->FlipHWSurface = NULL; -+ device->FreeHWSurface = GAPI_FreeHWSurface; -+ device->SetCaption = WIN_SetWMCaption; -+ device->SetIcon = WIN_SetWMIcon; -+ device->IconifyWindow = WIN_IconifyWindow; -+ device->GrabInput = WIN_GrabInput; -+ device->GetWMInfo = WIN_GetWMInfo; -+ device->FreeWMCursor = WIN_FreeWMCursor; -+ device->CreateWMCursor = WIN_CreateWMCursor; -+ device->ShowWMCursor = WIN_ShowWMCursor; -+ device->WarpWMCursor = WIN_WarpWMCursor; -+ device->CheckMouseMode = WIN_CheckMouseMode; -+ device->InitOSKeymap = DIB_InitOSKeymap; -+ device->PumpEvents = DIB_PumpEvents; -+ -+ device->SetColors = GAPI_SetColors; -+ -+ /* Set up the windows message handling functions */ -+ WIN_RealizePalette = GAPI_RealizePalette; -+ WIN_PaletteChanged = GAPI_PaletteChanged; -+ WIN_WinPAINT = GAPI_WinPAINT; -+ HandleMessage = DIB_HandleMessage; -+ -+ device->free = GAPI_DeleteDevice; -+ -+ -+ /* -+ device->VideoInit = GAPI_VideoInit; -+ device->ListModes = GAPI_ListModes; -+ device->SetVideoMode = GAPI_SetVideoMode; -+ device->CreateYUVOverlay = NULL; -+ device->SetColors = DUMMY_SetColors; -+ device->UpdateRects = DUMMY_UpdateRects; -+ device->VideoQuit = DUMMY_VideoQuit; -+ device->AllocHWSurface = DUMMY_AllocHWSurface; -+ device->CheckHWBlit = NULL; -+ device->FillHWRect = NULL; -+ device->SetHWColorKey = NULL; -+ device->SetHWAlpha = NULL; -+ device->LockHWSurface = DUMMY_LockHWSurface; -+ device->UnlockHWSurface = DUMMY_UnlockHWSurface; -+ device->FlipHWSurface = NULL; -+ device->FreeHWSurface = DUMMY_FreeHWSurface; -+ device->SetCaption = NULL; -+ device->SetIcon = NULL; -+ device->IconifyWindow = NULL; -+ device->GrabInput = NULL; -+ device->GetWMInfo = NULL; -+ device->InitOSKeymap = DUMMY_InitOSKeymap; -+ device->PumpEvents = DUMMY_PumpEvents; -+ -+ device->free = DUMMY_DeleteDevice; -+ */ -+ -+ return device; -+} -+ -+ -+int GAPI_VideoInit(_THIS, SDL_PixelFormat *vformat) -+{ -+ -+ /* Create the window */ -+ if ( DIB_CreateWindow(this) < 0 ) { -+ return(-1); -+ } -+ -+ vformat->BitsPerPixel = (unsigned char)displayProperties.cBPP; -+ -+ // Get color mask -+ if (displayProperties.ffFormat & kfDirect565) { -+ vformat->BitsPerPixel = 16; -+ vformat->Rmask = 0x0000f800; -+ vformat->Gmask = 0x000007e0; -+ vformat->Bmask = 0x0000001f; -+ videoMode = GAPI_DIRECT_565; -+ } -+ else -+ if (displayProperties.ffFormat & kfDirect555) { -+ vformat->BitsPerPixel = 16; -+ vformat->Rmask = 0x00007c00; -+ vformat->Gmask = 0x000003e0; -+ vformat->Bmask = 0x0000001f; -+ videoMode = GAPI_DIRECT_555; -+ } -+ else -+ if ((displayProperties.ffFormat & kfDirect) && (displayProperties.cBPP <= 8)) { -+ // We'll perform the conversion -+ vformat->BitsPerPixel = 24; -+ vformat->Rmask = 0x00ff0000; -+ vformat->Gmask = 0x0000ff00; -+ vformat->Bmask = 0x000000ff; -+ if (displayProperties.ffFormat & kfDirectInverted) -+ invert = (1 << displayProperties.cBPP) - 1; -+ colorscale = displayProperties.cBPP < 8 ? 8 - displayProperties.cBPP : 0; -+ videoMode = GAPI_MONO; -+ } -+ else -+ if (displayProperties.ffFormat & kfPalette) { -+ videoMode = GAPI_PALETTE; -+ } -+ -+ /* Set UpdateRect callback */ -+ // FIXME -+ /* -+ if (videoMode != GAPI_MONO) -+ this->UpdateRects = GAPI_UpdateRects; -+ else -+ this->UpdateRects = GAPI_UpdateRectsMono; -+ */ -+ -+ this->UpdateRects = GAPI_UpdateRects; -+ -+ /* We're done! */ -+ return(0); -+} -+ -+SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) -+{ -+ return (SDL_Rect **) -1; -+} -+ -+SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current, -+ int width, int height, int bpp, Uint32 flags) -+{ -+ SDL_Surface *video; -+ Uint32 Rmask, Gmask, Bmask; -+ Uint32 prev_flags; -+ DWORD style; -+ const DWORD directstyle = -+ (WS_POPUP); -+ const DWORD windowstyle = -+ (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX); -+ const DWORD resizestyle = -+ (WS_THICKFRAME|WS_MAXIMIZEBOX); -+ int screenWidth, screenHeight; -+ BOOL was_visible; -+ -+ /* We negociate legacy GAPI if we want a screen that fits in QVGA */ -+ if (_OzoneAvailable && _OzoneFrameBuffer && (width <= GetSystemMetrics(SM_CXSCREEN) || width <= GetSystemMetrics(SM_CYSCREEN)) && -+ (height <= GetSystemMetrics(SM_CXSCREEN) || height <= GetSystemMetrics(SM_CYSCREEN))) { -+ OutputDebugString(TEXT("Ozone workaround, switching back to GAPI\r\n")); -+ ozoneHack = 0; -+ checkGAPI(&this->hidden->gapiFuncs.dynamicGXGetDisplayProperties, -+ &this->hidden->gapiFuncs.dynamicGXOpenDisplay, -+ &this->hidden->gapiFuncs.dynamicGXCloseDisplay, -+ &this->hidden->gapiFuncs.dynamicGXBeginDraw, -+ &this->hidden->gapiFuncs.dynamicGXEndDraw, -+ &this->hidden->gapiFuncs.dynamicGXSuspend, -+ &this->hidden->gapiFuncs.dynamicGXResume, -+ TRUE); -+ this->hidden->displayProps = this->hidden->gapiFuncs.dynamicGXGetDisplayProperties(); -+ } -+ /* Otherwise we'll use the new system call */ -+ if (_OzoneAvailable && !_OzoneFrameBuffer && (width > GetSystemMetrics(SM_CXSCREEN) && width > GetSystemMetrics(SM_CYSCREEN)) && -+ (height > GetSystemMetrics(SM_CXSCREEN) && height > GetSystemMetrics(SM_CYSCREEN))) { -+ OutputDebugString(TEXT("Ozone workaround, switching back to true Ozone\r\n")); -+ checkGAPI(&this->hidden->gapiFuncs.dynamicGXGetDisplayProperties, -+ &this->hidden->gapiFuncs.dynamicGXOpenDisplay, -+ &this->hidden->gapiFuncs.dynamicGXCloseDisplay, -+ &this->hidden->gapiFuncs.dynamicGXBeginDraw, -+ &this->hidden->gapiFuncs.dynamicGXEndDraw, -+ &this->hidden->gapiFuncs.dynamicGXSuspend, -+ &this->hidden->gapiFuncs.dynamicGXResume, -+ FALSE); -+ this->hidden->displayProps = this->hidden->gapiFuncs.dynamicGXGetDisplayProperties(); -+ } -+ /* Which will need a tiny input hack if the original code does not have the "Hi Res" aware ressource property set */ -+ ozoneHack = 0; -+ if (_OzoneFrameBuffer && (GetSystemMetrics(SM_CXSCREEN) != (signed) _OzoneDisplayProperties.cxWidth || -+ GetSystemMetrics(SM_CYSCREEN) != (signed) _OzoneDisplayProperties.cyHeight)) { -+ OutputDebugString(TEXT("Running true Ozone with stylus hack\r\n")); -+ ozoneHack = 1; -+ } -+ -+ /* See whether or not we should center the window */ -+ was_visible = IsWindowVisible(SDL_Window); -+ -+ /* Recalculate bitmasks if necessary */ -+ if (bpp == current->format->BitsPerPixel) { -+ video = current; -+ } -+ else { -+ switch(bpp) { -+ case 8: -+ Rmask = 0; -+ Gmask = 0; -+ Bmask = 0; -+ break; -+ case 15: -+ case 16: -+ /* Default is 565 unless the display is specifically 555 */ -+ if (displayProperties.ffFormat & kfDirect555) { -+ Rmask = 0x00007c00; -+ Gmask = 0x000003e0; -+ Bmask = 0x0000001f; -+ } -+ else { -+ Rmask = 0x0000f800; -+ Gmask = 0x000007e0; -+ Bmask = 0x0000001f; -+ } -+ break; -+ case 24: -+ case 32: -+ Rmask = 0x00ff0000; -+ Gmask = 0x0000ff00; -+ Bmask = 0x000000ff; -+ break; -+ default: -+ SDL_SetError("Unsupported Bits Per Pixel format requested"); -+ return NULL; -+ } -+ video = SDL_CreateRGBSurface(SDL_SWSURFACE, -+ 0, 0, bpp, Rmask, Gmask, Bmask, 0); -+ if ( video == NULL ) { -+ SDL_OutOfMemory(); -+ return(NULL); -+ } -+ } -+ -+ /* Fill in part of the video surface */ -+ prev_flags = video->flags; -+ video->flags = 0; /* Clear flags */ -+ video->w = width; -+ video->h = height; -+ video->pitch = SDL_CalculatePitch(video); -+ mainSurfaceWidth = width; -+ mainSurfaceHeight = height; -+ -+//#ifdef WIN32_PLATFORM_PSPC -+ /* Hide taskbar */ -+ if ( flags & SDL_FULLSCREEN ) { -+ if ( !(prev_flags & SDL_FULLSCREEN) ) { -+ //SHFullScreen(SDL_Window, SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON); -+ //ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE); -+ DIB_ShowTaskBar(FALSE); -+ } -+ video->flags |= SDL_FULLSCREEN; -+ } else { -+ if ( prev_flags & SDL_FULLSCREEN ) { -+ //SHFullScreen(SDL_Window, SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON | SHFS_SHOWSTARTICON); -+ //ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOWNORMAL); -+ DIB_ShowTaskBar(TRUE); -+ } -+ } -+//#endif -+ -+ /* Reset the palette and create a new one if necessary */ -+ if (screenPal != NULL) { -+ DeleteObject(screenPal); -+ screenPal = NULL; -+ } -+ -+ /* See if we need to create a translation palette */ -+ if (convertPalette != NULL) { -+ free(convertPalette); -+ } -+ if (bpp == 8) { -+ OutputDebugString(TEXT("creating palette\r\n")); -+ convertPalette = (unsigned short*)malloc(256 * sizeof(unsigned short)); -+ } -+ -+ if (displayProperties.ffFormat & kfPalette) { -+ /* Will only be able to support 256 colors in this mode */ -+ // FIXME -+ //screenPal = GAPI_CreatePalette(); -+ } -+ -+ /* Set Window style */ -+ style = GetWindowLong(SDL_Window, GWL_STYLE); -+ if ( (video->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) { -+ style &= ~windowstyle; -+ style |= directstyle; -+ } else { -+ if ( flags & SDL_NOFRAME ) { -+ style &= ~windowstyle; -+ style |= directstyle; -+ video->flags |= SDL_NOFRAME; -+ } else { -+ style &= ~directstyle; -+ style |= windowstyle; -+ if ( flags & SDL_RESIZABLE ) { -+ style |= resizestyle; -+ video->flags |= SDL_RESIZABLE; -+ } -+ } -+#if WS_MAXIMIZE -+ if (IsZoomed(SDL_Window)) style |= WS_MAXIMIZE; -+#endif -+ } -+ -+ if (!SDL_windowid) -+ SetWindowLong(SDL_Window, GWL_STYLE, style); -+ -+ /* Allocate bitmap */ -+ if (gapiBuffer) { -+ free(gapiBuffer); -+ gapiBuffer = NULL; -+ } -+ gapiBuffer = malloc(video->h * video->pitch); -+ video->pixels = gapiBuffer; -+ -+ /* See if we will rotate */ -+ rotation = SDL_ROTATE_NONE; -+ screenWidth = getScreenWidth(); -+ screenHeight = getScreenHeight(); -+ if ((flags & SDL_FULLSCREEN) && -+ (width > screenWidth && width <= screenHeight) -+ ) -+ { -+ rotation = SDL_ROTATE_LEFT; -+ } -+ /* Compute the different drawing properties */ -+ switch(rotation) { -+ case SDL_ROTATE_NONE: -+ dstPixelstep = displayProperties.cbxPitch; -+ dstLinestep = displayProperties.cbyPitch; -+ startOffset = 0; -+ break; -+ case SDL_ROTATE_LEFT: -+ dstPixelstep = -displayProperties.cbyPitch; -+ dstLinestep = displayProperties.cbxPitch; -+ startOffset = displayProperties.cbyPitch * (displayProperties.cyHeight - 1); -+ break; -+ case SDL_ROTATE_RIGHT: -+ dstPixelstep = displayProperties.cbyPitch; -+ dstLinestep = -displayProperties.cbxPitch; -+ startOffset = displayProperties.cbxPitch * (displayProperties.cxWidth - 1); -+ break; -+ } -+ /* Compute padding */ -+ padWidth = 0; -+ padHeight = 0; -+ if (rotation == SDL_ROTATE_NONE) { -+ if (getScreenWidth() > width) -+ padWidth = (getScreenWidth() - width) / 2; -+ if (getScreenHeight() > height) -+ padHeight = (getScreenHeight() - height) / 2; -+ } -+ else { -+ if (getScreenWidth() > height) -+ padWidth = (getScreenWidth() - height) / 2; -+ if (getScreenHeight() > width) -+ padHeight = (getScreenHeight() - width) / 2; -+ } -+ srcLinestep = video->pitch; -+ srcPixelstep = (bpp == 15 ? 2 : bpp / 8); -+ -+ MoveWindow(SDL_Window, 0, 0, getScreenWidth(), getScreenHeight(), FALSE); -+ ShowWindow(SDL_Window, SW_SHOW); -+ -+ /* Resize the window */ -+ //if ( SDL_windowid == NULL ) { -+ if (0) { -+ HWND top; -+ UINT swp_flags; -+ RECT bounds; -+ int x,y; -+ -+ SDL_resizing = 1; -+ bounds.left = 0; -+ bounds.top = 0; -+ bounds.right = video->w; -+ bounds.bottom = video->h; -+ AdjustWindowRectEx(&bounds, GetWindowLong(SDL_Window, GWL_STYLE), FALSE, 0); -+ width = bounds.right-bounds.left; -+ height = bounds.bottom-bounds.top; -+ x = (getScreenWidth()-width)/2; -+ y = (getScreenHeight()-height)/2; -+ if ( y < 0 ) { /* Cover up title bar for more client area */ -+ y -= GetSystemMetrics(SM_CYCAPTION)/2; -+ } -+ swp_flags = (SWP_FRAMECHANGED | SWP_SHOWWINDOW); -+ if ( was_visible && !(flags & SDL_FULLSCREEN) ) { -+ swp_flags |= SWP_NOMOVE; -+ } -+ if ( flags & SDL_FULLSCREEN ) { -+ top = HWND_TOPMOST; -+ } else { -+ top = HWND_NOTOPMOST; -+ } -+ -+ if (flags & SDL_FULLSCREEN) { -+ SetWindowPos(SDL_Window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); -+ ShowWindow(SDL_Window, SW_SHOW); -+ } -+ else -+ SetWindowPos(SDL_Window, top, x, y, width, height, swp_flags); -+ -+ SDL_resizing = 0; -+ SetForegroundWindow(SDL_Window); -+ } -+ -+ /* Open GAPI display */ -+ GXOpenDisplay(SDL_Window, (flags & SDL_FULLSCREEN ? GX_FULLSCREEN : 0)); -+ -+ /* Grab hardware keys if necessary */ -+ if (flags & SDL_FULLSCREEN) -+ GAPI_GrabHardwareKeys(TRUE); -+ -+ /* Blank screen */ -+ memset(GXBeginDraw(), 0, getScreenWidth() * getScreenHeight() * 2); -+ GXEndDraw(); -+ -+ /* We're done */ -+ return(video); -+} -+ -+/* We don't actually allow hardware surfaces other than the main one */ -+static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface) -+{ -+ return(-1); -+} -+static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface) -+{ -+ return; -+} -+ -+/* We need to wait for vertical retrace on page flipped displays */ -+static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface) -+{ -+ return(0); -+} -+ -+static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface) -+{ -+ return; -+} -+ -+static void updateLine(_THIS, unsigned char *srcPointer, unsigned char *destPointer, int width) { -+ // FIXME, we assume everything is in the correct format, either 16 bits 565 or 555, or 8 bits -+ int i; -+ for (i=0; i= 8) \ -+ { \ -+ bitshift = 0; \ -+ bitmask = (1<>= displayProperties.cBPP; -+ -+ -+static void GAPI_UpdateRectsMono(_THIS, int numrects, SDL_Rect *rects) -+{ -+ int i; -+ unsigned char *screenBuffer; -+ -+ screenBuffer = GXBeginDraw(); -+ -+ for (i=0; i>3)) -+ -+#define COLORCONV555(r,g,b) (((r&0xf8)<<(10-3))|((g&0xf8)<<(5-2))|((b&0xf8)>>3)) -+ -+int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) -+{ -+ int i; -+ /* Convert colors to appropriate 565 or 555 mapping */ -+ for (i=0; ipixels) */ -+ if ( this->screen ) { -+//#ifdef WIN32_PLATFORM_PSPC -+ if ( this->screen->flags & SDL_FULLSCREEN ) { -+ /* Unhide taskbar, etc. */ -+ //SHFullScreen(SDL_Window, SHFS_SHOWTASKBAR | SHFS_SHOWSIPBUTTON | SHFS_SHOWSTARTICON); -+ //ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOWNORMAL); -+ DIB_ShowTaskBar(TRUE); -+ GAPI_GrabHardwareKeys(FALSE); -+ } -+//#endif -+ -+ if (this->screen->pixels != NULL) -+ { -+ free(this->screen->pixels); -+ this->screen->pixels = NULL; -+ } -+ -+ if (GXCloseDisplay) -+ GXCloseDisplay(); -+ } -+ } -+} -+ -+void GAPI_GrabHardwareKeys(BOOL grab) { -+ HINSTANCE GAPI_handle; -+ tGXVoidFunction GAPIActionInput; -+ -+ GAPI_handle = LoadLibrary(TEXT("gx.dll")); -+ if (!GAPI_handle) -+ return; -+ GAPIActionInput = (tGXVoidFunction)GetProcAddress(GAPI_handle, (grab ? TEXT("?GXOpenInput@@YAHXZ") : TEXT("?GXCloseInput@@YAHXZ"))); -+ if (GAPIActionInput) { -+ GAPIActionInput(); -+ } -+ FreeLibrary(GAPI_handle); -+} -diff -ruN SDL-1.2.7-orig/src/video/wingapi/SDL_gapivideo.h SDL-1.2.7/src/video/wingapi/SDL_gapivideo.h ---- SDL-1.2.7-orig/src/video/wingapi/SDL_gapivideo.h Wed Dec 31 19:00:00 1969 -+++ SDL-1.2.7/src/video/wingapi/SDL_gapivideo.h Sun May 30 17:57:48 2004 -@@ -0,0 +1,192 @@ -+/* -+ SDL - Simple DirectMedia Layer -+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga -+ -+ This library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Library General Public -+ License as published by the Free Software Foundation; either -+ version 2 of the License, or (at your option) any later version. -+ -+ This library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Library General Public License for more details. -+ -+ You should have received a copy of the GNU Library General Public -+ License along with this library; if not, write to the Free -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ Sam Lantinga -+ slouken@libsdl.org -+*/ -+ -+#ifdef SAVE_RCSID -+static char rcsid = -+ "@(#) $Id: SDL_gapivideo.h,v 1.1 2004/02/02 23:25:35 lemure Exp $"; -+#endif -+ -+#ifndef _SDL_gapivideo_h -+#define _SDL_gapivideo_h -+ -+#include -+ -+/* -------------------------------------------------------------------------------------------- */ -+ -+/* From gx.h, since it's not really C compliant */ -+ -+struct GXDisplayProperties { -+ DWORD cxWidth; -+ DWORD cyHeight; // notice lack of 'th' in the word height. -+ long cbxPitch; // number of bytes to move right one x pixel - can be negative. -+ long cbyPitch; // number of bytes to move down one y pixel - can be negative. -+ long cBPP; // # of bits in each pixel -+ DWORD ffFormat; // format flags. -+}; -+ -+struct GXKeyList { -+ short vkUp; // key for up -+ POINT ptUp; // x,y position of key/button. Not on screen but in screen coordinates. -+ short vkDown; -+ POINT ptDown; -+ short vkLeft; -+ POINT ptLeft; -+ short vkRight; -+ POINT ptRight; -+ short vkA; -+ POINT ptA; -+ short vkB; -+ POINT ptB; -+ short vkC; -+ POINT ptC; -+ short vkStart; -+ POINT ptStart; -+}; -+ -+#define kfLandscape 0x8 // Screen is rotated 270 degrees -+#define kfPalette 0x10 // Pixel values are indexes into a palette -+#define kfDirect 0x20 // Pixel values contain actual level information -+#define kfDirect555 0x40 // 5 bits each for red, green and blue values in a pixel. -+#define kfDirect565 0x80 // 5 red bits, 6 green bits and 5 blue bits per pixel -+#define kfDirect888 0x100 // 8 bits each for red, green and blue values in a pixel. -+#define kfDirect444 0x200 // 4 red, 4 green, 4 blue -+#define kfDirectInverted 0x400 -+ -+#define GX_FULLSCREEN 0x01 // for OpenDisplay() -+ -+/* -------------------------------------------------------------------------------------------- */ -+ -+/* Rotation direction */ -+typedef enum { -+ SDL_ROTATE_NONE, -+ SDL_ROTATE_LEFT, -+ SDL_ROTATE_RIGHT -+} SDL_RotateAttr; -+ -+/* GAPI video mode */ -+typedef enum { -+ GAPI_NONE = 0, -+ GAPI_DIRECT_565, -+ GAPI_DIRECT_555, -+ GAPI_MONO, -+ GAPI_PALETTE -+} SDL_GAPIVideoMode; -+ -+ -+/* Hidden "this" pointer for the video functions */ -+#define _THIS SDL_VideoDevice *this -+ -+/* GAPI functions definitions */ -+ -+typedef struct GXDisplayProperties (*tGXDisplayProperties)(void); -+typedef int (*tGXOpenDisplay)(HWND, unsigned long); -+typedef void* (*tGXBeginDraw)(void); -+typedef int (*tGXVoidFunction)(void); -+ -+/* Private display data */ -+ -+struct GAPI_funcs { -+ tGXDisplayProperties dynamicGXGetDisplayProperties; -+ tGXOpenDisplay dynamicGXOpenDisplay; -+ tGXVoidFunction dynamicGXCloseDisplay; -+ tGXBeginDraw dynamicGXBeginDraw; -+ tGXVoidFunction dynamicGXEndDraw; -+ tGXVoidFunction dynamicGXSuspend; -+ tGXVoidFunction dynamicGXResume; -+}; -+ -+struct GAPI_properties { -+ unsigned char invert; -+ int colorscale; -+ int dstPixelstep; -+ int dstLinestep; -+ int startOffset; -+ SDL_GAPIVideoMode videoMode; -+}; -+ -+#define MAX_CLR 0x100 -+ -+struct palette_properties { -+ unsigned char *palRed; -+ unsigned char *palGreen; -+ unsigned char *palBlue; -+ unsigned short *pal; -+}; -+ -+ -+struct SDL_PrivateVideoData { -+ /* --- --- begin with DIB private structure to allow DIB events code sharing */ -+ HBITMAP screen_bmp; -+ HPALETTE screen_pal; -+ void *work_pixels; /* if the display needs to be rotated, memory allocated by the API */ -+ void *rotation_pixels; /* if the display needs to be rotated, memory allocated by the code */ -+ SDL_RotateAttr rotation; -+ char ozoneHack; /* force stylus translation if running without Hi Res flag */ -+ -+#define NUM_MODELISTS 4 /* 8, 16, 24, and 32 bits-per-pixel */ -+ int SDL_nummodes[NUM_MODELISTS]; -+ SDL_Rect **SDL_modelist[NUM_MODELISTS]; -+ -+ /* --- --- */ -+ -+ int w, h; -+ void *gapiBuffer; -+ HPALETTE screenPal; -+ struct GAPI_funcs gapiFuncs; -+ struct GAPI_properties gapiProperties; -+ struct GXDisplayProperties displayProps; -+ int srcLinestep; -+ int srcPixelstep; -+ -+ int padWidth; -+ int padHeight; -+ -+ unsigned short *convertPalette; -+}; -+ -+#define gapiBuffer (this->hidden->gapiBuffer) -+#define mainSurfaceWidth (this->hidden->w) -+#define mainSurfaceHeight (this->hidden->h) -+#define rotation (this->hidden->rotation) -+#define ozoneHack (this->hidden->ozoneHack) -+#define displayProperties (this->hidden->displayProps) -+#define screenPal (this->hidden->screenPal) -+#define GXGetDisplayProperties (this->hidden->gapiFuncs.dynamicGXGetDisplayProperties) -+#define GXOpenDisplay (this->hidden->gapiFuncs.dynamicGXOpenDisplay) -+#define GXCloseDisplay (this->hidden->gapiFuncs.dynamicGXCloseDisplay) -+#define GXBeginDraw (this->hidden->gapiFuncs.dynamicGXBeginDraw) -+#define GXEndDraw (this->hidden->gapiFuncs.dynamicGXEndDraw) -+#define GXSuspend (this->hidden->gapiFuncs.dynamicGXSuspend) -+#define GXResume (this->hidden->gapiFuncs.dynamicGXResume) -+#define invert (this->hidden->gapiProperties.invert) -+#define colorscale (this->hidden->gapiProperties.colorscale) -+#define videoMode (this->hidden->gapiProperties.videoMode) -+#define srcPixelstep (this->hidden->srcPixelstep) -+#define srcLinestep (this->hidden->srcLinestep) -+#define dstPixelstep (this->hidden->gapiProperties.dstPixelstep) -+#define dstLinestep (this->hidden->gapiProperties.dstLinestep) -+#define startOffset (this->hidden->gapiProperties.startOffset) -+#define padWidth (this->hidden->padWidth) -+#define padHeight (this->hidden->padHeight) -+#define convertPalette (this->hidden->convertPalette) -+ -+#endif /* _SDL_gapivideo_h */ diff --git a/tools/SDL1.2.7_CE/VisualCEv2.zip b/tools/SDL1.2.7_CE/VisualCEv2.zip deleted file mode 100644 index 816382e3b..000000000 Binary files a/tools/SDL1.2.7_CE/VisualCEv2.zip and /dev/null differ diff --git a/tools/SOCEdit/Global.bas b/tools/SOCEdit/Global.bas deleted file mode 100644 index 77bf3df2b..000000000 --- a/tools/SOCEdit/Global.bas +++ /dev/null @@ -1,96 +0,0 @@ -Attribute VB_Name = "Module1" -Option Explicit -Public SOCFile As String -Public SOCTemp As String -Public SourcePath As String - -Public Function FirstToken(ByVal line As String) - Dim index As Integer - - index = InStr(line, " ") - 1 - - If index < 1 Then - index = Len(line) - End If - - FirstToken = TrimComplete(Left(line, index)) -End Function - -Public Function SecondToken(ByVal line As String) - Dim startclip As Integer - Dim endclip As Integer - - startclip = InStr(line, " ") - - startclip = startclip + 1 - - SecondToken = TrimComplete(Mid(line, startclip, Len(line))) -End Function - -Public Function SecondTokenEqual(ByVal line As String) - Dim startclip As Integer - Dim endclip As Integer - - startclip = InStr(line, "=") - - startclip = startclip + 2 - - line = Mid(line, startclip, Len(line)) - - SecondTokenEqual = TrimComplete(line) -End Function - -Public Function TrimComplete(ByVal sValue As String) As String - Dim sAns As String - Dim sWkg As String - Dim sChar As String - Dim lLen As Long - Dim lCtr As Long - - sAns = sValue - lLen = Len(sValue) - - If lLen > 0 Then - 'Ltrim - For lCtr = 1 To lLen - sChar = Mid(sAns, lCtr, 1) - If Asc(sChar) > 32 Then Exit For - Next - - sAns = Mid(sAns, lCtr) - lLen = Len(sAns) - - 'Rtrim - If lLen > 0 Then - For lCtr = lLen To 1 Step -1 - sChar = Mid(sAns, lCtr, 1) - If Asc(sChar) > 32 Then Exit For - Next - End If - sAns = Left$(sAns, lCtr) - End If - - TrimComplete = sAns -End Function - -Public Function RTrimComplete(ByVal sValue As String) As String - Dim sAns As String - Dim sWkg As String - Dim sChar As String - Dim lLen As Long - Dim lCtr As Long - - sAns = sValue - lLen = Len(sValue) - - 'Rtrim - If lLen > 0 Then - For lCtr = lLen To 1 Step -1 - sChar = Mid(sAns, lCtr, 1) - If Asc(sChar) > 32 Then Exit For - Next - End If - sAns = Left$(sAns, lCtr) - - RTrimComplete = sAns -End Function diff --git a/tools/SOCEdit/SOCEdit.vbp b/tools/SOCEdit/SOCEdit.vbp deleted file mode 100644 index 90af0095a..000000000 --- a/tools/SOCEdit/SOCEdit.vbp +++ /dev/null @@ -1,53 +0,0 @@ -Type=Exe -Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\WINNT\system32\stdole2.tlb#OLE Automation -Reference=*\G{420B2830-E718-11CF-893D-00A0C9054228}#1.0#0#..\..\..\WINNT\system32\scrrun.dll#Microsoft Scripting Runtime -Form=Things.frm -Module=Module1; Global.bas -Form=frmStateEdit.frm -Form=frmLevelHeader.frm -Form=frmHub.frm -Form=frmMaincfg.frm -Form=frmUnlockablesEdit.frm -Form=frmEmblemEdit.frm -Form=frmSoundEdit.frm -Form=frmCharacterEdit.frm -Form=frmCutsceneEdit.frm -Form=frmHelp.frm -Form=frmHUDEdit.frm -IconForm="frmThingEdit" -Startup="frmHub" -HelpFile="" -Title="SOC Editor" -ExeName32="SOCEdit.exe" -Path32="..\..\..\srb2demo2\SOCEdit" -Command32="" -Name="SOCEditor" -HelpContextID="0" -CompatibleMode="0" -MajorVer=0 -MinorVer=7 -RevisionVer=7 -AutoIncrementVer=0 -ServerSupportFiles=0 -VersionComments="http://www.srb2.org/" -VersionCompanyName="Sonic Team Junior" -VersionFileDescription="For SRB2 v1.09.4" -CompilationType=0 -OptimizationType=0 -FavorPentiumPro(tm)=0 -CodeViewDebugInfo=0 -NoAliasing=0 -BoundsCheck=0 -OverflowCheck=0 -FlPointCheck=0 -FDIVCheck=0 -UnroundedFP=0 -StartMode=0 -Unattended=0 -Retained=0 -ThreadPerObject=0 -MaxNumberOfThreads=1 -DebugStartupOption=0 - -[MS Transaction Server] -AutoRefresh=1 diff --git a/tools/SOCEdit/Things.frm b/tools/SOCEdit/Things.frm deleted file mode 100644 index f95b6afb7..000000000 --- a/tools/SOCEdit/Things.frm +++ /dev/null @@ -1,1895 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmThingEdit - Caption = "Thing Edit" - ClientHeight = 5745 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 11880 - Icon = "Things.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 5745 - ScaleWidth = 11880 - StartUpPosition = 3 'Windows Default - Begin VB.CommandButton cmdCopy - Caption = "&Copy Thing" - Height = 615 - Left = 6600 - TabIndex = 77 - Top = 4920 - Width = 975 - End - Begin VB.CommandButton cmdLoadDefault - Caption = "&Load Code Default" - Height = 615 - Left = 4440 - Style = 1 'Graphical - TabIndex = 76 - Top = 4920 - Width = 975 - End - Begin VB.CommandButton cmdDelete - Caption = "&Delete Thing from SOC" - Height = 615 - Left = 3240 - Style = 1 'Graphical - TabIndex = 74 - Top = 4920 - Width = 1095 - End - Begin VB.CommandButton cmdSave - Caption = "&Save" - Height = 615 - Left = 5520 - TabIndex = 73 - Top = 4920 - Width = 975 - End - Begin VB.Frame frmFlags - Caption = "Flags" - Height = 3735 - Left = 7680 - TabIndex = 45 - Top = 1920 - Width = 4095 - Begin VB.CheckBox chkFlags - Caption = "MF_FIRE" - Height = 255 - Index = 26 - Left = 2040 - TabIndex = 72 - Tag = "4194304" - ToolTipText = "Fire object. Doesn't harm if you have red shield." - Top = 2160 - Width = 1695 - End - Begin VB.CheckBox chkFlags - Caption = "MF_NOCLIPTHING" - Height = 255 - Index = 25 - Left = 2040 - TabIndex = 71 - Tag = "1073741824" - ToolTipText = "Don't be blocked by things (partial clipping)" - Top = 3120 - Width = 1815 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SCENERY" - Height = 255 - Index = 24 - Left = 2040 - TabIndex = 70 - Tag = "33554432" - ToolTipText = "Scenery (uses scenery thinker). Uses less CPU than a standard object, but generally can't move, etc." - Top = 2880 - Width = 1455 - End - Begin VB.CheckBox chkFlags - Caption = "MF_ENEMY" - Height = 255 - Index = 23 - Left = 2040 - TabIndex = 69 - Tag = "16777216" - ToolTipText = "This mobj is an enemy!" - Top = 2640 - Width = 1335 - End - Begin VB.CheckBox chkFlags - Caption = "MF_COUNTITEM" - Height = 255 - Index = 22 - Left = 2040 - TabIndex = 68 - Tag = "8388608" - ToolTipText = "On picking up, count this item object towards intermission item total." - Top = 2400 - Width = 1695 - End - Begin VB.CheckBox chkFlags - Caption = "MF_NOTHINK" - Height = 255 - Index = 21 - Left = 2040 - TabIndex = 67 - Tag = "2097152" - ToolTipText = "Don't run this thing's thinker." - Top = 1920 - Width = 1695 - End - Begin VB.CheckBox chkFlags - Caption = "MF_MONITOR" - Height = 255 - Index = 20 - Left = 2040 - TabIndex = 66 - Tag = "1048576" - ToolTipText = "Item box" - Top = 1680 - Width = 1575 - End - Begin VB.CheckBox chkFlags - Caption = "MF_HIRES" - Height = 255 - Index = 19 - Left = 2040 - TabIndex = 65 - Tag = "524288" - ToolTipText = "Object uses a high-resolution sprite" - Top = 1440 - Width = 1215 - End - Begin VB.CheckBox chkFlags - Caption = "MF_BOUNCE" - Height = 255 - Index = 18 - Left = 2040 - TabIndex = 64 - Tag = "262144" - ToolTipText = "Bounce off walls and things." - Top = 1200 - Width = 1335 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SPRING" - Height = 255 - Index = 17 - Left = 2040 - TabIndex = 63 - Tag = "131072" - ToolTipText = "Item is a spring." - Top = 960 - Width = 1575 - End - Begin VB.CheckBox chkFlags - Caption = "MF_MISSILE" - Height = 255 - Index = 16 - Left = 2040 - TabIndex = 62 - Tag = "65536" - ToolTipText = "Any kind of projectile currently flying through the air, waiting to hit something" - Top = 720 - Width = 1335 - End - Begin VB.CheckBox chkFlags - Caption = "MF_BOXICON" - Height = 255 - Index = 15 - Left = 2040 - TabIndex = 61 - Tag = "32768" - ToolTipText = "Monitor powerup icon. These rise a bit." - Top = 480 - Width = 1815 - End - Begin VB.CheckBox chkFlags - Caption = "MF_FLOAT" - Height = 255 - Index = 14 - Left = 2040 - TabIndex = 60 - Tag = "16384" - ToolTipText = "Allow moves to any height, no gravity. For active floaters." - Top = 240 - Width = 1215 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SPECIALFLAGS" - Height = 255 - Index = 13 - Left = 120 - TabIndex = 59 - Tag = "8192" - ToolTipText = "This object does not adhere to regular flag/z properties for object placing." - Top = 3360 - Width = 1815 - End - Begin VB.CheckBox chkFlags - Caption = "MF_NOCLIP" - Height = 255 - Index = 12 - Left = 120 - TabIndex = 58 - Tag = "4096" - ToolTipText = "Don't clip against objects, walls, etc." - Top = 3120 - Width = 1335 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SLIDEME" - Height = 255 - Index = 11 - Left = 120 - TabIndex = 57 - Tag = "2048" - ToolTipText = "Slide this object when it hits a wall." - Top = 2880 - Width = 1335 - End - Begin VB.CheckBox chkFlags - Caption = "MF_AMBIENT" - Height = 255 - Index = 10 - Left = 120 - TabIndex = 56 - Tag = "1024" - ToolTipText = "This object is an ambient sound." - Top = 2640 - Width = 1695 - End - Begin VB.CheckBox chkFlags - Caption = "MF_NOGRAVITY" - Height = 255 - Index = 9 - Left = 120 - TabIndex = 55 - Tag = "512" - ToolTipText = "Don't apply gravity" - Top = 2400 - Width = 1695 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SPAWNCEILING" - Height = 255 - Index = 8 - Left = 120 - TabIndex = 54 - Tag = "256" - ToolTipText = "On level spawning (initial position), hang from ceiling instead of stand on floor." - Top = 2160 - Width = 1935 - End - Begin VB.CheckBox chkFlags - Caption = "MF_BOSS" - Height = 255 - Index = 7 - Left = 120 - TabIndex = 53 - Tag = "128" - ToolTipText = "Object is a boss." - Top = 1920 - Width = 1575 - End - Begin VB.CheckBox chkFlags - Caption = "MF_PUSHABLE" - Height = 255 - Index = 6 - Left = 120 - TabIndex = 52 - Tag = "64" - ToolTipText = "You can push this object. It can activate switches and things by pushing it on top." - Top = 1680 - Width = 1575 - End - Begin VB.CheckBox chkFlags - Caption = "MF_AMBUSH" - Height = 255 - Index = 5 - Left = 120 - TabIndex = 51 - Tag = "32" - ToolTipText = "Special attributes" - Top = 1440 - Width = 1455 - End - Begin VB.CheckBox chkFlags - Caption = "MF_NOBLOCKMAP" - Height = 255 - Index = 4 - Left = 120 - TabIndex = 50 - Tag = "16" - ToolTipText = "Don't use the blocklinks (inert but displayable)" - Top = 1200 - Width = 1815 - End - Begin VB.CheckBox chkFlags - Caption = "MF_NOSECTOR" - Height = 255 - Index = 3 - Left = 120 - TabIndex = 49 - Tag = "8" - ToolTipText = "Don't use the sector links (invisible but touchable)." - Top = 960 - Width = 1575 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SHOOTABLE" - Height = 255 - Index = 2 - Left = 120 - TabIndex = 48 - Tag = "4" - ToolTipText = "Can be hit." - Top = 720 - Width = 1695 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SOLID" - Height = 255 - Index = 1 - Left = 120 - TabIndex = 47 - Tag = "2" - ToolTipText = "Blocks." - Top = 480 - Width = 1335 - End - Begin VB.CheckBox chkFlags - Caption = "MF_SPECIAL" - Height = 255 - Index = 0 - Left = 120 - TabIndex = 46 - Tag = "1" - ToolTipText = "Call P_TouchSpecialThing when touched." - Top = 240 - Width = 1455 - End - End - Begin VB.ComboBox cmbRaisestate - Height = 315 - Left = 4320 - TabIndex = 43 - Text = "cmbRaisestate" - Top = 4440 - Width = 3300 - End - Begin VB.ComboBox cmbActivesound - Height = 315 - Left = 4320 - TabIndex = 41 - Text = "cmbActivesound" - Top = 4080 - Width = 3300 - End - Begin VB.TextBox txtDamage - Height = 285 - Left = 10680 - TabIndex = 39 - Text = "0" - Top = 1200 - Width = 1095 - End - Begin VB.TextBox txtMass - Height = 285 - Left = 10680 - TabIndex = 37 - Text = "0" - Top = 840 - Width = 1095 - End - Begin VB.TextBox txtHeight - Height = 285 - Left = 10680 - TabIndex = 35 - Text = "0" - Top = 480 - Width = 1095 - End - Begin VB.TextBox txtRadius - Height = 285 - Left = 10680 - TabIndex = 33 - Text = "0" - Top = 120 - Width = 1095 - End - Begin VB.TextBox txtSpeed - Height = 285 - Left = 8760 - TabIndex = 31 - Text = "0" - Top = 1560 - Width = 1095 - End - Begin VB.ComboBox cmbDeathsound - Height = 315 - Left = 4320 - TabIndex = 29 - Text = "cmbDeathsound" - Top = 3720 - Width = 3300 - End - Begin VB.ComboBox cmbXdeathstate - Height = 315 - Left = 4320 - TabIndex = 27 - Text = "cmbXdeathstate" - Top = 3360 - Width = 3300 - End - Begin VB.ComboBox cmbDeathstate - Height = 315 - Left = 4320 - TabIndex = 25 - Text = "cmbDeathstate" - Top = 3000 - Width = 3300 - End - Begin VB.ComboBox cmbMissilestate - Height = 315 - Left = 4320 - TabIndex = 23 - Text = "cmbMissilestate" - Top = 2640 - Width = 3300 - End - Begin VB.ComboBox cmbMeleestate - Height = 315 - Left = 4320 - TabIndex = 21 - Text = "cmbMeleestate" - Top = 2280 - Width = 3300 - End - Begin VB.ComboBox cmbPainsound - Height = 315 - Left = 4320 - TabIndex = 19 - Text = "cmbPainsound" - Top = 1920 - Width = 3300 - End - Begin VB.TextBox txtPainchance - Height = 285 - Left = 8760 - TabIndex = 17 - Text = "0" - Top = 1200 - Width = 1095 - End - Begin VB.ComboBox cmbPainstate - Height = 315 - Left = 4320 - TabIndex = 15 - Text = "cmbPainstate" - Top = 1560 - Width = 3300 - End - Begin VB.ComboBox cmbAttacksound - Height = 315 - Left = 4320 - TabIndex = 13 - Text = "cmbAttacksound" - Top = 1200 - Width = 3300 - End - Begin VB.TextBox txtReactiontime - Height = 285 - Left = 8760 - TabIndex = 11 - Text = "0" - Top = 840 - Width = 1095 - End - Begin VB.ComboBox cmbSeesound - Height = 315 - Left = 4320 - TabIndex = 9 - Text = "cmbSeesound" - Top = 840 - Width = 3300 - End - Begin VB.ComboBox cmbSeestate - Height = 315 - Left = 4320 - TabIndex = 7 - Text = "cmbSeestate" - Top = 480 - Width = 3300 - End - Begin VB.TextBox txtSpawnhealth - Height = 285 - Left = 8760 - TabIndex = 6 - Text = "0" - Top = 480 - Width = 1095 - End - Begin VB.ComboBox cmbSpawnstate - Height = 315 - Left = 4320 - TabIndex = 3 - Text = "cmbSpawnstate" - Top = 120 - Width = 3300 - End - Begin VB.TextBox txtDoomednum - Height = 285 - Left = 8760 - TabIndex = 1 - Text = "0" - Top = 120 - Width = 1095 - End - Begin VB.ListBox lstThings - Height = 5520 - ItemData = "Things.frx":0442 - Left = 120 - List = "Things.frx":0444 - TabIndex = 0 - Top = 120 - Width = 3015 - End - Begin VB.Label lblStatusInfo - Alignment = 2 'Center - Caption = "Idle" - BeginProperty Font - Name = "MS Sans Serif" - Size = 8.25 - Charset = 0 - Weight = 700 - Underline = 0 'False - Italic = 0 'False - Strikethrough = 0 'False - EndProperty - Height = 375 - Left = 9960 - TabIndex = 75 - Top = 1560 - Width = 1815 - End - Begin VB.Label lblRaisestate - Alignment = 1 'Right Justify - Caption = "Raisestate:" - Height = 255 - Left = 3360 - TabIndex = 44 - Top = 4440 - Width = 855 - End - Begin VB.Label lblActivesound - Alignment = 1 'Right Justify - Caption = "Activesound:" - Height = 255 - Left = 3240 - TabIndex = 42 - Top = 4080 - Width = 975 - End - Begin VB.Label lblDamage - Alignment = 1 'Right Justify - Caption = "Damage:" - Height = 255 - Left = 9840 - TabIndex = 40 - Top = 1200 - Width = 735 - End - Begin VB.Label lblMass - Alignment = 1 'Right Justify - Caption = "Mass:" - Height = 255 - Left = 9960 - TabIndex = 38 - Top = 840 - Width = 615 - End - Begin VB.Label lblHeight - Alignment = 1 'Right Justify - Caption = "Height:" - Height = 255 - Left = 9960 - TabIndex = 36 - Top = 480 - Width = 615 - End - Begin VB.Label lblRadius - Alignment = 1 'Right Justify - Caption = "Radius:" - Height = 255 - Left = 9960 - TabIndex = 34 - Top = 120 - Width = 615 - End - Begin VB.Label lblSpeed - Alignment = 1 'Right Justify - Caption = "Speed:" - Height = 255 - Left = 7680 - TabIndex = 32 - Top = 1560 - Width = 975 - End - Begin VB.Label lblDeathsound - Alignment = 1 'Right Justify - Caption = "Deathsound:" - Height = 255 - Left = 3240 - TabIndex = 30 - Top = 3720 - Width = 975 - End - Begin VB.Label lblXdeathstate - Alignment = 1 'Right Justify - Caption = "Xdeathstate:" - Height = 255 - Left = 3240 - TabIndex = 28 - Top = 3360 - Width = 975 - End - Begin VB.Label lblDeathstate - Alignment = 1 'Right Justify - Caption = "Deathstate:" - Height = 255 - Left = 3240 - TabIndex = 26 - Top = 3000 - Width = 975 - End - Begin VB.Label lblMissilestate - Alignment = 1 'Right Justify - Caption = "Missilestate:" - Height = 255 - Left = 3240 - TabIndex = 24 - Top = 2640 - Width = 975 - End - Begin VB.Label lblMeleestate - Alignment = 1 'Right Justify - Caption = "Meleestate:" - Height = 255 - Left = 3240 - TabIndex = 22 - Top = 2280 - Width = 975 - End - Begin VB.Label lblPainsound - Alignment = 1 'Right Justify - Caption = "Painsound:" - Height = 255 - Left = 3240 - TabIndex = 20 - Top = 1920 - Width = 975 - End - Begin VB.Label lblPainchance - Alignment = 1 'Right Justify - Caption = "Painchance:" - Height = 255 - Left = 7680 - TabIndex = 18 - Top = 1200 - Width = 975 - End - Begin VB.Label lblPainstate - Alignment = 1 'Right Justify - Caption = "Painstate:" - Height = 255 - Left = 3240 - TabIndex = 16 - Top = 1560 - Width = 975 - End - Begin VB.Label lblAttacksound - Alignment = 1 'Right Justify - Caption = "Attacksound:" - Height = 255 - Left = 3240 - TabIndex = 14 - Top = 1200 - Width = 975 - End - Begin VB.Label lblReactiontime - Alignment = 1 'Right Justify - Caption = "Reactiontime:" - Height = 255 - Left = 7680 - TabIndex = 12 - Top = 840 - Width = 975 - End - Begin VB.Label lblSeesound - Alignment = 1 'Right Justify - Caption = "Seesound:" - Height = 255 - Left = 3240 - TabIndex = 10 - Top = 840 - Width = 975 - End - Begin VB.Label lblSeestate - Alignment = 1 'Right Justify - Caption = "Seestate:" - Height = 255 - Left = 3240 - TabIndex = 8 - Top = 480 - Width = 975 - End - Begin VB.Label lblSpawnhealth - Alignment = 1 'Right Justify - Caption = "Spawnhealth:" - Height = 255 - Left = 7680 - TabIndex = 5 - Top = 480 - Width = 975 - End - Begin VB.Label lblSpawnstate - Alignment = 1 'Right Justify - Caption = "Spawnstate:" - Height = 255 - Left = 3240 - TabIndex = 4 - Top = 120 - Width = 975 - End - Begin VB.Label lblDoomednum - Alignment = 1 'Right Justify - Caption = "Thing Map #:" - Height = 255 - Left = 7680 - TabIndex = 2 - Top = 120 - Width = 975 - End -End -Attribute VB_Name = "frmThingEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdCopy_Click() - Dim Response As String - - Response$ = InputBox("Copy state to #:", "Copy State") - - If Response = "" Then Exit Sub - - Response = TrimComplete(Response) - - Call WriteThing(False, Val(Response)) - - MsgBox "Thing copied to #" & Val(Response) -End Sub - -Private Sub cmdDelete_Click() - Call WriteThing(True, lstThings.ListIndex) -End Sub - -Private Sub cmdLoadDefault_Click() - Call ClearForm - If InStr(lstThings.List(lstThings.ListIndex), "MT_FREESLOT") = 0 Then - LoadObjectInfo (lstThings.ListIndex) - Else - MsgBox "Free slots do not have a code default." - End If -End Sub - -Private Sub cmdSave_Click() - Call WriteThing(False, lstThings.ListIndex) -End Sub - -Private Sub Form_Load() - Call Reload -End Sub - -Private Sub ClearForm() - Dim i As Integer - cmbSpawnstate.Text = "" - cmbSeestate.Text = "" - cmbSeesound.Text = "" - cmbAttacksound.Text = "" - cmbPainstate.Text = "" - cmbPainsound.Text = "" - cmbMeleestate.Text = "" - cmbMissilestate.Text = "" - cmbDeathstate.Text = "" - cmbXdeathstate.Text = "" - cmbDeathsound.Text = "" - cmbActivesound.Text = "" - cmbRaisestate.Text = "" - txtDoomednum.Text = "" - txtSpawnhealth.Text = "" - txtReactiontime.Text = "" - txtPainchance.Text = "" - txtSpeed.Text = "" - txtRadius.Text = "" - txtHeight.Text = "" - txtMass.Text = "" - txtDamage.Text = "" - - For i = 0 To 26 - chkFlags(i).Value = 0 - Next -End Sub - -Private Sub Reload() - lblStatusInfo.Caption = "Loading Sounds Info..." - DoEvents - LoadSounds - lblStatusInfo.Caption = "Loading Things Info..." - DoEvents - LoadThings - lblStatusInfo.Caption = "Loading States Info..." - DoEvents - LoadStates - lblStatusInfo.Caption = "Idle" - lstThings.ListIndex = 0 -End Sub - -Private Sub LoadSounds() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - Dim i As Integer, numfreeslots As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("sounds.h", ForReading, False) - - Do While InStr(ts.ReadLine, "List of sounds (don't modify this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - cmbSeesound.Clear - cmbAttacksound.Clear - cmbPainsound.Clear - cmbDeathsound.Clear - cmbActivesound.Clear - - Do While InStr(line, "sfx_freeslot0") = 0 - startclip = InStr(line, "sfx_") - If InStr(line, "sfx_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - cmbSeesound.AddItem addstring - cmbAttacksound.AddItem addstring - cmbPainsound.AddItem addstring - cmbDeathsound.AddItem addstring - cmbActivesound.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing - - 'Populate the free slots! - numfreeslots = 800 - - For i = 1 To numfreeslots - If i < 10 Then - addstring = number & " - " & "sfx_fre00" & i & " (free slot)" - ElseIf i < 100 Then - addstring = number & " - " & "sfx_fre0" & i & " (free slot)" - Else - addstring = number & " - " & "sfx_fre" & i & " (free slot)" - End If - cmbSeesound.AddItem addstring - cmbAttacksound.AddItem addstring - cmbPainsound.AddItem addstring - cmbDeathsound.AddItem addstring - cmbActivesound.AddItem addstring - number = number + 1 - Next -End Sub -Private Sub LoadStates() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - Dim i As Integer - Dim numfreeslots As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Object states (don't modify this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - cmbSpawnstate.Clear - cmbSeestate.Clear - cmbPainstate.Clear - cmbMeleestate.Clear - cmbMissilestate.Clear - cmbDeathstate.Clear - cmbXdeathstate.Clear - cmbRaisestate.Clear - - Do While InStr(line, "S_FIRSTFREESLOT") = 0 - startclip = InStr(line, "S_") - If InStr(line, "S_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - cmbSpawnstate.AddItem addstring - cmbSeestate.AddItem addstring - cmbPainstate.AddItem addstring - cmbMeleestate.AddItem addstring - cmbMissilestate.AddItem addstring - cmbDeathstate.AddItem addstring - cmbXdeathstate.AddItem addstring - cmbRaisestate.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - - 'Populate the free slots! - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - line = ts.ReadLine - Do While InStr(line, "#define NUMMOBJFREESLOTS") = 0 - line = ts.ReadLine - Loop - - startclip = InStr(line, "SLOTS ") + 6 - numfreeslots = Val(Mid(line, startclip, Len(line) - startclip + 1)) * 6 - - For i = 1 To numfreeslots - addstring = number & " - " & "S_FREESLOT" & i - cmbSpawnstate.AddItem addstring - cmbSeestate.AddItem addstring - cmbPainstate.AddItem addstring - cmbMeleestate.AddItem addstring - cmbMissilestate.AddItem addstring - cmbDeathstate.AddItem addstring - cmbXdeathstate.AddItem addstring - cmbRaisestate.AddItem addstring - number = number + 1 - Next - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub LoadThings() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim numfreeslots As Integer, i As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Little flag for SOC editor (don't change this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - lstThings.Clear - - Do While InStr(line, "MT_FIRSTFREESLOT") = 0 - startclip = InStr(line, "MT_") - If InStr(line, "MT_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - lstThings.AddItem number & " - " & line - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - - 'Populate the free slots! - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - line = ts.ReadLine - Do While InStr(line, "#define NUMMOBJFREESLOTS") = 0 - line = ts.ReadLine - Loop - - startclip = InStr(line, "SLOTS ") + 6 - numfreeslots = Val(Mid(line, startclip, Len(line) - startclip + 1)) - - For i = 1 To numfreeslots - lstThings.AddItem number & " - " & "MT_FREESLOT" & i - number = number + 1 - Next - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub LoadObjectInfo(ThingNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("info.c", ForReading, False) - - Do While InStr(ts.ReadLine, "mobjinfo[NUMMOBJTYPES] =") = 0 - Loop - - number = 0 - - Do While number <> ThingNum - Do While InStr(ts.ReadLine, "}") = 0 - Loop - number = number + 1 - Loop - - Do While InStr(line, "doomednum") = 0 - line = ts.ReadLine - Loop - - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtDoomednum.Text = line - - line = ts.ReadLine - Do While InStr(line, "spawnstate") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbSpawnstate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbSpawnstate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbSpawnstate.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "spawnhealth") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtSpawnhealth.Text = line - - line = ts.ReadLine - Do While InStr(line, "seestate") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbSeestate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbSeestate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbSeestate.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "seesound") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbSeesound, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbSeesound.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbSeesound.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "reactiontime") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtReactiontime.Text = line - - line = ts.ReadLine - Do While InStr(line, "attacksound") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbAttacksound, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbAttacksound.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbAttacksound.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "painstate") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbPainstate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbPainstate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbPainstate.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "painchance") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtPainchance.Text = line - - line = ts.ReadLine - Do While InStr(line, "painsound") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbPainsound, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbPainsound.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbPainsound.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "meleestate") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbMeleestate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbMeleestate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbMeleestate.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "missilestate") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbMissilestate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbMissilestate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbMissilestate.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "deathstate") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbDeathstate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbDeathstate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbDeathstate.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "xdeathstate") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbXdeathstate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbXdeathstate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbXdeathstate.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "deathsound") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbDeathsound, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbDeathsound.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbDeathsound.Text = number & " - " & line - End If - - - line = ts.ReadLine - Do While InStr(line, "speed") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtSpeed.Text = line - - line = ts.ReadLine - Do While InStr(line, "radius") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtRadius.Text = line - - line = ts.ReadLine - Do While InStr(line, "height") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtHeight.Text = line - - line = ts.ReadLine 'Display order offset (add support, please!) - - line = ts.ReadLine - Do While InStr(line, "mass") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtMass.Text = line - - line = ts.ReadLine - Do While InStr(line, "damage") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - 'Check for *FRACUNIT values - endclip = InStr(line, "*FRACUNIT") - If endclip <> 0 Then - line = Left(line, endclip - 1) - line = Val(line) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - line = FindThingNum(line) & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - line = FindPowerNum(line) & " - " & line - End If - txtDamage.Text = line - - line = ts.ReadLine - Do While InStr(line, "activesound") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbActivesound, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbActivesound.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbActivesound.Text = number & " - " & line - End If - - line = ts.ReadLine - Do While InStr(line, "flags") = 0 - Loop - endclip = InStr(line, ",") - line = Left(line, endclip - 1) - line = TrimComplete(line) - ProcessFlags (line) - - line = ts.ReadLine - Do While InStr(line, "raisestate") = 0 - Loop - endclip = InStr(line, "//") - line = Left(line, endclip - 1) - line = TrimComplete(line) - Call FindComboIndex(cmbRaisestate, line) - 'Check for crazy-odd MT_ usage - endclip = InStr(line, "MT_") - If endclip <> 0 Then - number = FindThingNum(line) - cmbRaisestate.Text = number & " - " & line - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(line, "pw_") - If endclip <> 0 Then - number = FindPowerNum(line) - cmbRaisestate.Text = number & " - " & line - End If - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ProcessFlags(flags As String) - Dim FlagList(32) As String - Dim endpoint As Integer - Dim ListCount As Integer - Dim FlagString As String - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim j As Integer, i As Integer - Dim number As Long - Dim startclip As Integer, endclip As Integer - - For j = 0 To 26 - chkFlags(j).Value = 0 - Next j - - FlagString = flags - - flags = flags & "||" - - ListCount = 0 - - Do While Len(flags) > 3 - endpoint = InStr(flags, "|") - FlagString = Left(flags, endpoint - 1) - flags = Right(flags, Len(flags) - endpoint) - FlagList(ListCount) = FlagString - ListCount = ListCount + 1 - Loop - - ChDir SourcePath - - For i = 0 To ListCount - 1 - Set ts = myFSO.OpenTextFile("p_mobj.h", ForReading, False) - - line = ts.ReadLine - - Do While Not ts.AtEndOfStream - line = ts.ReadLine - If InStr(line, FlagList(i)) Then - If InStr(line, "//") = 0 Or (InStr(line, "//") > InStr(line, FlagList(i))) Then - Exit Do - End If - End If - Loop - - If InStr(line, FlagList(i)) Then - startclip = InStr(line, "0x") - endclip = InStr(line, ",") - line = Mid(line, startclip + 2, endclip - 1) - line = "&H" & line - TrimComplete (line) - line = Left(line, Len(line) - 1) - number = CLng(line) - - For j = 0 To 26 - If chkFlags(j).Tag = number Then - chkFlags(j).Value = 1 - End If - Next j - End If - ts.Close - Next i - - Set myFSO = Nothing -End Sub - -Private Sub FindComboIndex(ByRef Box As ComboBox, line As String) - Dim i As Integer - - For i = 0 To Box.ListCount - If InStr(Box.List(i), line) Then - Box.ListIndex = i - Exit For - End If - Next -End Sub - -Private Sub lstThings_Click() - lblStatusInfo.Caption = "Loading thing info..." - DoEvents - Call ClearForm - If InStr(lstThings.List(lstThings.ListIndex), "MT_FREESLOT") = 0 Then - LoadObjectInfo (lstThings.ListIndex) - End If - LoadSOCObjectInfo (lstThings.ListIndex) - lblStatusInfo.Caption = "Idle" -End Sub - -Private Sub LoadSOCObjectInfo(ThingNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim j As Integer - Dim temp As Long - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "THING" And Val(word2) = ThingNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "MAPTHINGNUM" Then - txtDoomednum.Text = Val(word2) - ElseIf word = "SPAWNSTATE" Then - cmbSpawnstate.ListIndex = Val(word2) - ElseIf word = "SPAWNHEALTH" Then - txtSpawnhealth.Text = Val(word2) - ElseIf word = "SEESTATE" Then - cmbSeestate.ListIndex = Val(word2) - ElseIf word = "SEESOUND" Then - cmbSeesound.ListIndex = Val(word2) - ElseIf word = "REACTIONTIME" Then - txtReactiontime.Text = Val(word2) - ElseIf word = "ATTACKSOUND" Then - cmbAttacksound.ListIndex = Val(word2) - ElseIf word = "PAINSTATE" Then - cmbPainstate.ListIndex = Val(word2) - ElseIf word = "PAINCHANCE" Then - txtPainchance.Text = Val(word2) - ElseIf word = "PAINSOUND" Then - cmbPainsound.ListIndex = Val(word2) - ElseIf word = "MELEESTATE" Then - cmbMeleestate.ListIndex = Val(word2) - ElseIf word = "MISSILESTATE" Then - cmbMissilestate.ListIndex = Val(word2) - ElseIf word = "DEATHSTATE" Then - cmbDeathstate.ListIndex = Val(word2) - ElseIf word = "DEATHSOUND" Then - cmbDeathsound.ListIndex = Val(word2) - ElseIf word = "XDEATHSTATE" Then - cmbXdeathstate.ListIndex = Val(word2) - ElseIf word = "SPEED" Then - txtSpeed.Text = Val(word2) - ElseIf word = "RADIUS" Then - txtRadius.Text = Val(word2) - ElseIf word = "HEIGHT" Then - txtHeight.Text = Val(word2) - ElseIf word = "MASS" Then - txtMass.Text = Val(word2) - ElseIf word = "DAMAGE" Then - txtDamage.Text = Val(word2) - ElseIf word = "ACTIVESOUND" Then - cmbActivesound.ListIndex = Val(word2) - ElseIf word = "FLAGS" Then - For j = 0 To 26 - temp = Val(word2) - If temp And chkFlags(j).Tag Then - chkFlags(j).Value = 1 - Else - chkFlags(j).Value = 0 - End If - Next j - ElseIf word = "RAISESTATE" Then - cmbRaisestate.ListIndex = Val(word2) - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Function FindThingNum(ThingName As String) As Integer - Dim i As Integer - Dim temp As String - Dim startpoint As Integer - Dim endpoint As Integer - - For i = 0 To lstThings.ListCount - 1 - temp = lstThings.List(i) - startpoint = InStr(temp, "-") + 2 - endpoint = Len(temp) - startpoint + 1 - temp = Mid(temp, startpoint, endpoint) - If temp = ThingName Then - FindThingNum = Val(lstThings.List(i)) - Exit For - End If - Next -End Function - -Private Function FindPowerNum(PowerName As String) As Integer - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("d_player.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Player powers. (don't edit this comment)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - Do While InStr(line, "NUMPOWERS") = 0 - startclip = InStr(line, PowerName) - If startclip <> 0 Then - FindPowerNum = number - Exit Do - End If - number = number + 1 - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing -End Function - -Private Sub WriteThing(Remove As Boolean, num As Integer) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim flags As Long - Dim thingfound As Boolean - Dim i As Integer - - thingfound = False - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the current thing exists in the SOC, delete it. - If word = "THING" And Val(word2) = num Then - thingfound = True - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not (tsSource.AtEndOfStream) - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - tsTarget.WriteLine "Thing " & num - txtDoomednum.Text = TrimComplete(txtDoomednum.Text) - cmbSpawnstate.Text = TrimComplete(cmbSpawnstate.Text) - txtSpawnhealth.Text = TrimComplete(txtSpawnhealth.Text) - cmbSeestate.Text = TrimComplete(cmbSeestate.Text) - cmbSeesound.Text = TrimComplete(cmbSeesound.Text) - txtReactiontime.Text = TrimComplete(txtReactiontime.Text) - cmbAttacksound.Text = TrimComplete(cmbAttacksound.Text) - cmbPainstate.Text = TrimComplete(cmbPainstate.Text) - txtPainchance.Text = TrimComplete(txtPainchance.Text) - cmbPainsound.Text = TrimComplete(cmbPainsound.Text) - cmbMeleestate.Text = TrimComplete(cmbMeleestate.Text) - cmbMissilestate.Text = TrimComplete(cmbMissilestate.Text) - cmbDeathstate.Text = TrimComplete(cmbDeathstate.Text) - cmbDeathsound.Text = TrimComplete(cmbDeathsound.Text) - cmbXdeathstate.Text = TrimComplete(cmbXdeathstate.Text) - txtSpeed.Text = TrimComplete(txtSpeed.Text) - txtRadius.Text = TrimComplete(txtRadius.Text) - txtHeight.Text = TrimComplete(txtHeight.Text) - txtMass.Text = TrimComplete(txtMass.Text) - txtDamage.Text = TrimComplete(txtDamage.Text) - cmbActivesound.Text = TrimComplete(cmbActivesound.Text) - cmbRaisestate.Text = TrimComplete(cmbRaisestate.Text) - flags = 0 - ' Only 31 bits can be used, because VB is stupid. - For i = 0 To 26 - If chkFlags(i).Value = 1 Then flags = flags + Val(chkFlags(i).Tag) - Next - If txtDoomednum.Text <> "" Then tsTarget.WriteLine "MAPTHINGNUM = " & Val(txtDoomednum.Text) - If cmbSpawnstate.Text <> "" Then tsTarget.WriteLine "SPAWNSTATE = " & Val(cmbSpawnstate.Text) - If txtSpawnhealth.Text <> "" Then tsTarget.WriteLine "SPAWNHEALTH = " & Val(txtSpawnhealth.Text) - If cmbSeestate.Text <> "" Then tsTarget.WriteLine "SEESTATE = " & Val(cmbSeestate.Text) - If cmbSeesound.Text <> "" Then tsTarget.WriteLine "SEESOUND = " & Val(cmbSeesound.Text) - If txtReactiontime.Text <> "" Then tsTarget.WriteLine "REACTIONTIME = " & Val(txtReactiontime.Text) - If cmbAttacksound.Text <> "" Then tsTarget.WriteLine "ATTACKSOUND = " & Val(cmbAttacksound.Text) - If cmbPainstate.Text <> "" Then tsTarget.WriteLine "PAINSTATE = " & Val(cmbPainstate.Text) - If txtPainchance.Text <> "" Then tsTarget.WriteLine "PAINCHANCE = " & Val(txtPainchance.Text) - If cmbPainsound.Text <> "" Then tsTarget.WriteLine "PAINSOUND = " & Val(cmbPainsound.Text) - If cmbMeleestate.Text <> "" Then tsTarget.WriteLine "MELEESTATE = " & Val(cmbMeleestate.Text) - If cmbMissilestate.Text <> "" Then tsTarget.WriteLine "MISSILESTATE = " & Val(cmbMissilestate.Text) - If cmbDeathstate.Text <> "" Then tsTarget.WriteLine "DEATHSTATE = " & Val(cmbDeathstate.Text) - If cmbDeathsound.Text <> "" Then tsTarget.WriteLine "DEATHSOUND = " & Val(cmbDeathsound.Text) - If cmbXdeathstate.Text <> "" Then tsTarget.WriteLine "XDEATHSTATE = " & Val(cmbXdeathstate.Text) - If txtSpeed.Text <> "" Then tsTarget.WriteLine "SPEED = " & Val(txtSpeed.Text) - If txtRadius.Text <> "" Then tsTarget.WriteLine "RADIUS = " & Val(txtRadius.Text) - If txtHeight.Text <> "" Then tsTarget.WriteLine "HEIGHT = " & Val(txtHeight.Text) - If txtMass.Text <> "" Then tsTarget.WriteLine "MASS = " & Val(txtMass.Text) - If txtDamage.Text <> "" Then tsTarget.WriteLine "DAMAGE = " & Val(txtDamage.Text) - If cmbActivesound.Text <> "" Then tsTarget.WriteLine "ACTIVESOUND = " & Val(cmbActivesound.Text) - If cmbRaisestate.Text <> "" Then tsTarget.WriteLine "RAISESTATE = " & Val(cmbRaisestate.Text) - tsTarget.WriteLine "FLAGS = " & flags - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - If thingfound = True Then - MsgBox "Thing removed from SOC." - Else - MsgBox "Thing not found in SOC." - End If - Else - MsgBox "Thing Saved." - End If -End Sub diff --git a/tools/SOCEdit/Things.frx b/tools/SOCEdit/Things.frx deleted file mode 100644 index 980538679..000000000 Binary files a/tools/SOCEdit/Things.frx and /dev/null differ diff --git a/tools/SOCEdit/frmCharacterEdit.frm b/tools/SOCEdit/frmCharacterEdit.frm deleted file mode 100644 index 415fcbb0f..000000000 --- a/tools/SOCEdit/frmCharacterEdit.frm +++ /dev/null @@ -1,320 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmCharacterEdit - Caption = "Character Edit" - ClientHeight = 3345 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 4680 - Icon = "frmCharacterEdit.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 3345 - ScaleWidth = 4680 - Begin VB.CommandButton cmdExample - Caption = "Show Me An &Example" - Height = 495 - Left = 1320 - Style = 1 'Graphical - TabIndex = 14 - Top = 2400 - Width = 975 - End - Begin VB.CheckBox chkEnabled - Caption = "Enable this player selection." - Height = 495 - Left = 1080 - TabIndex = 13 - Top = 1560 - Width = 1455 - End - Begin VB.CommandButton cmdDelete - Caption = "&Delete from SOC" - Height = 495 - Left = 120 - Style = 1 'Graphical - TabIndex = 12 - Top = 2760 - Width = 855 - End - Begin VB.CommandButton cmdSave - Caption = "&Save" - Height = 495 - Left = 120 - TabIndex = 11 - Top = 2160 - Width = 855 - End - Begin VB.TextBox txtSkinname - Height = 285 - Left = 3240 - TabIndex = 9 - Top = 1200 - Width = 1335 - End - Begin VB.TextBox txtPicname - Height = 285 - Left = 3240 - MaxLength = 8 - TabIndex = 7 - Top = 840 - Width = 1095 - End - Begin VB.TextBox txtMenuposition - Height = 285 - Left = 3240 - MaxLength = 3 - TabIndex = 5 - Top = 480 - Width = 495 - End - Begin VB.TextBox txtPlayername - Height = 285 - Left = 3240 - MaxLength = 64 - TabIndex = 3 - Top = 120 - Width = 1335 - End - Begin VB.TextBox txtPlayertext - Height = 1455 - Left = 2640 - MultiLine = -1 'True - TabIndex = 1 - Top = 1800 - Width = 1935 - End - Begin VB.ListBox lstPlayers - Height = 1815 - ItemData = "frmCharacterEdit.frx":0442 - Left = 120 - List = "frmCharacterEdit.frx":0461 - TabIndex = 0 - Top = 240 - Width = 855 - End - Begin VB.Label lblSkinname - Caption = "Name of player (skin) to use:" - Height = 255 - Left = 1080 - TabIndex = 10 - Top = 1200 - Width = 2055 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture to display:" - Height = 255 - Left = 1560 - TabIndex = 8 - Top = 840 - Width = 1575 - End - Begin VB.Label lblMenuposition - Alignment = 1 'Right Justify - Caption = "Vertical menu position:" - Height = 255 - Left = 1320 - TabIndex = 6 - Top = 480 - Width = 1815 - End - Begin VB.Label lblPlayername - Alignment = 1 'Right Justify - Caption = "Displayed name of player:" - Height = 255 - Left = 1320 - TabIndex = 4 - Top = 120 - Width = 1815 - End - Begin VB.Label lblPlayertext - Caption = "Short Description:" - Height = 255 - Left = 2640 - TabIndex = 2 - Top = 1560 - Width = 1455 - End -End -Attribute VB_Name = "frmCharacterEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdDelete_Click() - Call WriteCharacter(True) -End Sub - -Private Sub cmdExample_Click() - txtPlayername.Text = "SONIC" - txtMenuposition.Text = "20" - txtPicname.Text = "SONCCHAR" - txtSkinname.Text = "SONIC" - chkEnabled.Value = 1 - txtPlayertext.Text = " Fastest" & vbCrLf & " Speed Thok" & vbCrLf & " Not a good pick" & vbCrLf & "for starters, but when" & vbCrLf & "controlled properly," & vbCrLf & "Sonic is the most" & vbCrLf & "powerful of the three." -End Sub - -Private Sub cmdSave_Click() - Call WriteCharacter(False) -End Sub - -Private Sub ClearForm() - txtPlayername.Text = "" - txtMenuposition.Text = "" - txtPicname.Text = "" - txtSkinname.Text = "" - chkEnabled.Value = 0 - txtPlayertext.Text = "" -End Sub - -Private Sub ReadSOCPlayer(num As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "CHARACTER" And Val(word2) = num Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "PLAYERTEXT" Then - Dim startclip As Integer, endclip As Integer - startclip = InStr(line, "=") - - startclip = startclip + 2 - - line = Mid(line, startclip, Len(line)) - - txtPlayertext.Text = line & vbCrLf - - Do While InStr(line, "#") = 0 And Not ts.AtEndOfStream - line = ts.ReadLine & vbCrLf - txtPlayertext.Text = txtPlayertext.Text & line - Loop - - txtPlayertext.Text = RTrimComplete(txtPlayertext.Text) - If Right(txtPlayertext.Text, 1) = "#" Then - txtPlayertext.Text = Left(txtPlayertext.Text, Len(txtPlayertext.Text) - 1) - End If - ElseIf word = "PLAYERNAME" Then - txtPlayername.Text = word2 - ElseIf word = "MENUPOSITION" Then - txtMenuposition.Text = Val(word2) - ElseIf word = "PICNAME" Then - txtPicname.Text = word2 - ElseIf word = "STATUS" Then - If Val(word2) = 32 Then - chkEnabled.Value = 1 - Else - chkEnabled.Value = 0 - End If - ElseIf word = "SKINNAME" Then - txtSkinname.Text = word2 - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub lstPlayers_Click() - Call ClearForm - Call ReadSOCPlayer(lstPlayers.ListIndex) -End Sub - -Private Sub WriteCharacter(Remove As Boolean) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim charfound As Boolean - - charfound = False - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the current character exists in the SOC, delete it. - If word = "CHARACTER" And Val(word2) = lstPlayers.ListIndex Then - charfound = True - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not (tsSource.AtEndOfStream) - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "CHARACTER " & lstPlayers.ListIndex - txtPlayername.Text = TrimComplete(txtPlayername.Text) - txtMenuposition.Text = TrimComplete(txtMenuposition.Text) - txtPicname.Text = TrimComplete(txtPicname.Text) - txtSkinname.Text = TrimComplete(txtSkinname.Text) - If txtPlayername.Text <> "" Then tsTarget.WriteLine "PLAYERNAME = " & txtPlayername.Text - If txtMenuposition.Text <> "" Then tsTarget.WriteLine "MENUPOSITION = " & Val(txtMenuposition.Text) - If txtPicname.Text <> "" Then tsTarget.WriteLine "PICNAME = " & txtPicname.Text - If txtSkinname.Text <> "" Then tsTarget.WriteLine "SKINNAME = " & txtSkinname.Text - If chkEnabled.Value = 1 Then - tsTarget.WriteLine "STATUS = 32" - Else - tsTarget.WriteLine "STATUS = 0" - End If - If txtPlayertext.Text <> "" Then tsTarget.WriteLine "PLAYERTEXT = " & txtPlayertext.Text & "#" - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - If charfound = True Then - MsgBox "Player choice removed from SOC." - Else - MsgBox "Player choice not found in SOC." - End If - Else - MsgBox "Character Saved." - End If -End Sub - diff --git a/tools/SOCEdit/frmCharacterEdit.frx b/tools/SOCEdit/frmCharacterEdit.frx deleted file mode 100644 index 5e767f4ab..000000000 Binary files a/tools/SOCEdit/frmCharacterEdit.frx and /dev/null differ diff --git a/tools/SOCEdit/frmCutsceneEdit.frm b/tools/SOCEdit/frmCutsceneEdit.frm deleted file mode 100644 index 7fb18feed..000000000 --- a/tools/SOCEdit/frmCutsceneEdit.frm +++ /dev/null @@ -1,1365 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmCutsceneEdit - Caption = "Cutscene Edit" - ClientHeight = 6495 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 10410 - Icon = "frmCutsceneEdit.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 6495 - ScaleWidth = 10410 - StartUpPosition = 3 'Windows Default - Begin VB.TextBox txtNumScenes - Height = 285 - Left = 3480 - MaxLength = 3 - TabIndex = 97 - Top = 240 - Width = 615 - End - Begin VB.ListBox lstScene - Height = 450 - ItemData = "frmCutsceneEdit.frx":0442 - Left = 3360 - List = "frmCutsceneEdit.frx":0444 - TabIndex = 94 - Top = 600 - Width = 735 - End - Begin VB.ComboBox cmbMusicslot - Height = 315 - Left = 8760 - TabIndex = 93 - Top = 1680 - Width = 1575 - End - Begin VB.Frame frmPic1 - Caption = "Picture 8:" - Height = 1335 - Index = 7 - Left = 7440 - TabIndex = 80 - Top = 5040 - Width = 2895 - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 7 - Left = 600 - MaxLength = 3 - TabIndex = 85 - Top = 960 - Width = 495 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 7 - Left = 600 - MaxLength = 3 - TabIndex = 84 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 7 - Left = 2040 - MaxLength = 5 - TabIndex = 83 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 7 - Left = 1320 - TabIndex = 82 - Top = 240 - Width = 1455 - End - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 7 - Left = 1320 - TabIndex = 81 - Top = 960 - Width = 1455 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 7 - Left = 240 - TabIndex = 89 - Top = 960 - Width = 255 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 7 - Left = 240 - TabIndex = 88 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 7 - Left = 1200 - TabIndex = 87 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 7 - Left = 120 - TabIndex = 86 - Top = 240 - Width = 1095 - End - End - Begin VB.Frame frmPic1 - Caption = "Picture 7:" - Height = 1335 - Index = 6 - Left = 4440 - TabIndex = 70 - Top = 5040 - Width = 2895 - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 6 - Left = 600 - MaxLength = 3 - TabIndex = 75 - Top = 960 - Width = 495 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 6 - Left = 600 - MaxLength = 3 - TabIndex = 74 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 6 - Left = 2040 - MaxLength = 5 - TabIndex = 73 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 6 - Left = 1320 - TabIndex = 72 - Top = 240 - Width = 1455 - End - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 6 - Left = 1320 - TabIndex = 71 - Top = 960 - Width = 1455 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 6 - Left = 240 - TabIndex = 79 - Top = 960 - Width = 255 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 6 - Left = 240 - TabIndex = 78 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 6 - Left = 1200 - TabIndex = 77 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 6 - Left = 120 - TabIndex = 76 - Top = 240 - Width = 1095 - End - End - Begin VB.Frame frmPic1 - Caption = "Picture 6:" - Height = 1335 - Index = 5 - Left = 7440 - TabIndex = 60 - Top = 3600 - Width = 2895 - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 5 - Left = 600 - MaxLength = 3 - TabIndex = 65 - Top = 960 - Width = 495 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 5 - Left = 600 - MaxLength = 3 - TabIndex = 64 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 5 - Left = 2040 - MaxLength = 5 - TabIndex = 63 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 5 - Left = 1320 - TabIndex = 62 - Top = 240 - Width = 1455 - End - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 5 - Left = 1320 - TabIndex = 61 - Top = 960 - Width = 1455 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 5 - Left = 240 - TabIndex = 69 - Top = 960 - Width = 255 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 5 - Left = 240 - TabIndex = 68 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 5 - Left = 1200 - TabIndex = 67 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 5 - Left = 120 - TabIndex = 66 - Top = 240 - Width = 1095 - End - End - Begin VB.Frame frmPic1 - Caption = "Picture 5:" - Height = 1335 - Index = 4 - Left = 4440 - TabIndex = 50 - Top = 3600 - Width = 2895 - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 4 - Left = 600 - MaxLength = 3 - TabIndex = 55 - Top = 960 - Width = 495 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 4 - Left = 600 - MaxLength = 3 - TabIndex = 54 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 4 - Left = 2040 - MaxLength = 5 - TabIndex = 53 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 4 - Left = 1320 - TabIndex = 52 - Top = 240 - Width = 1455 - End - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 4 - Left = 1320 - TabIndex = 51 - Top = 960 - Width = 1455 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 4 - Left = 240 - TabIndex = 59 - Top = 960 - Width = 255 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 4 - Left = 240 - TabIndex = 58 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 4 - Left = 1200 - TabIndex = 57 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 4 - Left = 120 - TabIndex = 56 - Top = 240 - Width = 1095 - End - End - Begin VB.Frame frmPic1 - Caption = "Picture 4:" - Height = 1335 - Index = 3 - Left = 1440 - TabIndex = 40 - Top = 3600 - Width = 2895 - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 3 - Left = 1320 - TabIndex = 45 - Top = 960 - Width = 1455 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 3 - Left = 1320 - TabIndex = 44 - Top = 240 - Width = 1455 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 3 - Left = 2040 - MaxLength = 5 - TabIndex = 43 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 3 - Left = 600 - MaxLength = 3 - TabIndex = 42 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 3 - Left = 600 - MaxLength = 3 - TabIndex = 41 - Top = 960 - Width = 495 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 3 - Left = 120 - TabIndex = 49 - Top = 240 - Width = 1095 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 3 - Left = 1200 - TabIndex = 48 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 3 - Left = 240 - TabIndex = 47 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 3 - Left = 240 - TabIndex = 46 - Top = 960 - Width = 255 - End - End - Begin VB.Frame frmPic1 - Caption = "Picture 3:" - Height = 1335 - Index = 2 - Left = 7440 - TabIndex = 30 - Top = 2160 - Width = 2895 - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 2 - Left = 1320 - TabIndex = 35 - Top = 960 - Width = 1455 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 2 - Left = 1320 - TabIndex = 34 - Top = 240 - Width = 1455 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 2 - Left = 2040 - MaxLength = 5 - TabIndex = 33 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 2 - Left = 600 - MaxLength = 3 - TabIndex = 32 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 2 - Left = 600 - MaxLength = 3 - TabIndex = 31 - Top = 960 - Width = 495 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 2 - Left = 120 - TabIndex = 39 - Top = 240 - Width = 1095 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 2 - Left = 1200 - TabIndex = 38 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 2 - Left = 240 - TabIndex = 37 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 2 - Left = 240 - TabIndex = 36 - Top = 960 - Width = 255 - End - End - Begin VB.Frame frmPic1 - Caption = "Picture 2:" - Height = 1335 - Index = 1 - Left = 4440 - TabIndex = 20 - Top = 2160 - Width = 2895 - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 1 - Left = 1320 - TabIndex = 25 - Top = 960 - Width = 1455 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 1 - Left = 1320 - TabIndex = 24 - Top = 240 - Width = 1455 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 1 - Left = 2040 - MaxLength = 5 - TabIndex = 23 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 1 - Left = 600 - MaxLength = 3 - TabIndex = 22 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 1 - Left = 600 - MaxLength = 3 - TabIndex = 21 - Top = 960 - Width = 495 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 1 - Left = 120 - TabIndex = 29 - Top = 240 - Width = 1095 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 1 - Left = 1200 - TabIndex = 28 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 1 - Left = 240 - TabIndex = 27 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 1 - Left = 240 - TabIndex = 26 - Top = 960 - Width = 255 - End - End - Begin VB.TextBox txtTextypos - Height = 285 - Left = 3120 - MaxLength = 3 - TabIndex = 19 - Top = 5880 - Width = 615 - End - Begin VB.TextBox txtTextxpos - Height = 285 - Left = 3120 - MaxLength = 3 - TabIndex = 18 - Top = 5520 - Width = 615 - End - Begin VB.Frame frmPic1 - Caption = "Picture 1:" - Height = 1335 - Index = 0 - Left = 1440 - TabIndex = 6 - Top = 2160 - Width = 2895 - Begin VB.TextBox txtPicycoord - Height = 285 - Index = 0 - Left = 600 - MaxLength = 3 - TabIndex = 14 - Top = 960 - Width = 495 - End - Begin VB.TextBox txtPicXcoord - Height = 285 - Index = 0 - Left = 600 - MaxLength = 3 - TabIndex = 12 - Top = 600 - Width = 495 - End - Begin VB.TextBox txtPicduration - Height = 285 - Index = 0 - Left = 2040 - MaxLength = 5 - TabIndex = 11 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtPicname - Height = 285 - Index = 0 - Left = 1320 - TabIndex = 8 - Top = 240 - Width = 1455 - End - Begin VB.CheckBox chkPichires - Caption = "High-Resolution" - Height = 255 - Index = 0 - Left = 1320 - TabIndex = 7 - Top = 960 - Width = 1455 - End - Begin VB.Label lblPicycoord - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Index = 0 - Left = 240 - TabIndex = 15 - Top = 960 - Width = 255 - End - Begin VB.Label lblPicxcoord - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Index = 0 - Left = 240 - TabIndex = 13 - Top = 600 - Width = 255 - End - Begin VB.Label lblPicduration - Alignment = 1 'Right Justify - Caption = "Duration:" - Height = 255 - Index = 0 - Left = 1200 - TabIndex = 10 - Top = 600 - Width = 735 - End - Begin VB.Label lblPicname - Alignment = 1 'Right Justify - Caption = "Picture Name:" - Height = 255 - Index = 0 - Left = 120 - TabIndex = 9 - Top = 240 - Width = 1095 - End - End - Begin VB.TextBox txtNumberofpics - Height = 285 - Left = 3840 - MaxLength = 1 - TabIndex = 5 - Top = 1800 - Width = 375 - End - Begin VB.TextBox txtScenetext - Height = 1815 - Left = 4440 - MultiLine = -1 'True - TabIndex = 3 - Top = 240 - Width = 3135 - End - Begin VB.CommandButton cmdSave - Caption = "&Save Scene" - Height = 495 - Left = 3360 - Style = 1 'Graphical - TabIndex = 1 - Top = 1200 - Width = 855 - End - Begin VB.ListBox lstCutscenes - Height = 6300 - ItemData = "frmCutsceneEdit.frx":0446 - Left = 120 - List = "frmCutsceneEdit.frx":0448 - TabIndex = 0 - Top = 120 - Width = 1215 - End - Begin VB.Label Label3 - Caption = "Note: The cutscene editor is not fully functional. Only use it to get an idea of the proper syntax to use." - BeginProperty Font - Name = "MS Sans Serif" - Size = 9.75 - Charset = 0 - Weight = 700 - Underline = 0 'False - Italic = 0 'False - Strikethrough = 0 'False - EndProperty - Height = 1335 - Left = 7680 - TabIndex = 98 - Top = 240 - Width = 2655 - End - Begin VB.Label Label2 - Caption = "For Scene Text:" - BeginProperty Font - Name = "MS Sans Serif" - Size = 8.25 - Charset = 0 - Weight = 400 - Underline = -1 'True - Italic = 0 'False - Strikethrough = 0 'False - EndProperty - Height = 255 - Left = 1560 - TabIndex = 96 - Top = 5160 - Width = 1695 - End - Begin VB.Label Label1 - Caption = "Enter all time durations in game tics (35 = 1 second)" - BeginProperty Font - Name = "MS Sans Serif" - Size = 8.25 - Charset = 0 - Weight = 700 - Underline = 0 'False - Italic = 0 'False - Strikethrough = 0 'False - EndProperty - Height = 855 - Left = 1560 - TabIndex = 95 - Top = 960 - Width = 1335 - End - Begin VB.Label lblMusicslot - Alignment = 1 'Right Justify - Caption = "Music to play:" - Height = 255 - Left = 7680 - TabIndex = 92 - Top = 1680 - Width = 975 - End - Begin VB.Label lblCurrentScene - Alignment = 1 'Right Justify - Caption = "Current Scene:" - Height = 255 - Left = 1920 - TabIndex = 91 - Top = 720 - Width = 1215 - End - Begin VB.Label lblNumScenes - Alignment = 1 'Right Justify - Caption = "Number of Scenes in this Cutscene:" - Height = 375 - Left = 1440 - TabIndex = 90 - Top = 120 - Width = 1935 - End - Begin VB.Label lblTextypos - Alignment = 1 'Right Justify - Caption = "Text Y Position:" - Height = 255 - Left = 1800 - TabIndex = 17 - Top = 5880 - Width = 1215 - End - Begin VB.Label lblTextxpos - Alignment = 1 'Right Justify - Caption = "Text X Position:" - Height = 255 - Left = 1800 - TabIndex = 16 - Top = 5520 - Width = 1215 - End - Begin VB.Label lblNumberofpics - Alignment = 1 'Right Justify - Caption = "Number of Pictures (max 8):" - Height = 255 - Left = 1560 - TabIndex = 4 - Top = 1800 - Width = 2175 - End - Begin VB.Label lblScenetext - Caption = "Scene Text:" - Height = 255 - Left = 4440 - TabIndex = 2 - Top = 0 - Width = 1215 - End -End -Attribute VB_Name = "frmCutsceneEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdSave_Click() - Call WriteScene(False) -End Sub - -Private Sub lstScene_Click() - Call ClearForm - Call LoadSOCCutscene(Val(lstCutscenes.List(lstCutscenes.ListIndex)), Val(lstScene.List(lstScene.ListIndex))) -End Sub - -Private Sub LoadMusic() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("sounds.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Music list (don't edit this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - cmbMusicslot.Clear - - Do While InStr(line, "NUMMUSIC") = 0 - startclip = InStr(line, "mus_") - If InStr(line, "mus_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - cmbMusicslot.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub cmdReload_Click() - Call Reload -End Sub - -Private Sub Form_Load() - Call Reload -End Sub - -Private Sub Reload() - ClearForm - Call ReadCutsceneSOCNumbers - Call LoadMusic - If lstCutscenes.ListCount > 0 Then - lstCutscenes.ListIndex = 0 - End If -End Sub - -Private Sub LoadSOCCutscene(CutNum As Integer, SceneNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim ind As Integer - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - ' WOW! This looks fun, don't it?! - If UCase(word) = "CUTSCENE" And Val(word2) = CutNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - If word = "NUMSCENES" Then - txtNumScenes.Text = Val(word2) - ElseIf UCase(word) = "SCENE" And Val(word2) = SceneNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "SCENETEXT" Then - Dim startclip As Integer, endclip As Integer - startclip = InStr(line, "=") - - startclip = startclip + 2 - - line = Mid(line, startclip, Len(line)) - - txtScenetext.Text = line & vbCrLf - - Do While InStr(line, "#") = 0 And Not ts.AtEndOfStream - line = ts.ReadLine & vbCrLf - txtScenetext.Text = txtScenetext.Text & line - Loop - - txtScenetext.Text = RTrimComplete(txtScenetext.Text) - If Right(txtScenetext.Text, 1) = "#" Then - txtScenetext.Text = Left(txtScenetext.Text, Len(txtScenetext.Text) - 1) - End If - ElseIf word = "PIC1NAME" Or word = "PIC2NAME" Or word = "PIC3NAME" Or word = "PIC4NAME" Or word = "PIC5NAME" Or word = "PIC6NAME" Or word = "PIC7NAME" Or word = "PIC8NAME" Then - ind = Val(Mid(word, 4, 1)) - 1 - txtPicname(ind).Text = word2 - ElseIf word = "PIC1HIRES" Or word = "PIC2HIRES" Or word = "PIC3HIRES" Or word = "PIC4HIRES" Or word = "PIC5HIRES" Or word = "PIC6HIRES" Or word = "PIC7HIRES" Or word = "PIC8HIRES" Then - ind = Val(Mid(word, 4, 1)) - 1 - chkPichires(ind).Value = Val(word2) - ElseIf word = "PIC1DURATION" Or word = "PIC2DURATION" Or word = "PIC3DURATION" Or word = "PIC4DURATION" Or word = "PIC5DURATION" Or word = "PIC6DURATION" Or word = "PIC7DURATION" Or word = "PIC8DURATION" Then - ind = Val(Mid(word, 4, 1)) - 1 - txtPicduration(ind).Text = Val(word2) - ElseIf word = "PIC1XCOORD" Or word = "PIC2XCOORD" Or word = "PIC3XCOORD" Or word = "PIC4XCOORD" Or word = "PIC5XCOORD" Or word = "PIC6XCOORD" Or word = "PIC7XCOORD" Or word = "PIC8XCOORD" Then - ind = Val(Mid(word, 4, 1)) - 1 - txtPicXcoord(ind).Text = Val(word2) - ElseIf word = "PIC1YCOORD" Or word = "PIC2YCOORD" Or word = "PIC3YCOORD" Or word = "PIC4YCOORD" Or word = "PIC5YCOORD" Or word = "PIC6YCOORD" Or word = "PIC7YCOORD" Or word = "PIC8YCOORD" Then - ind = Val(Mid(word, 4, 1)) - 1 - txtPicycoord(ind).Text = Val(word2) - ElseIf word = "TEXTXPOS" Then - txtTextxpos.Text = Val(word2) - ElseIf word = "TEXTYPOS" Then - txtTextypos.Text = Val(word2) - ElseIf word = "MUSICSLOT" Then - cmbMusicslot.ListIndex = Val(word2) - ElseIf word = "NUMBEROFPICS" Then - txtNumberofpics.Text = Val(word2) - ElseIf word = "SCENE" Then 'End of scene data - line = "" - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ReadCutsceneSOCNumbers() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - - lstCutscenes.Clear - -CutsceneLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo CutsceneLoad - - If Left(line, 1) = vbCrLf Then GoTo CutsceneLoad - - If Len(line) < 1 Then GoTo CutsceneLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "CUTSCENE" Then - lstCutscenes.AddItem (Val(word2)) - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ClearForm() - Dim i As Integer - - For i = 0 To 7 - chkPichires(i).Value = 0 - txtPicXcoord(i).Text = "" - txtPicycoord(i).Text = "" - txtPicname(i).Text = "" - txtPicduration(i).Text = "" - Next - - txtScenetext.Text = "" - txtNumberofpics.Text = "" - txtTextxpos.Text = "" - txtTextypos.Text = "" - cmbMusicslot.Text = "" -End Sub - -Private Sub lstCutscenes_Click() - Dim i As Integer - - LoadNumScenes (Val(lstCutscenes.List(lstCutscenes.ListIndex))) - - lstScene.Clear - For i = 1 To Val(txtNumScenes.Text) - lstScene.AddItem i - Next - - If Val(txtNumScenes) > 0 Then - lstScene.ListIndex = lstScene.ListCount - 1 - lstScene.ListIndex = 0 - End If -End Sub - -Private Sub LoadNumScenes(CutNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim ind As Integer - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - ' WOW! This looks fun, don't it?! - If UCase(word) = "CUTSCENE" And Val(word2) = CutNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - If word = "NUMSCENES" Then - txtNumScenes.Text = Val(word2) - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub WriteScene(Remove As Boolean) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim flags As Long - Dim i As Integer - Dim CutsceneNum As Integer - Dim InCutScene As Boolean - Dim scenefound As Boolean - Dim nevercheckagain As Boolean - - ' This whole sub is a mess, but it works, - ' so I'd better not touch it... - scenefound = False - nevercheckagain = False - - InCutScene = False - CutsceneNum = Val(lstCutscenes.List(lstCutscenes.ListIndex)) - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - If nevercheckagain = False And word = "CUTSCENE" And Val(word2) = CutsceneNum Then - InCutScene = True - tsTarget.WriteLine "CUTSCENE " & Val(lstCutscenes.List(lstCutscenes.ListIndex)) - tsTarget.WriteLine "NUMSCENES " & Val(txtNumScenes.Text) - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - If word = "NUMSCENES" Then - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - End If - End If - - 'If the current scene exists in the SOC, delete it. - If nevercheckagain = False And InCutScene = True And word = "SCENE" And Val(word2) = Val(lstScene.List(lstScene.ListIndex)) Then - scenefound = True - line = tsSource.ReadLine - Do While (Left(UCase(line), 6) <> "SCENE " And Len(TrimComplete(line)) > 0) And Not (tsSource.AtEndOfStream) - line = tsSource.ReadLine - Loop - If Remove = False Then - tsTarget.WriteLine "SCENE " & Val(lstScene.List(lstScene.ListIndex)) - txtNumberofpics.Text = TrimComplete(txtNumberofpics.Text) - txtTextxpos.Text = TrimComplete(txtTextxpos.Text) - txtTextypos.Text = TrimComplete(txtTextypos.Text) - cmbMusicslot.Text = TrimComplete(cmbMusicslot.Text) - - For i = 0 To 7 - txtPicname(i).Text = TrimComplete(txtPicname(i).Text) - txtPicXcoord(i).Text = TrimComplete(txtPicXcoord(i).Text) - txtPicycoord(i).Text = TrimComplete(txtPicycoord(i).Text) - txtPicduration(i).Text = TrimComplete(txtPicduration(i).Text) - Next - - If txtNumberofpics.Text <> "" Then tsTarget.WriteLine "NUMBEROFPICS = " & Val(txtNumberofpics.Text) - If txtTextxpos.Text <> "" Then tsTarget.WriteLine "TEXTXPOS = " & Val(txtTextxpos.Text) - If txtTextypos.Text <> "" Then tsTarget.WriteLine "TEXTYPOS = " & Val(txtTextypos.Text) - If cmbMusicslot.Text <> "" Then tsTarget.WriteLine "MUSICSLOT = " & Val(cmbMusicslot.Text) - - For i = 0 To 7 - If txtPicname(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "NAME = " & txtPicname(i).Text - - If chkPichires(i).Value = 1 Then tsTarget.WriteLine "PIC" & (i + 1) & "HIRES = 1" - - If txtPicXcoord(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "XCOORD = " & Val(txtPicXcoord(i).Text) - If txtPicycoord(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "YCOORD = " & Val(txtPicycoord(i).Text) - If txtPicduration(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "DURATION = " & Val(txtPicduration(i).Text) - Next - If txtScenetext.Text <> "" Then tsTarget.WriteLine "SCENETEXT = " & txtScenetext.Text & "#" - End If - InCutScene = False - nevercheckagain = True - End If - tsTarget.WriteLine line - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False And scenefound = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "CUTSCENE " & Val(lstCutscenes.List(lstCutscenes.ListIndex)) - tsTarget.WriteLine "NUMSCENES " & Val(txtNumScenes.Text) - tsTarget.WriteLine "SCENE " & Val(lstScene.List(lstScene.ListIndex)) - txtNumberofpics.Text = TrimComplete(txtNumberofpics.Text) - txtScenetext.Text = TrimComplete(txtScenetext.Text) - txtTextxpos.Text = TrimComplete(txtTextxpos.Text) - txtTextypos.Text = TrimComplete(txtTextypos.Text) - cmbMusicslot.Text = TrimComplete(cmbMusicslot.Text) - - For i = 0 To 7 - txtPicname(i).Text = TrimComplete(txtPicname(i).Text) - txtPicXcoord(i).Text = TrimComplete(txtPicXcoord(i).Text) - txtPicycoord(i).Text = TrimComplete(txtPicycoord(i).Text) - txtPicduration(i).Text = TrimComplete(txtPicduration(i).Text) - Next - - If txtNumberofpics.Text <> "" Then tsTarget.WriteLine "NUMBEROFPICS = " & Val(txtNumberofpics.Text) - If txtScenetext.Text <> "" Then tsTarget.WriteLine "SCENETEXT = " & txtScenetext.Text & "#" - If txtTextxpos.Text <> "" Then tsTarget.WriteLine "TEXTXPOS = " & Val(txtTextxpos.Text) - If txtTextypos.Text <> "" Then tsTarget.WriteLine "TEXTYPOS = " & Val(txtTextypos.Text) - If cmbMusicslot.Text <> "" Then tsTarget.WriteLine "MUSICSLOT = " & Val(cmbMusicslot.Text) - - For i = 0 To 7 - If txtPicname(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "NAME = " & txtPicname(i).Text - - If chkPichires(i).Value = 1 Then tsTarget.WriteLine "PIC" & (i + 1) & "HIRES = 1" - - If txtPicXcoord(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "XCOORD = " & Val(txtPicXcoord(i).Text) - If txtPicycoord(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "YCOORD = " & Val(txtPicycoord(i).Text) - If txtPicduration(i).Text <> "" Then tsTarget.WriteLine "PIC" & (i + 1) & "DURATION = " & Val(txtPicduration(i).Text) - Next - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - If scenefound = True Then - MsgBox "Scene removed from SOC." - Else - MsgBox "Scene not found in SOC." - End If - Else - MsgBox "Scene Saved." - End If -End Sub diff --git a/tools/SOCEdit/frmCutsceneEdit.frx b/tools/SOCEdit/frmCutsceneEdit.frx deleted file mode 100644 index 6f844e643..000000000 Binary files a/tools/SOCEdit/frmCutsceneEdit.frx and /dev/null differ diff --git a/tools/SOCEdit/frmEmblemEdit.frm b/tools/SOCEdit/frmEmblemEdit.frm deleted file mode 100644 index f94255b9c..000000000 --- a/tools/SOCEdit/frmEmblemEdit.frm +++ /dev/null @@ -1,384 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmEmblemEdit - Caption = "Emblem Edit" - ClientHeight = 2865 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 5160 - Icon = "frmEmblemEdit.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 2865 - ScaleWidth = 5160 - StartUpPosition = 3 'Windows Default - Begin VB.CommandButton cmdDelete - Caption = "&Delete Last Emblem" - Height = 735 - Left = 1560 - Style = 1 'Graphical - TabIndex = 17 - Top = 600 - Width = 855 - End - Begin VB.CommandButton cmdAdd - Caption = "&Add" - Height = 375 - Left = 1560 - TabIndex = 16 - Top = 120 - Width = 855 - End - Begin VB.CommandButton cmdSave - Caption = "&Save Emblem" - Height = 495 - Left = 4200 - Style = 1 'Graphical - TabIndex = 13 - Top = 2280 - Width = 855 - End - Begin VB.CommandButton cmdReload - Caption = "&Reload" - Height = 495 - Left = 3120 - TabIndex = 12 - Top = 2280 - Width = 975 - End - Begin VB.TextBox txtPlayernum - Height = 285 - Left = 4320 - MaxLength = 3 - TabIndex = 9 - Top = 1800 - Width = 735 - End - Begin VB.TextBox txtMapnum - Height = 285 - Left = 4320 - MaxLength = 4 - TabIndex = 7 - Top = 1320 - Width = 735 - End - Begin VB.TextBox txtZ - Height = 285 - Left = 4320 - MaxLength = 5 - TabIndex = 3 - Top = 960 - Width = 735 - End - Begin VB.TextBox txtY - Height = 285 - Left = 4320 - MaxLength = 5 - TabIndex = 2 - Top = 600 - Width = 735 - End - Begin VB.TextBox txtX - Height = 285 - Left = 4320 - MaxLength = 5 - TabIndex = 1 - Top = 240 - Width = 735 - End - Begin VB.ListBox lstEmblems - Height = 2400 - Left = 120 - TabIndex = 0 - Top = 120 - Width = 1335 - End - Begin VB.Label Label1 - Caption = "Emblem #s must be linear, sorry!" - Height = 495 - Left = 1560 - TabIndex = 18 - Top = 2400 - Width = 1455 - End - Begin VB.Label lblNumEmblems - Caption = "# of Emblems:" - Height = 255 - Left = 120 - TabIndex = 15 - Top = 2520 - Width = 1335 - End - Begin VB.Label lblNote2 - Caption = "Don't forget to set Game Data file and # of Emblems in Global Game Settings!" - Height = 855 - Left = 1560 - TabIndex = 14 - Top = 1440 - Width = 1575 - End - Begin VB.Label lblNote - Appearance = 0 'Flat - BorderStyle = 1 'Fixed Single - Caption = "Note: Enter map coordinates, not game coordinates. (I.e., 128, not 8388608)" - ForeColor = &H80000008& - Height = 1095 - Left = 2640 - TabIndex = 11 - Top = 120 - Width = 1335 - End - Begin VB.Label lblPlayernum - Caption = "Player # (255 for all players):" - Height = 495 - Left = 3240 - TabIndex = 10 - Top = 1680 - Width = 1095 - End - Begin VB.Label lblMapnum - Alignment = 1 'Right Justify - Caption = "Map #:" - Height = 255 - Left = 3600 - TabIndex = 8 - Top = 1320 - Width = 615 - End - Begin VB.Label lblZ - Alignment = 1 'Right Justify - Caption = "Z:" - Height = 255 - Left = 3960 - TabIndex = 6 - Top = 960 - Width = 255 - End - Begin VB.Label lblY - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Left = 3960 - TabIndex = 5 - Top = 600 - Width = 255 - End - Begin VB.Label lblX - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Left = 3960 - TabIndex = 4 - Top = 240 - Width = 255 - End -End -Attribute VB_Name = "frmEmblemEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdAdd_Click() - lstEmblems.AddItem "Emblem " & lstEmblems.ListCount + 1 - lstEmblems.ListIndex = lstEmblems.ListCount - 1 - lblNumEmblems.Caption = "# of Emblems: " & lstEmblems.ListCount - txtX.Text = 0 - txtY.Text = 0 - txtZ.Text = 0 - txtPlayernum.Text = 255 - txtMapnum.Text = 1 -End Sub - -Private Sub cmdDelete_Click() - Call WriteEmblem(True) - lstEmblems.RemoveItem lstEmblems.ListCount - 1 - lstEmblems.ListIndex = lstEmblems.ListCount - 1 - lblNumEmblems.Caption = "# of Emblems: " & lstEmblems.ListCount -End Sub - -Private Sub cmdReload_Click() - Call Reload -End Sub - -Private Sub Reload() - lstEmblems.Clear - txtX.Text = "" - txtY.Text = "" - txtZ.Text = "" - txtMapnum.Text = "" - txtPlayernum.Text = "" - lblNumEmblems.Caption = "# of Emblems: " & lstEmblems.ListCount - Call ReadSOCEmblems -End Sub - -Private Sub cmdSave_Click() - If lstEmblems.ListCount <= 0 Then - MsgBox "You have no emblems to save!" - Else - Call WriteEmblem(False) - End If -End Sub - -Private Sub Form_Load() - Call Reload -End Sub - -Private Sub ReadSOCEmblems() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - - lstEmblems.Clear - -EmblemLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo EmblemLoad - - If Left(line, 1) = vbCrLf Then GoTo EmblemLoad - - If Len(line) < 1 Then GoTo EmblemLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "EMBLEM" Then - lstEmblems.AddItem ("Emblem " & Val(word2)) - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ReadSOCEmblemNum(num As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -EmblemLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo EmblemLoad - - If Left(line, 1) = vbCrLf Then GoTo EmblemLoad - - If Len(line) < 1 Then GoTo EmblemLoad - - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - If word = "EMBLEM" Then - If Val(word2) = num Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "X" Then - txtX.Text = Val(word2) - ElseIf word = "Y" Then - txtY.Text = Val(word2) - ElseIf word = "Z" Then - txtZ.Text = Val(word2) - ElseIf word = "PLAYERNUM" Then - txtPlayernum.Text = Val(word2) - ElseIf word = "MAPNUM" Then - txtMapnum.Text = Val(word2) - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC with Emblem " & num & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub lstEmblems_Click() - Dim i As Integer - - i = InStr(lstEmblems.List(lstEmblems.ListIndex), " ") + 1 - - i = Mid(lstEmblems.List(lstEmblems.ListIndex), i, Len(lstEmblems.List(lstEmblems.ListIndex)) - i + 1) - i = Val(i) - Call ReadSOCEmblemNum(i) -End Sub - -Private Sub WriteEmblem(Remove As Boolean) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim i As Integer - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - i = InStr(lstEmblems.List(lstEmblems.ListIndex), " ") + 1 - - i = Mid(lstEmblems.List(lstEmblems.ListIndex), i, Len(lstEmblems.List(lstEmblems.ListIndex)) - i + 1) - i = Val(i) - - 'If the current emblem exists in the SOC, delete it. - If word = "EMBLEM" And Val(word2) = i Then - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not (tsSource.AtEndOfStream) - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine UCase(lstEmblems.List(lstEmblems.ListIndex)) - txtX.Text = TrimComplete(txtX.Text) - txtY.Text = TrimComplete(txtY.Text) - txtZ.Text = TrimComplete(txtZ.Text) - txtMapnum.Text = TrimComplete(txtMapnum.Text) - txtPlayernum.Text = TrimComplete(txtPlayernum.Text) - If txtX.Text <> "" Then tsTarget.WriteLine "X = " & Val(txtX.Text) - If txtY.Text <> "" Then tsTarget.WriteLine "Y = " & Val(txtY.Text) - If txtZ.Text <> "" Then tsTarget.WriteLine "Z = " & Val(txtZ.Text) - If txtMapnum.Text <> "" Then tsTarget.WriteLine "MAPNUM = " & Val(txtMapnum.Text) - If txtPlayernum.Text <> "" Then tsTarget.WriteLine "PLAYERNUM = " & Val(txtPlayernum.Text) - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - MsgBox "Emblem deleted." - Else - MsgBox "Emblem Saved." - End If -End Sub diff --git a/tools/SOCEdit/frmEmblemEdit.frx b/tools/SOCEdit/frmEmblemEdit.frx deleted file mode 100644 index 2ae367330..000000000 Binary files a/tools/SOCEdit/frmEmblemEdit.frx and /dev/null differ diff --git a/tools/SOCEdit/frmHUDEdit.frm b/tools/SOCEdit/frmHUDEdit.frm deleted file mode 100644 index 2b267b79b..000000000 --- a/tools/SOCEdit/frmHUDEdit.frm +++ /dev/null @@ -1,315 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmHUDEdit - Caption = "HUD Edit" - ClientHeight = 2505 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 5160 - Icon = "frmHUDEdit.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 2505 - ScaleWidth = 5160 - StartUpPosition = 3 'Windows Default - Begin VB.CommandButton cmdCodeDefault - Caption = "&Load Code Default" - Height = 375 - Left = 3480 - TabIndex = 9 - Top = 1080 - Width = 1575 - End - Begin VB.CommandButton cmdDelete - Caption = "&Delete from SOC" - Height = 375 - Left = 3480 - TabIndex = 7 - Top = 2040 - Width = 1575 - End - Begin VB.CommandButton cmdSave - Caption = "&Save Changes" - Height = 375 - Left = 3480 - TabIndex = 6 - Top = 1560 - Width = 1575 - End - Begin VB.TextBox txtY - Height = 285 - Left = 4080 - MaxLength = 3 - TabIndex = 3 - Top = 720 - Width = 615 - End - Begin VB.TextBox txtX - Height = 285 - Left = 4080 - MaxLength = 3 - TabIndex = 2 - Top = 360 - Width = 615 - End - Begin VB.ListBox lstHUD - Height = 2010 - Left = 120 - TabIndex = 0 - Top = 360 - Width = 3255 - End - Begin VB.Label lblNote - Caption = "HUD items are placed on a 320x200 grid." - Height = 255 - Left = 1680 - TabIndex = 8 - Top = 120 - Width = 3015 - End - Begin VB.Label lblY - Alignment = 1 'Right Justify - Caption = "Y:" - Height = 255 - Left = 3600 - TabIndex = 5 - Top = 720 - Width = 375 - End - Begin VB.Label lblX - Alignment = 1 'Right Justify - Caption = "X:" - Height = 255 - Left = 3720 - TabIndex = 4 - Top = 360 - Width = 255 - End - Begin VB.Label lblHUDItems - Caption = "HUD Items:" - Height = 255 - Left = 120 - TabIndex = 1 - Top = 120 - Width = 975 - End -End -Attribute VB_Name = "frmHUDEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdCodeDefault_Click() - LoadHUDInfo (lstHUD.ListIndex) -End Sub - -Private Sub cmdDelete_Click() - Call WriteHUDItem(True) -End Sub - -Private Sub cmdSave_Click() - Call WriteHUDItem(False) -End Sub - -Private Sub Form_Load() - Call Reload -End Sub - -Private Sub Reload() - txtX.Text = "" - txtY.Text = "" - Call LoadCode - lstHUD.ListIndex = 0 -End Sub - -Private Sub LoadCode() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("st_stuff.h", ForReading, False) - - Do While ts.ReadLine <> "/** HUD location information (don't move this comment)" - Loop - - ts.ReadLine ' */ - ts.ReadLine ' typedef struct - ts.ReadLine ' { - ts.ReadLine ' int x, y; - ts.ReadLine ' } hudinfo_t; - ts.ReadLine ' - ts.ReadLine ' typedef enum - ts.ReadLine ' { - - line = ts.ReadLine - number = 0 - - lstHUD.Clear - - Do While InStr(line, "NUMHUDITEMS") = 0 - startclip = InStr(line, "HUD_") - If InStr(line, "HUD_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - lstHUD.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub lstHUD_Click() - LoadHUDInfo (lstHUD.ListIndex) - Call ReadSOC(lstHUD.ListIndex) -End Sub - -Private Sub LoadHUDInfo(HUDNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("st_stuff.c", ForReading, False) - - Do While InStr(ts.ReadLine, "hudinfo[NUMHUDITEMS] =") = 0 - Loop - - ts.SkipLine ' { - line = ts.ReadLine ' First HUD item - - number = 0 - - Do While number <> HUDNum - line = ts.ReadLine - number = number + 1 - Loop - - startclip = InStr(line, "{") + 1 - endclip = InStr(line, ",") - - txtX.Text = TrimComplete(Mid(line, startclip, endclip - startclip)) - - startclip = endclip + 2 - endclip = InStr(startclip, line, "}") - 1 - - txtY.Text = TrimComplete(Mid(line, startclip, endclip - startclip)) - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ReadSOC(HUDNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "HUDITEM" And Val(word2) = HUDNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "X" Then - txtX.Text = Val(word2) - ElseIf word = "Y" Then - txtY.Text = Val(word2) - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub WriteHUDItem(Remove As Boolean) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim hudremoved As Boolean - - hudremoved = False - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the current item exists in the SOC, delete it. - If word = "HUDITEM" And Val(word2) = lstHUD.ListIndex Then - hudremoved = True - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not tsSource.AtEndOfStream - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "HUDITEM " & lstHUD.ListIndex - txtX.Text = TrimComplete(txtX.Text) - txtY.Text = TrimComplete(txtY.Text) - If txtX.Text <> "" Then tsTarget.WriteLine "X = " & Val(txtX.Text) - If txtY.Text <> "" Then tsTarget.WriteLine "Y = " & Val(txtY.Text) - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - If hudremoved = True Then - MsgBox "HUD Item deleted from SOC." - Else - MsgBox "Couldn't find HUD Item in SOC." - End If - Else - MsgBox "HUD Item Saved." - End If -End Sub diff --git a/tools/SOCEdit/frmHUDEdit.frx b/tools/SOCEdit/frmHUDEdit.frx deleted file mode 100644 index 2ae367330..000000000 Binary files a/tools/SOCEdit/frmHUDEdit.frx and /dev/null differ diff --git a/tools/SOCEdit/frmHelp.frm b/tools/SOCEdit/frmHelp.frm deleted file mode 100644 index acf991057..000000000 --- a/tools/SOCEdit/frmHelp.frm +++ /dev/null @@ -1,213 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmHelp - BorderStyle = 3 'Fixed Dialog - Caption = "Getting Started" - ClientHeight = 7395 - ClientLeft = 45 - ClientTop = 330 - ClientWidth = 6360 - Icon = "frmHelp.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - MinButton = 0 'False - ScaleHeight = 7395 - ScaleWidth = 6360 - ShowInTaskbar = 0 'False - StartUpPosition = 1 'CenterOwner - Begin VB.CommandButton cmdOK - Caption = "&OK, I know what I'm doing now." - Height = 495 - Left = 1920 - Style = 1 'Graphical - TabIndex = 8 - Top = 6840 - Width = 2535 - End - Begin VB.Line Line9 - X1 = 120 - X2 = 6120 - Y1 = 4800 - Y2 = 4800 - End - Begin VB.Line Line7 - X1 = 120 - X2 = 6120 - Y1 = 5400 - Y2 = 5400 - End - Begin VB.Label Label12 - Caption = $"frmHelp.frx":0442 - Height = 615 - Left = 120 - TabIndex = 12 - Top = 4800 - Width = 6015 - End - Begin VB.Line Line6 - X1 = 120 - X2 = 6120 - Y1 = 4200 - Y2 = 4200 - End - Begin VB.Label Label11 - Caption = $"frmHelp.frx":04F8 - Height = 615 - Left = 120 - TabIndex = 11 - Top = 4200 - Width = 6015 - End - Begin VB.Line Line8 - X1 = 120 - X2 = 6120 - Y1 = 6360 - Y2 = 6360 - End - Begin VB.Line Line5 - X1 = 120 - X2 = 6120 - Y1 = 3720 - Y2 = 3720 - End - Begin VB.Line Line4 - X1 = 120 - X2 = 6120 - Y1 = 2880 - Y2 = 2880 - End - Begin VB.Line Line3 - X1 = 120 - X2 = 6120 - Y1 = 2400 - Y2 = 2400 - End - Begin VB.Line Line2 - X1 = 120 - X2 = 6120 - Y1 = 1800 - Y2 = 1800 - End - Begin VB.Line Line1 - X1 = 120 - X2 = 6120 - Y1 = 1200 - Y2 = 1200 - End - Begin VB.Label Label10 - Caption = $"frmHelp.frx":05EC - Height = 495 - Left = 120 - TabIndex = 10 - Top = 3720 - Width = 6135 - End - Begin VB.Label Label9 - Caption = $"frmHelp.frx":068F - Height = 615 - Left = 120 - TabIndex = 9 - Top = 1200 - Width = 6135 - End - Begin VB.Label Label8 - Caption = $"frmHelp.frx":0772 - Height = 495 - Left = 120 - TabIndex = 7 - Top = 6360 - Width = 6135 - End - Begin VB.Label Label7 - Caption = "However, if you have these settings in the SOC you are using, don't worry - the editor will not erase them from your file." - Height = 495 - Left = 120 - TabIndex = 6 - Top = 5880 - Width = 6135 - End - Begin VB.Label Label6 - Caption = $"frmHelp.frx":0816 - Height = 495 - Left = 120 - TabIndex = 5 - Top = 5400 - Width = 6135 - End - Begin VB.Label Label5 - Caption = $"frmHelp.frx":08A9 - BeginProperty Font - Name = "MS Sans Serif" - Size = 8.25 - Charset = 0 - Weight = 700 - Underline = 0 'False - Italic = 0 'False - Strikethrough = 0 'False - EndProperty - Height = 855 - Left = 120 - TabIndex = 4 - Top = 2880 - Width = 6135 - End - Begin VB.Label Label4 - Caption = $"frmHelp.frx":09B1 - Height = 495 - Left = 120 - TabIndex = 3 - Top = 2400 - Width = 6135 - End - Begin VB.Label Label3 - Caption = $"frmHelp.frx":0A5A - Height = 495 - Left = 120 - TabIndex = 2 - Top = 1920 - Width = 6135 - End - Begin VB.Label Label2 - Caption = "Finally! A way to easily edit SOC files! I know you're anxious to get started, but here are some things you should know first:" - BeginProperty Font - Name = "MS Sans Serif" - Size = 9.75 - Charset = 0 - Weight = 400 - Underline = 0 'False - Italic = 0 'False - Strikethrough = 0 'False - EndProperty - Height = 495 - Left = 120 - TabIndex = 1 - Top = 600 - Width = 6135 - End - Begin VB.Label Label1 - Caption = "How To Use This Program" - BeginProperty Font - Name = "MS Sans Serif" - Size = 13.5 - Charset = 0 - Weight = 700 - Underline = -1 'True - Italic = 0 'False - Strikethrough = 0 'False - EndProperty - Height = 495 - Left = 120 - TabIndex = 0 - Top = 120 - Width = 3855 - End -End -Attribute VB_Name = "frmHelp" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdOK_Click() - frmHelp.Hide -End Sub diff --git a/tools/SOCEdit/frmHelp.frx b/tools/SOCEdit/frmHelp.frx deleted file mode 100644 index 25004fe29..000000000 Binary files a/tools/SOCEdit/frmHelp.frx and /dev/null differ diff --git a/tools/SOCEdit/frmHub.frm b/tools/SOCEdit/frmHub.frm deleted file mode 100644 index 3672c62b0..000000000 --- a/tools/SOCEdit/frmHub.frm +++ /dev/null @@ -1,429 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmHub - Caption = "SOC Editor" - ClientHeight = 6960 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 4920 - Icon = "frmHub.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 6960 - ScaleWidth = 4920 - StartUpPosition = 3 'Windows Default - Begin VB.CommandButton cmdCreateBlank - Caption = "Make a &Blank SOC" - Height = 255 - Left = 240 - TabIndex = 22 - Top = 2520 - Width = 2055 - End - Begin VB.CommandButton cmdUnlockables - Caption = "Edit &Unlockables" - Enabled = 0 'False - Height = 495 - Left = 2760 - Style = 1 'Graphical - TabIndex = 21 - Top = 6360 - Width = 1095 - End - Begin VB.CommandButton cmdAuthor - Caption = "Enter &Author Info" - Enabled = 0 'False - Height = 495 - Left = 120 - Style = 1 'Graphical - TabIndex = 19 - Top = 3960 - Width = 1215 - End - Begin VB.CommandButton cmdHelp - Caption = "Getting Starte&d / READ ME FIRST!" - Height = 495 - Left = 480 - TabIndex = 18 - Top = 2880 - Width = 1575 - End - Begin VB.CommandButton cmdEditCutscenes - Caption = "Edit C&utscenes" - Enabled = 0 'False - Height = 495 - Left = 120 - TabIndex = 17 - Top = 6360 - Width = 1215 - End - Begin VB.CommandButton cmdCharacterEdit - Caption = "Edit &Character Select Screen" - Enabled = 0 'False - Height = 495 - Left = 120 - Style = 1 'Graphical - TabIndex = 16 - Top = 5760 - Width = 1215 - End - Begin VB.PictureBox Picture1 - Height = 1965 - Left = 2760 - Picture = "frmHub.frx":0442 - ScaleHeight = 1905 - ScaleWidth = 1905 - TabIndex = 15 - Top = 3960 - Width = 1965 - End - Begin VB.CommandButton cmdSoundEdit - Caption = "Edit &Sounds" - Enabled = 0 'False - Height = 495 - Left = 120 - TabIndex = 14 - Top = 5160 - Width = 1215 - End - Begin VB.CommandButton cmdEmblemEdit - Caption = "Edit &Emblem Locations" - Enabled = 0 'False - Height = 495 - Left = 120 - Style = 1 'Graphical - TabIndex = 13 - Top = 4560 - Width = 1215 - End - Begin VB.CommandButton cmdHUDEdit - Caption = "Edit &HUD Coordinates" - Enabled = 0 'False - Height = 495 - Left = 1440 - Style = 1 'Graphical - TabIndex = 12 - Top = 3960 - Width = 1215 - End - Begin VB.CommandButton cmdMaincfg - Caption = "Edit &Global Game Settings" - Enabled = 0 'False - Height = 495 - Left = 1440 - Style = 1 'Graphical - TabIndex = 11 - Top = 4560 - Width = 1215 - End - Begin VB.DriveListBox Drive2 - Height = 315 - Left = 2640 - TabIndex = 9 - Top = 360 - Width = 2175 - End - Begin VB.DirListBox Dir2 - Height = 1665 - Left = 2520 - TabIndex = 8 - Top = 720 - Width = 2295 - End - Begin VB.FileListBox File1 - Height = 1455 - Left = 2520 - Pattern = "*.soc" - TabIndex = 7 - Top = 2400 - Width = 2295 - End - Begin VB.DriveListBox Drive1 - Height = 315 - Left = 120 - TabIndex = 6 - Top = 360 - Width = 2295 - End - Begin VB.DirListBox Dir1 - Height = 1665 - Left = 120 - TabIndex = 4 - Top = 720 - Width = 2295 - End - Begin VB.CommandButton cmdAbout - Caption = "&About" - Height = 375 - Left = 3960 - TabIndex = 3 - Top = 6000 - Width = 735 - End - Begin VB.CommandButton cmdStateEdit - Caption = "Edit St&ates" - Enabled = 0 'False - Height = 495 - Left = 1440 - TabIndex = 2 - Top = 6360 - Width = 1215 - End - Begin VB.CommandButton cmdLevelHeader - Caption = "Edit &Level Headers" - Enabled = 0 'False - Height = 495 - Left = 1440 - Style = 1 'Graphical - TabIndex = 1 - Top = 5160 - Width = 1215 - End - Begin VB.CommandButton cmdThingEdit - Caption = "Edit &Things" - Enabled = 0 'False - Height = 495 - Left = 1440 - TabIndex = 0 - Top = 5760 - Width = 1215 - End - Begin VB.Label lblAuthor - Caption = "Modification By:" - Height = 495 - Left = 120 - TabIndex = 20 - Top = 3480 - Width = 2295 - End - Begin VB.Label lblSOCFile - Caption = "SOC File to use (double click):" - Height = 255 - Left = 2640 - TabIndex = 10 - Top = 120 - Width = 2175 - End - Begin VB.Label lblSourcePath - Caption = "Path to SRB2 Source Code:" - Height = 255 - Left = 120 - TabIndex = 5 - Top = 120 - Width = 2175 - End -End -Attribute VB_Name = "frmHub" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdAbout_Click() - MsgBox App.Title & " v" & App.Major & "." & App.Minor & "." & App.Revision & vbCrLf & "By " & App.CompanyName & vbCrLf & "(SSNTails)" & vbCrLf & App.Comments & vbCrLf & App.FileDescription -End Sub - -Private Sub cmdAuthor_Click() - Dim Response As String - - Response$ = InputBox("Enter name to appear on credits (type in NOBODY to delete):", "Modification By", GetAuthor) - - If Response = "" Then Exit Sub - - Response = TrimComplete(Response) - - If UCase(Response) = "NOBODY" Then - Call WriteAuthor(True, Response) - lblAuthor.Caption = "Modification By: " - Else - Call WriteAuthor(False, Response) - lblAuthor.Caption = "Modification By: " & Response - End If -End Sub - -Private Sub cmdCharacterEdit_Click() - frmCharacterEdit.Show vbModal, Me -End Sub - -Private Sub cmdCreateBlank_Click() - Dim socname As String - - socname = InputBox("This file will be created in the directory you have selected on the main window." & vbCrLf & vbCrLf & "Enter the filename you want (do not include .SOC at the end):", "Make A Blank SOC") - Trim (socname) - - If InStr(LCase(socname), ".soc") > 0 Then - MsgBox "The thing says not to include the .SOC at the end, stupid.", vbOKOnly, "You goofed!" - Exit Sub - End If - - If Len(socname) > 0 Then - socname = socname & ".soc" - - Dim myFSOSOC As New Scripting.FileSystemObject - Dim tsSOC As TextStream - - Set tsSOC = myFSOSOC.OpenTextFile(File1.Path & "\" & socname, ForWriting, True) - tsSOC.Close - Set myFSOSOC = Nothing - - MsgBox "Blank SOC named " & socname & " created in " & File1.Path, vbOKOnly, "Success!" - End If -End Sub - -Private Sub cmdEditCutscenes_Click() - frmCutsceneEdit.Show vbModal, Me -End Sub - -Private Sub cmdEmblemEdit_Click() - frmEmblemEdit.Show vbModal, Me -End Sub - -Private Sub cmdHelp_Click() - frmHelp.Show vbModal, Me -End Sub - -Private Sub cmdHUDEdit_Click() - frmHUDEdit.Show vbModal, Me -End Sub - -Private Sub cmdLevelHeader_Click() - frmLevelHeader.Show vbModal, Me -End Sub - -Private Sub cmdMaincfg_Click() - frmMaincfg.Show vbModal, Me -End Sub - -Private Sub cmdSoundEdit_Click() - frmSoundEdit.Show vbModal, Me -End Sub - -Private Sub cmdStateEdit_Click() - frmStateEdit.Show vbModal, Me -End Sub - -Private Sub cmdThingEdit_Click() - frmThingEdit.Show vbModal, Me -End Sub - -Private Sub cmdUnlockables_Click() - frmUnlockablesEdit.Show vbModal, Me -End Sub - -Private Sub Dir1_Change() - SourcePath = Dir1.Path -End Sub - -Private Sub Dir2_Change() - File1.Path = Dir2.Path -End Sub - -Private Sub Drive1_Change() - Dir1.Path = Drive1.Drive -End Sub - -Private Sub Drive2_Change() - Dir2.Path = Drive2.Drive -End Sub - -Private Sub File1_DblClick() - SOCTemp = File1.Path & "\" & "socedit.tmp" - SOCFile = File1.Path & "\" & File1.List(File1.ListIndex) - MsgBox "You are now using the file: " & vbCrLf & SOCFile - cmdLevelHeader.Enabled = True - cmdThingEdit.Enabled = True - cmdStateEdit.Enabled = True - cmdHUDEdit.Enabled = True - cmdMaincfg.Enabled = True - cmdEmblemEdit.Enabled = True - cmdSoundEdit.Enabled = True - cmdCharacterEdit.Enabled = True - cmdEditCutscenes.Enabled = True - cmdAuthor.Enabled = True - cmdUnlockables.Enabled = True - lblAuthor.Caption = "Modification By: " & GetAuthor -End Sub - -Private Sub Form_Load() - SourcePath = App.Path - Dir1.Path = SourcePath -End Sub - -Private Function GetAuthor() As String - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "MODBY" Then - GetAuthor = word2 - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Function - -Private Sub WriteAuthor(Remove As Boolean, ModderName As String) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the entry exists in the SOC, delete it. - If word <> "MODBY" Then - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "ModBy " & ModderName - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - MsgBox "Name removed." - Else - MsgBox "Name Saved." - End If -End Sub - diff --git a/tools/SOCEdit/frmHub.frx b/tools/SOCEdit/frmHub.frx deleted file mode 100644 index 176491ab6..000000000 Binary files a/tools/SOCEdit/frmHub.frx and /dev/null differ diff --git a/tools/SOCEdit/frmLevelHeader.frm b/tools/SOCEdit/frmLevelHeader.frm deleted file mode 100644 index e30acd581..000000000 --- a/tools/SOCEdit/frmLevelHeader.frm +++ /dev/null @@ -1,839 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmLevelHeader - Caption = "Level Header Info" - ClientHeight = 5250 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 7650 - Icon = "frmLevelHeader.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 5250 - ScaleWidth = 7650 - StartUpPosition = 3 'Windows Default - Begin VB.TextBox txtRunSOC - Height = 285 - Left = 6240 - MaxLength = 8 - TabIndex = 49 - Top = 4680 - Width = 1215 - End - Begin VB.CheckBox chkLevelSelect - Caption = "Show on Host Game selection menu" - Height = 375 - Left = 1680 - TabIndex = 48 - Top = 4800 - Width = 1935 - End - Begin VB.CheckBox chkTimeAttack - Caption = "Include in Time Attack calculations" - Height = 255 - Left = 1680 - TabIndex = 47 - Top = 4440 - Width = 2775 - End - Begin VB.CheckBox chkNoReload - Caption = "Retain level state when player dies." - Height = 255 - Left = 1680 - TabIndex = 46 - Top = 4080 - Width = 2895 - End - Begin VB.CommandButton cmdSave - Caption = "&Save Map" - Height = 735 - Left = 120 - Style = 1 'Graphical - TabIndex = 45 - Top = 4440 - Width = 1215 - End - Begin VB.CommandButton cmdRename - Caption = "&Rename Map" - Height = 375 - Left = 120 - TabIndex = 44 - Top = 3960 - Width = 1215 - End - Begin VB.CommandButton cmdDelete - Caption = "&Delete Map" - Height = 375 - Left = 120 - TabIndex = 43 - Top = 3480 - Width = 1215 - End - Begin VB.CommandButton cmdAddMap - Caption = "&Add Map" - Height = 375 - Left = 120 - TabIndex = 42 - Top = 3000 - Width = 1215 - End - Begin VB.CheckBox chkNossmusic - Caption = "Disable Super Sonic music changes" - Height = 255 - Left = 4560 - TabIndex = 29 - Top = 1200 - Width = 2895 - End - Begin VB.CheckBox chkHidden - Caption = "Don't show on level selection menu" - Height = 255 - Left = 4560 - TabIndex = 28 - Top = 480 - Width = 2895 - End - Begin VB.TextBox txtCountdown - Height = 285 - Left = 6360 - MaxLength = 3 - TabIndex = 26 - Top = 840 - Width = 735 - End - Begin VB.TextBox txtCutscenenum - Height = 285 - Left = 4440 - MaxLength = 3 - TabIndex = 25 - Top = 3720 - Width = 495 - End - Begin VB.TextBox txtPrecutscenenum - Height = 285 - Left = 2640 - MaxLength = 3 - TabIndex = 22 - Top = 3720 - Width = 495 - End - Begin VB.CheckBox chkScriptislump - Caption = "Script is a lump in WAD, not a file" - Height = 255 - Left = 1680 - TabIndex = 21 - Top = 3360 - Width = 2775 - End - Begin VB.TextBox txtScriptname - Height = 285 - Left = 2640 - MaxLength = 191 - TabIndex = 19 - Top = 3000 - Width = 1455 - End - Begin VB.TextBox txtSkynum - Height = 285 - Left = 2640 - MaxLength = 4 - TabIndex = 17 - Top = 2640 - Width = 495 - End - Begin VB.ComboBox cmbWeather - Height = 315 - ItemData = "frmLevelHeader.frx":0442 - Left = 2640 - List = "frmLevelHeader.frx":0458 - TabIndex = 15 - Top = 2280 - Width = 2295 - End - Begin VB.TextBox txtForcecharacter - Height = 285 - Left = 2640 - MaxLength = 2 - TabIndex = 13 - Top = 1920 - Width = 495 - End - Begin VB.ComboBox cmbMusicslot - Height = 315 - Left = 2640 - TabIndex = 11 - Top = 1560 - Width = 1815 - End - Begin VB.TextBox txtNextlevel - Height = 285 - Left = 2640 - MaxLength = 4 - TabIndex = 9 - Top = 1200 - Width = 615 - End - Begin VB.Frame frmTypeOfLevel - Caption = "Type of Level" - Height = 2775 - Left = 5040 - TabIndex = 8 - Top = 1680 - Width = 2535 - Begin VB.CheckBox chkTypeoflevel - Caption = "Christmas" - Height = 255 - Index = 11 - Left = 1440 - TabIndex = 41 - Tag = "1024" - Top = 960 - Width = 975 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "2D" - Height = 255 - Index = 10 - Left = 1440 - TabIndex = 40 - Tag = "512" - Top = 720 - Width = 735 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Mario" - Height = 255 - Index = 9 - Left = 120 - TabIndex = 39 - Tag = "256" - Top = 2400 - Width = 1455 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Sonic Adventure" - Height = 255 - Index = 8 - Left = 120 - TabIndex = 38 - Tag = "128" - Top = 2160 - Width = 1575 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "NiGHTS" - Height = 255 - Index = 7 - Left = 120 - TabIndex = 37 - Tag = "64" - Top = 1920 - Width = 1335 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Chaos" - Height = 255 - Index = 6 - Left = 120 - TabIndex = 36 - Tag = "32" - Top = 1680 - Width = 1455 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Capture the Flag" - Height = 255 - Index = 5 - Left = 120 - TabIndex = 35 - Tag = "16" - Top = 1440 - Width = 1695 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Tag" - Height = 255 - Index = 4 - Left = 120 - TabIndex = 34 - Tag = "8" - Top = 1200 - Width = 1215 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Match" - Height = 255 - Index = 3 - Left = 120 - TabIndex = 33 - Tag = "4" - Top = 960 - Width = 855 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Race" - Height = 255 - Index = 2 - Left = 120 - TabIndex = 32 - Tag = "2" - Top = 720 - Width = 855 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Cooperative" - Height = 255 - Index = 1 - Left = 120 - TabIndex = 31 - Tag = "1" - Top = 480 - Width = 1215 - End - Begin VB.CheckBox chkTypeoflevel - Caption = "Single Player" - Height = 255 - Index = 0 - Left = 120 - TabIndex = 30 - Tag = "4096" - Top = 240 - Width = 1215 - End - End - Begin VB.CheckBox chkNozone - Caption = "Don't show ""ZONE"" after Level Name" - Height = 255 - Left = 4560 - TabIndex = 7 - Top = 120 - Width = 3015 - End - Begin VB.TextBox txtAct - Height = 285 - Left = 2640 - MaxLength = 2 - TabIndex = 5 - Top = 840 - Width = 495 - End - Begin VB.TextBox txtInterscreen - Height = 285 - Left = 2640 - MaxLength = 8 - TabIndex = 3 - Top = 480 - Width = 1335 - End - Begin VB.ListBox lstMaps - Height = 2790 - Left = 120 - Sorted = -1 'True - TabIndex = 2 - Top = 120 - Width = 1215 - End - Begin VB.TextBox txtLevelName - Height = 285 - Left = 2640 - MaxLength = 32 - TabIndex = 0 - Top = 120 - Width = 1815 - End - Begin VB.Label lblRunSOC - Alignment = 1 'Right Justify - Caption = "Run SOC at level load (lump name):" - Height = 495 - Left = 4440 - TabIndex = 50 - Top = 4560 - Width = 1695 - End - Begin VB.Label lblCountdown - Alignment = 1 'Right Justify - Caption = "Level Timer (seconds):" - Height = 255 - Left = 4560 - TabIndex = 27 - Top = 840 - Width = 1695 - End - Begin VB.Label lblCutscenenum - Alignment = 1 'Right Justify - Caption = "Cutscene to play after level:" - Height = 495 - Left = 3240 - TabIndex = 24 - Top = 3600 - Width = 1095 - End - Begin VB.Label lblPrecutscenenum - Alignment = 1 'Right Justify - Caption = "Cutscene to play before level:" - Height = 375 - Left = 1320 - TabIndex = 23 - Top = 3600 - Width = 1215 - End - Begin VB.Label lblScriptName - Alignment = 1 'Right Justify - Caption = "Script Name:" - Height = 255 - Left = 1440 - TabIndex = 20 - Top = 3000 - Width = 1095 - End - Begin VB.Label lblSkynum - Alignment = 1 'Right Justify - Caption = "Sky #:" - Height = 255 - Left = 1800 - TabIndex = 18 - Top = 2640 - Width = 735 - End - Begin VB.Label Label1 - Alignment = 1 'Right Justify - Caption = "Weather:" - Height = 255 - Left = 1680 - TabIndex = 16 - Top = 2280 - Width = 855 - End - Begin VB.Label lblForcecharacter - Caption = "Force Character #:" - Height = 375 - Left = 1440 - TabIndex = 14 - Top = 1800 - Width = 1095 - End - Begin VB.Label lblMusicslot - Alignment = 1 'Right Justify - Caption = "Music:" - Height = 255 - Left = 1800 - TabIndex = 12 - Top = 1560 - Width = 735 - End - Begin VB.Label lblNextlevel - Alignment = 1 'Right Justify - Caption = "Next Level:" - Height = 255 - Left = 1440 - TabIndex = 10 - Top = 1200 - Width = 1095 - End - Begin VB.Label lblAct - Alignment = 1 'Right Justify - Caption = "Act:" - Height = 255 - Left = 2040 - TabIndex = 6 - Top = 840 - Width = 495 - End - Begin VB.Label lblInterscreen - Alignment = 1 'Right Justify - Caption = "Intermission BG:" - Height = 255 - Left = 1320 - TabIndex = 4 - Top = 480 - Width = 1215 - End - Begin VB.Label lblLevelName - Alignment = 1 'Right Justify - Caption = "Level Name:" - Height = 255 - Left = 1560 - TabIndex = 1 - Top = 120 - Width = 975 - End -End -Attribute VB_Name = "frmLevelHeader" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdAddMap_Click() - Dim Response As String - Dim NewNum As Integer - - Response$ = InputBox("Enter the new level (NUMBER ONLY):") - - If Response = "" Then - Exit Sub - End If - - NewNum = Val(TrimComplete(Response)) - - lstMaps.AddItem "Level " & NewNum - lstMaps.ListIndex = lstMaps.ListCount - 1 -End Sub - -Private Sub cmdDelete_Click() - Dim i As Integer - - If MsgBox("Delete this level header?", vbYesNo) = vbNo Then - Exit Sub - End If - - i = InStr(lstMaps.List(lstMaps.ListIndex), " ") + 1 - - i = Mid(lstMaps.List(lstMaps.ListIndex), i, Len(lstMaps.List(lstMaps.ListIndex)) - i + 1) - i = Val(i) - Call WriteLevel(True, i) - lstMaps.RemoveItem lstMaps.ListIndex - - If lstMaps.ListCount > 0 Then - lstMaps.ListIndex = 0 - End If -End Sub - -Private Sub cmdRename_Click() - Dim Response As String - Dim NewNum As Integer - Dim i As Integer - - Response$ = InputBox("Rename level to (NUMBER ONLY):") - - If Response = "" Then - Exit Sub - End If - - NewNum = Val(TrimComplete(Response)) - - i = InStr(lstMaps.List(lstMaps.ListIndex), " ") + 1 - - i = Mid(lstMaps.List(lstMaps.ListIndex), i, Len(lstMaps.List(lstMaps.ListIndex)) - i + 1) - i = Val(i) - Call WriteLevel(True, i) - lstMaps.List(lstMaps.ListIndex) = "Level " & NewNum - Call cmdSave_Click -End Sub - -Private Sub cmdSave_Click() - Dim i As Integer - - i = InStr(lstMaps.List(lstMaps.ListIndex), " ") + 1 - - i = Val(Mid(lstMaps.List(lstMaps.ListIndex), i, Len(lstMaps.List(lstMaps.ListIndex)) - i + 1)) - Call WriteLevel(False, i) -End Sub - -Private Sub Form_Load() - Call LoadMusic - Call LoadSOCMaps - If lstMaps.ListCount > 0 Then lstMaps.ListIndex = 0 -End Sub - -Private Sub LoadSOCMaps() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - - lstMaps.Clear - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "LEVEL" Then - lstMaps.AddItem ("Level " & Val(word2)) - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub LoadMusic() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("sounds.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Music list (don't edit this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - cmbMusicslot.Clear - - Do While InStr(line, "NUMMUSIC") = 0 - startclip = InStr(line, "mus_") - If InStr(line, "mus_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - cmbMusicslot.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ClearForm() - Dim j As Integer - - txtLevelName.Text = "" - txtInterscreen.Text = "" - txtAct.Text = "" - txtNextlevel.Text = "" - cmbMusicslot.Text = "" - txtForcecharacter.Text = "" - cmbWeather.Text = "" - txtSkynum.Text = "" - txtScriptname.Text = "" - chkScriptislump.Value = 0 - txtPrecutscenenum.Text = "" - txtCutscenenum.Text = "" - txtRunSOC.Text = "" - chkNozone.Value = 0 - chkHidden.Value = 0 - txtCountdown.Text = "" - chkNossmusic.Value = 0 - chkNoReload.Value = 0 - chkTimeAttack.Value = 0 - chkLevelSelect = 0 - - For j = 0 To 11 - chkTypeoflevel(j).Value = 0 - Next j -End Sub - -Private Sub lstMaps_Click() - Dim startclip As Integer - Call ClearForm - startclip = InStr(lstMaps.List(lstMaps.ListIndex), " ") - Call LoadSOCMapInfo(Val(Mid(lstMaps.List(lstMaps.ListIndex), startclip + 1, Len(lstMaps.List(lstMaps.ListIndex))))) -End Sub - -Private Sub LoadSOCMapInfo(num As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - If word = "LEVEL" Then - If Val(word2) = num Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "LEVELNAME" Then - txtLevelName.Text = word2 - ElseIf word = "INTERSCREEN" Then - txtInterscreen.Text = word2 - ElseIf word = "ACT" Then - txtAct.Text = Val(word2) - ElseIf word = "NOZONE" Then - chkNozone.Value = Val(word2) - ElseIf word = "TYPEOFLEVEL" Then - ProcessMapFlags (Val(word2)) - ElseIf word = "NEXTLEVEL" Then - txtNextlevel.Text = Val(word2) - ElseIf word = "MUSICSLOT" Then - cmbMusicslot.ListIndex = Val(word2) - ElseIf word = "FORCECHARACTER" Then - txtForcecharacter.Text = Val(word2) - ElseIf word = "WEATHER" Then - cmbWeather.ListIndex = Val(word2) - ElseIf word = "SKYNUM" Then - txtSkynum.Text = Val(word2) - ElseIf word = "SCRIPTNAME" Then - txtScriptname.Text = word2 - ElseIf word = "SCRIPTISLUMP" Then - chkScriptislump.Value = Val(word2) - ElseIf word = "PRECUTSCENENUM" Then - txtPrecutscenenum.Text = Val(word2) - ElseIf word = "CUTSCENENUM" Then - txtCutscenenum.Text = Val(word2) - ElseIf word = "COUNTDOWN" Then - txtCountdown.Text = Val(word2) - ElseIf word = "HIDDEN" Then - chkHidden.Value = Val(word2) - ElseIf word = "NOSSMUSIC" Then - chkNossmusic.Value = Val(word2) - ElseIf word = "NORELOAD" Then - chkNoReload.Value = Val(word2) - ElseIf word = "TIMEATTACK" Then - chkTimeAttack.Value = Val(word2) - ElseIf word = "LEVELSELECT" Then - chkLevelSelect.Value = Val(word2) - ElseIf word = "RUNSOC" Then - txtRunSOC.Text = word2 - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ProcessMapFlags(flags As Long) - Dim j As Integer - - For j = 0 To 11 - If flags And chkTypeoflevel(j).Tag Then - chkTypeoflevel(j).Value = 1 - Else - chkTypeoflevel(j).Value = 0 - End If - Next j -End Sub - -Private Sub WriteLevel(Remove As Boolean, Mapnum As Integer) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim flags As Long - Dim i As Integer - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - i = InStr(lstMaps.List(lstMaps.ListIndex), " ") + 1 - - i = Mid(lstMaps.List(lstMaps.ListIndex), i, Len(lstMaps.List(lstMaps.ListIndex)) - i + 1) - i = Val(i) - 'If the current level exists in the SOC, delete it. - If word = "LEVEL" And Val(word2) = i Then - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not (tsSource.AtEndOfStream) - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine UCase(lstMaps.List(lstMaps.ListIndex)) - txtLevelName.Text = TrimComplete(txtLevelName.Text) - txtInterscreen.Text = TrimComplete(txtInterscreen.Text) - txtAct.Text = TrimComplete(txtAct.Text) - txtNextlevel.Text = TrimComplete(txtNextlevel.Text) - cmbMusicslot.Text = TrimComplete(cmbMusicslot.Text) - txtForcecharacter.Text = TrimComplete(txtForcecharacter.Text) - cmbWeather.Text = TrimComplete(cmbWeather.Text) - txtSkynum.Text = TrimComplete(txtSkynum.Text) - txtScriptname.Text = TrimComplete(txtScriptname.Text) - txtPrecutscenenum.Text = TrimComplete(txtPrecutscenenum.Text) - txtCutscenenum.Text = TrimComplete(txtCutscenenum.Text) - txtCountdown.Text = TrimComplete(txtCountdown.Text) - txtRunSOC.Text = TrimComplete(txtRunSOC.Text) - - If txtLevelName.Text <> "" Then tsTarget.WriteLine "LEVELNAME = " & txtLevelName.Text - If txtInterscreen.Text <> "" Then tsTarget.WriteLine "INTERSCREEN = " & txtInterscreen.Text - If txtAct.Text <> "" Then tsTarget.WriteLine "ACT = " & Val(txtAct.Text) - If txtNextlevel.Text <> "" Then tsTarget.WriteLine "NEXTLEVEL = " & Val(txtNextlevel.Text) - If cmbMusicslot.Text <> "" Then tsTarget.WriteLine "MUSICSLOT = " & cmbMusicslot.ListIndex - If txtForcecharacter.Text <> "" Then tsTarget.WriteLine "FORCECHARACTER = " & Val(txtForcecharacter.Text) - If cmbWeather.Text <> "" Then tsTarget.WriteLine "WEATHER = " & cmbWeather.ListIndex - If txtSkynum.Text <> "" Then tsTarget.WriteLine "SKYNUM = " & Val(txtSkynum.Text) - If txtScriptname.Text <> "" Then tsTarget.WriteLine "SCRIPTNAME = " & txtScriptname.Text - If txtPrecutscenenum.Text <> "" Then tsTarget.WriteLine "PRECUTSCENENUM = " & Val(txtPrecutscenenum.Text) - If txtCutscenenum.Text <> "" Then tsTarget.WriteLine "CUTSCENENUM = " & Val(txtCutscenenum.Text) - If txtCountdown.Text <> "" Then tsTarget.WriteLine "COUNTDOWN = " & Val(txtCountdown.Text) - If chkScriptislump.Value = 1 Then tsTarget.WriteLine "SCRIPTISLUMP = 1" - If chkNozone.Value = 1 Then tsTarget.WriteLine "NOZONE = 1" - If chkHidden.Value = 1 Then tsTarget.WriteLine "HIDDEN = 1" - If chkNossmusic.Value = 1 Then tsTarget.WriteLine "NOSSMUSIC = 1" - If chkNoReload.Value = 1 Then tsTarget.WriteLine "NORELOAD = 1" - If chkTimeAttack.Value = 1 Then tsTarget.WriteLine "TIMEATTACK = 1" - If chkLevelSelect.Value = 1 Then tsTarget.WriteLine "LEVELSELECT = 1" - If txtRunSOC.Text <> "" Then tsTarget.WriteLine "RUNSOC = " & txtRunSOC.Text - - flags = 0 - For i = 0 To 11 - If chkTypeoflevel(i).Value = 1 Then - flags = flags + Val(chkTypeoflevel(i).Tag) - End If - Next - - If flags > 0 Then tsTarget.WriteLine "TYPEOFLEVEL = " & flags - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - MsgBox "Level Deleted." - Else - MsgBox "Level Saved." - End If -End Sub - diff --git a/tools/SOCEdit/frmLevelHeader.frx b/tools/SOCEdit/frmLevelHeader.frx deleted file mode 100644 index fe81f4413..000000000 Binary files a/tools/SOCEdit/frmLevelHeader.frx and /dev/null differ diff --git a/tools/SOCEdit/frmMaincfg.frm b/tools/SOCEdit/frmMaincfg.frm deleted file mode 100644 index 3efca74a8..000000000 --- a/tools/SOCEdit/frmMaincfg.frm +++ /dev/null @@ -1,644 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmMaincfg - Caption = "Global Game Settings" - ClientHeight = 5295 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 9360 - Icon = "frmMaincfg.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 5295 - ScaleWidth = 9360 - StartUpPosition = 3 'Windows Default - Begin VB.Frame frmReset - Caption = "Reset Data (Be sure this is at the TOP of your SOC)" - Height = 975 - Left = 4800 - TabIndex = 43 - Top = 4200 - Width = 4455 - Begin VB.CheckBox chkReset - Caption = "Thing Properties" - Height = 255 - Index = 2 - Left = 1680 - TabIndex = 46 - Tag = "4" - Top = 240 - Width = 1575 - End - Begin VB.CheckBox chkReset - Caption = "States" - Height = 255 - Index = 1 - Left = 240 - TabIndex = 45 - Tag = "2" - Top = 600 - Width = 1335 - End - Begin VB.CheckBox chkReset - Caption = "Sprite Names" - Height = 255 - Index = 0 - Left = 240 - TabIndex = 44 - Tag = "1" - Top = 240 - Width = 1575 - End - End - Begin VB.CheckBox chkDisableSpeedAdjust - Caption = "Disable speed adjustment of player animations depending on how fast they are moving." - Height = 375 - Left = 1080 - TabIndex = 42 - Top = 4200 - Width = 3615 - End - Begin VB.TextBox txtTitleScrollSpeed - Height = 285 - Left = 4080 - TabIndex = 41 - Top = 1920 - Width = 495 - End - Begin VB.CheckBox chkLoopTitle - Caption = "Loop the title screen music?" - Height = 195 - Left = 1080 - TabIndex = 39 - Top = 3840 - Width = 2415 - End - Begin VB.TextBox txtCreditsCutscene - Height = 285 - Left = 4080 - TabIndex = 37 - Top = 1560 - Width = 495 - End - Begin VB.CommandButton cmdSave - Caption = "&Save" - Height = 495 - Left = 120 - TabIndex = 36 - Top = 3120 - Width = 735 - End - Begin VB.CommandButton cmdReload - Caption = "&Reload" - Height = 495 - Left = 120 - TabIndex = 35 - Top = 2520 - Width = 735 - End - Begin VB.TextBox txtNumemblems - Height = 285 - Left = 4080 - MaxLength = 2 - TabIndex = 33 - Top = 3360 - Width = 495 - End - Begin VB.TextBox txtGamedata - Height = 285 - Left = 3240 - MaxLength = 64 - TabIndex = 31 - Top = 2880 - Width = 1335 - End - Begin VB.TextBox txtExeccfg - Height = 285 - Left = 3240 - TabIndex = 9 - Top = 2400 - Width = 1335 - End - Begin VB.Frame frmTimers - Caption = "Timers (35 = 1 second)" - Height = 3975 - Left = 4800 - TabIndex = 8 - Top = 120 - Width = 4455 - Begin VB.TextBox txtGameovertics - Height = 285 - Left = 3000 - TabIndex = 29 - Top = 3480 - Width = 1335 - End - Begin VB.TextBox txtHelpertics - Height = 285 - Left = 3000 - TabIndex = 27 - Top = 3120 - Width = 1335 - End - Begin VB.TextBox txtParalooptics - Height = 285 - Left = 3000 - TabIndex = 25 - Top = 2760 - Width = 1335 - End - Begin VB.TextBox txtExtralifetics - Height = 285 - Left = 3000 - TabIndex = 23 - Top = 2400 - Width = 1335 - End - Begin VB.TextBox txtSpacetimetics - Height = 285 - Left = 3000 - TabIndex = 21 - Top = 2040 - Width = 1335 - End - Begin VB.TextBox txtUnderwatertics - Height = 285 - Left = 3000 - TabIndex = 19 - Top = 1680 - Width = 1335 - End - Begin VB.TextBox txtTailsflytics - Height = 285 - Left = 3000 - TabIndex = 17 - Top = 1320 - Width = 1335 - End - Begin VB.TextBox txtFlashingtics - Height = 285 - Left = 3000 - TabIndex = 15 - Top = 960 - Width = 1335 - End - Begin VB.TextBox txtSneakertics - Height = 285 - Left = 3000 - TabIndex = 13 - Top = 600 - Width = 1335 - End - Begin VB.TextBox txtInvulntics - Height = 285 - Left = 3000 - TabIndex = 11 - Top = 240 - Width = 1335 - End - Begin VB.Label lblGameovertics - Alignment = 1 'Right Justify - Caption = "Game Over Screen Time:" - Height = 255 - Left = 960 - TabIndex = 30 - Top = 3480 - Width = 1935 - End - Begin VB.Label lblHelpertics - Alignment = 1 'Right Justify - Caption = "NiGHTS Nightopian Helper Time:" - Height = 255 - Left = 240 - TabIndex = 28 - Top = 3120 - Width = 2655 - End - Begin VB.Label lblParalooptics - Alignment = 1 'Right Justify - Caption = "NiGHTS Paraloop Powerup Time:" - Height = 255 - Left = 360 - TabIndex = 26 - Top = 2760 - Width = 2535 - End - Begin VB.Label lblExtralifetics - Alignment = 1 'Right Justify - Caption = "Extra Life Music Duration:" - Height = 255 - Left = 960 - TabIndex = 24 - Top = 2400 - Width = 1935 - End - Begin VB.Label lblSpacetimetics - Alignment = 1 'Right Justify - Caption = "Space Breath Timeout:" - Height = 255 - Left = 1200 - TabIndex = 22 - Top = 2040 - Width = 1695 - End - Begin VB.Label lblUnderwatertics - Alignment = 1 'Right Justify - Caption = "Underwater Breath Timeout:" - Height = 255 - Left = 840 - TabIndex = 20 - Top = 1680 - Width = 2055 - End - Begin VB.Label lblTailsflytics - Alignment = 1 'Right Justify - Caption = "Tails Flying Time:" - Height = 255 - Left = 1440 - TabIndex = 18 - Top = 1320 - Width = 1455 - End - Begin VB.Label lblFlashingtics - Alignment = 1 'Right Justify - Caption = "Flashing Time After Being Hit:" - Height = 255 - Left = 360 - TabIndex = 16 - Top = 960 - Width = 2535 - End - Begin VB.Label lblSneakertics - Alignment = 1 'Right Justify - Caption = "Super Sneakers Time:" - Height = 255 - Left = 240 - TabIndex = 14 - Top = 600 - Width = 2655 - End - Begin VB.Label lblInvulntics - Alignment = 1 'Right Justify - Caption = "Invincibility Time:" - Height = 255 - Left = 360 - TabIndex = 12 - Top = 240 - Width = 2535 - End - End - Begin VB.TextBox txtIntrotoplay - Height = 285 - Left = 4080 - TabIndex = 6 - Top = 1200 - Width = 495 - End - Begin VB.TextBox txtRacestage_start - Height = 285 - Left = 4080 - MaxLength = 4 - TabIndex = 4 - Top = 840 - Width = 495 - End - Begin VB.TextBox txtSpstage_start - Height = 285 - Left = 4080 - MaxLength = 4 - TabIndex = 2 - Top = 480 - Width = 495 - End - Begin VB.TextBox txtSstage_start - Height = 285 - Left = 4080 - MaxLength = 4 - TabIndex = 0 - Top = 120 - Width = 495 - End - Begin VB.Label lblTitleScrollSpeed - Alignment = 1 'Right Justify - Caption = "Scroll speed of title background:" - Height = 255 - Left = 1560 - TabIndex = 40 - Top = 1920 - Width = 2415 - End - Begin VB.Label lblCreditsCutscene - Alignment = 1 'Right Justify - Caption = "Cutscene # to replace credits with:" - Height = 255 - Left = 1080 - TabIndex = 38 - Top = 1560 - Width = 2895 - End - Begin VB.Label lblNumemblems - Alignment = 1 'Right Justify - Caption = "# of LEVEL Emblems (Gamedata field must also be filled out):" - Height = 375 - Left = 1440 - TabIndex = 34 - Top = 3240 - Width = 2535 - End - Begin VB.Label lblGamedata - Alignment = 1 'Right Justify - Caption = "Gamedata file (to save mod emblems and time data):" - Height = 375 - Left = 960 - TabIndex = 32 - Top = 2760 - Width = 2175 - End - Begin VB.Label lblExeccfg - Alignment = 1 'Right Justify - Caption = "CFG file to instantly execute upon loading this SOC:" - Height = 495 - Left = 960 - TabIndex = 10 - Top = 2280 - Width = 2175 - End - Begin VB.Label lblIntrotoplay - Alignment = 1 'Right Justify - Caption = "Cutscene # to use for introduction:" - Height = 255 - Left = 1440 - TabIndex = 7 - Top = 1200 - Width = 2535 - End - Begin VB.Label lblRacestage_start - Alignment = 1 'Right Justify - Caption = "Racing mode starts/loops back to this map #:" - Height = 255 - Left = 720 - TabIndex = 5 - Top = 840 - Width = 3255 - End - Begin VB.Label lblSpstage_start - Alignment = 1 'Right Justify - Caption = "Single Player Game Starts on this map #:" - Height = 255 - Left = 1080 - TabIndex = 3 - Top = 480 - Width = 2895 - End - Begin VB.Label lblSstage_start - Alignment = 1 'Right Justify - Caption = "First Special Stage Map #:" - Height = 255 - Left = 2040 - TabIndex = 1 - Top = 120 - Width = 1935 - End -End -Attribute VB_Name = "frmMaincfg" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Private Sub cmdReload_Click() - Call Reload -End Sub - -Private Sub cmdSave_Click() - Call WriteSettings -End Sub - -Private Sub Form_Load() - Call Reload -End Sub - -Private Sub ClearForm() - Dim i As Integer - - txtSstage_start.Text = "" - txtSpstage_start.Text = "" - txtRacestage_start.Text = "" - txtIntrotoplay.Text = "" - txtExeccfg.Text = "" - txtGamedata.Text = "" - txtNumemblems.Text = "" - txtInvulntics.Text = "" - txtSneakertics.Text = "" - txtFlashingtics.Text = "" - txtTailsflytics.Text = "" - txtUnderwatertics.Text = "" - txtSpacetimetics.Text = "" - txtExtralifetics.Text = "" - txtParalooptics.Text = "" - txtHelpertics.Text = "" - txtGameovertics.Text = "" - txtCreditsCutscene.Text = "" - txtTitleScrollSpeed.Text = "" - chkLoopTitle.Value = 0 - chkDisableSpeedAdjust.Value = 0 - - For i = 0 To 2 - chkReset(i).Value = 0 - Next i -End Sub - -Private Sub Reload() - Call ClearForm - Call ReadSOCMaincfg -End Sub - -Private Sub ReadSOCMaincfg() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "MAINCFG" Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "SSTAGE_START" Then - txtSstage_start.Text = Val(word2) - ElseIf word = "SPSTAGE_START" Then - txtSpstage_start.Text = Val(word2) - ElseIf word = "RACESTAGE_START" Then - txtRacestage_start.Text = Val(word2) - ElseIf word = "INVULNTICS" Then - txtInvulntics.Text = Val(word2) - ElseIf word = "SNEAKERTICS" Then - txtSneakertics.Text = Val(word2) - ElseIf word = "FLASHINGTICS" Then - txtFlashingtics.Text = Val(word2) - ElseIf word = "TAILSFLYTICS" Then - txtTailsflytics.Text = Val(word2) - ElseIf word = "UNDERWATERTICS" Then - txtUnderwatertics.Text = Val(word2) - ElseIf word = "SPACETIMETICS" Then - txtSpacetimetics.Text = Val(word2) - ElseIf word = "EXTRALIFETICS" Then - txtExtralifetics.Text = Val(word2) - ElseIf word = "PARALOOPTICS" Then - txtParalooptics.Text = Val(word2) - ElseIf word = "HELPERTICS" Then - txtHelpertics.Text = Val(word2) - ElseIf word = "GAMEOVERTICS" Then - txtGameovertics.Text = Val(word2) - ElseIf word = "INTROTOPLAY" Then - txtIntrotoplay.Text = Val(word2) - ElseIf word = "CREDITSCUTSCENE" Then - txtCreditsCutscene.Text = Val(word2) - ElseIf word = "TITLESCROLLSPEED" Then - txtTitleScrollSpeed.Text = Val(word2) - ElseIf word = "LOOPTITLE" Then - chkLoopTitle.Value = Val(word2) - ElseIf word = "DISABLESPEEDADJUST" Then - chkDisableSpeedAdjust.Value = Val(word2) - ElseIf word = "GAMEDATA" Then - txtGamedata.Text = word2 - ElseIf word = "NUMEMBLEMS" Then - txtNumemblems.Text = Val(word2) - ElseIf word = "RESETDATA" Then - Dim resetflags As Integer - Dim z As Integer - - resetflags = Val(word2) - - For z = 0 To 2 - If resetflags And chkReset(z).Tag Then - chkReset(z).Value = 1 - Else - chkReset(z).Value = 0 - End If - Next z - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub WriteSettings() - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim flags As Long - Dim i As Integer - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the category exists in the SOC, delete it. - If word = "MAINCFG" Then - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not (tsSource.AtEndOfStream) - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "MAINCFG CATEGORY" - txtSstage_start.Text = TrimComplete(txtSstage_start.Text) - txtSpstage_start.Text = TrimComplete(txtSpstage_start.Text) - txtRacestage_start.Text = TrimComplete(txtRacestage_start.Text) - txtIntrotoplay.Text = TrimComplete(txtIntrotoplay.Text) - txtCreditsCutscene.Text = TrimComplete(txtCreditsCutscene.Text) - txtExeccfg.Text = TrimComplete(txtExeccfg.Text) - txtGamedata.Text = TrimComplete(txtGamedata.Text) - txtNumemblems.Text = TrimComplete(txtNumemblems.Text) - txtInvulntics.Text = TrimComplete(txtInvulntics.Text) - txtSneakertics.Text = TrimComplete(txtSneakertics.Text) - txtFlashingtics.Text = TrimComplete(txtFlashingtics.Text) - txtTailsflytics.Text = TrimComplete(txtTailsflytics.Text) - txtUnderwatertics.Text = TrimComplete(txtUnderwatertics.Text) - txtSpacetimetics.Text = TrimComplete(txtSpacetimetics.Text) - txtExtralifetics.Text = TrimComplete(txtExtralifetics.Text) - txtParalooptics.Text = TrimComplete(txtParalooptics.Text) - txtHelpertics.Text = TrimComplete(txtHelpertics.Text) - txtGameovertics.Text = TrimComplete(txtGameovertics.Text) - txtTitleScrollSpeed.Text = TrimComplete(txtTitleScrollSpeed.Text) - - If txtSstage_start.Text <> "" Then tsTarget.WriteLine "SSTAGE_START = " & Val(txtSstage_start.Text) - If txtSpstage_start.Text <> "" Then tsTarget.WriteLine "SPSTAGE_START = " & Val(txtSpstage_start.Text) - If txtRacestage_start.Text <> "" Then tsTarget.WriteLine "RACESTAGE_START = " & Val(txtRacestage_start.Text) - If txtIntrotoplay.Text <> "" Then tsTarget.WriteLine "INTROTOPLAY = " & Val(txtIntrotoplay.Text) - If txtCreditsCutscene.Text <> "" Then tsTarget.WriteLine "CREDITSCUTSCENE = " & Val(txtCreditsCutscene.Text) - If txtExeccfg.Text <> "" Then tsTarget.WriteLine "EXECCFG = " & txtExeccfg.Text - If txtGamedata.Text <> "" Then tsTarget.WriteLine "GAMEDATA = " & txtGamedata.Text - If txtNumemblems.Text <> "" Then - tsTarget.WriteLine "NUMEMBLEMS = " & Val(txtNumemblems.Text) - EditedNumemblems = True - End If - If txtInvulntics.Text <> "" Then tsTarget.WriteLine "INVULNTICS = " & Val(txtInvulntics.Text) - If txtSneakertics.Text <> "" Then tsTarget.WriteLine "SNEAKERTICS = " & Val(txtSneakertics.Text) - If txtFlashingtics.Text <> "" Then tsTarget.WriteLine "FLASHINGTICS = " & Val(txtFlashingtics.Text) - If txtTailsflytics.Text <> "" Then tsTarget.WriteLine "TAILSFLYTICS = " & Val(txtTailsflytics.Text) - If txtUnderwatertics.Text <> "" Then tsTarget.WriteLine "UNDERWATERTICS = " & Val(txtUnderwatertics.Text) - If txtSpacetimetics.Text <> "" Then tsTarget.WriteLine "SPACETIMETICS = " & Val(txtSpacetimetics.Text) - If txtExtralifetics.Text <> "" Then tsTarget.WriteLine "EXTRALIFETICS = " & Val(txtExtralifetics.Text) - If txtParalooptics.Text <> "" Then tsTarget.WriteLine "PARALOOPTICS = " & Val(txtParalooptics.Text) - If txtHelpertics.Text <> "" Then tsTarget.WriteLine "HELPERTICS = " & Val(txtHelpertics.Text) - If txtGameovertics.Text <> "" Then tsTarget.WriteLine "GAMEOVERTICS = " & Val(txtGameovertics.Text) - If txtTitleScrollSpeed.Text <> "" Then tsTarget.WriteLine "TITLESCROLLSPEED = " & Val(txtTitleScrollSpeed.Text) - If chkLoopTitle.Value = 1 Then tsTarget.WriteLine "LOOPTITLE = " & chkLoopTitle.Value - If chkDisableSpeedAdjust.Value = 1 Then tsTarget.WriteLine "DISABLESPEEDADJUST = " & chkDisableSpeedAdjust.Value - - flags = 0 - For i = 0 To 2 - If chkReset(i).Value = 1 Then - flags = flags + Val(chkReset(i).Tag) - End If - Next - - If flags > 0 Then tsTarget.WriteLine "RESETDATA = " & flags - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - MsgBox "Settings Saved." -End Sub - diff --git a/tools/SOCEdit/frmMaincfg.frx b/tools/SOCEdit/frmMaincfg.frx deleted file mode 100644 index 2ae367330..000000000 Binary files a/tools/SOCEdit/frmMaincfg.frx and /dev/null differ diff --git a/tools/SOCEdit/frmSoundEdit.frm b/tools/SOCEdit/frmSoundEdit.frm deleted file mode 100644 index c91d84ed8..000000000 --- a/tools/SOCEdit/frmSoundEdit.frm +++ /dev/null @@ -1,485 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmSoundEdit - Caption = "Sound Edit" - ClientHeight = 4995 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 6180 - Icon = "frmSoundEdit.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 4995 - ScaleWidth = 6180 - StartUpPosition = 3 'Windows Default - Begin VB.CommandButton cmdDelete - Caption = "&Delete sound from SOC" - Height = 495 - Left = 5040 - Style = 1 'Graphical - TabIndex = 13 - Top = 4320 - Width = 1095 - End - Begin VB.CommandButton cmdSave - Caption = "&Save" - Height = 495 - Left = 3840 - TabIndex = 6 - Top = 4320 - Width = 1095 - End - Begin VB.CommandButton cmdReload - Caption = "&Load Code Default" - Height = 495 - Left = 2640 - Style = 1 'Graphical - TabIndex = 5 - Top = 4320 - Width = 1095 - End - Begin VB.Frame frmSpecial - Caption = "Special Properties" - Height = 3375 - Left = 2640 - TabIndex = 4 - Top = 840 - Width = 3495 - Begin VB.CheckBox chkTotallySingle - Caption = "Make sure only one sound of this is playing at a time on any sound channel." - Height = 615 - Left = 120 - TabIndex = 12 - Tag = "1" - Top = 2640 - Width = 3255 - End - Begin VB.CheckBox chkEightEx - Caption = "Sound can be heard across 8x the distance" - Height = 375 - Left = 120 - TabIndex = 10 - Tag = "16" - Top = 2160 - Width = 2295 - End - Begin VB.CheckBox chkOutside - Caption = "Volume dependent on how close you are to outside" - Height = 375 - Left = 120 - TabIndex = 9 - Tag = "4" - Top = 360 - Width = 2295 - End - Begin VB.CheckBox chkFourEx - Caption = "Sound can be heard across 4x the distance" - Height = 375 - Left = 120 - TabIndex = 8 - Tag = "8" - Top = 1560 - Width = 2055 - End - Begin VB.CheckBox chkMultiple - Caption = "More than one of this sound can be played per object at a time (i.e., thunder)" - Height = 615 - Left = 120 - TabIndex = 7 - Tag = "2" - Top = 840 - Width = 2535 - End - Begin VB.Label Label1 - Caption = "Combine for 32x" - Height = 495 - Left = 2760 - TabIndex = 11 - Top = 1800 - Width = 615 - End - Begin VB.Line Line4 - X1 = 2400 - X2 = 2640 - Y1 = 2400 - Y2 = 2400 - End - Begin VB.Line Line2 - X1 = 2400 - X2 = 2640 - Y1 = 1800 - Y2 = 1800 - End - Begin VB.Line Line1 - X1 = 2640 - X2 = 2640 - Y1 = 2400 - Y2 = 1800 - End - End - Begin VB.ComboBox cmbPriority - Height = 315 - ItemData = "frmSoundEdit.frx":0442 - Left = 3360 - List = "frmSoundEdit.frx":0444 - TabIndex = 2 - Top = 120 - Width = 855 - End - Begin VB.CheckBox chkSingularity - Caption = "Only one can be played at a time per object." - Height = 255 - Left = 2640 - TabIndex = 1 - Top = 480 - Width = 3495 - End - Begin VB.ListBox lstSounds - Height = 4740 - Left = 120 - TabIndex = 0 - Top = 120 - Width = 2415 - End - Begin VB.Line Line3 - X1 = 0 - X2 = 720 - Y1 = 0 - Y2 = 0 - End - Begin VB.Label lblPriority - Alignment = 1 'Right Justify - Caption = "Priority:" - Height = 255 - Left = 2640 - TabIndex = 3 - Top = 120 - Width = 615 - End -End -Attribute VB_Name = "frmSoundEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdDelete_Click() - Call WriteSound(True) -End Sub - -Private Sub cmdReload_Click() - Call ClearForm - If InStr(lstSounds.List(lstSounds.ListIndex), "(free slot)") = 0 Then - Call LoadSoundInfo(lstSounds.ListIndex) - Else - MsgBox "Free slots do not have a code default." - End If -End Sub - -Private Sub cmdSave_Click() - Call WriteSound(False) -End Sub - -Private Sub Form_Load() - Call Reload -End Sub - -Private Sub ClearForm() - cmbPriority.Text = "" - chkSingularity.Value = 0 - chkOutside.Value = 0 - chkMultiple.Value = 0 - chkFourEx.Value = 0 - chkEightEx.Value = 0 - chkTotallySingle.Value = 0 -End Sub - -Private Sub Reload() - Call ClearForm - Call LoadCode - lstSounds.ListIndex = 0 -End Sub - -Private Sub LoadCode() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - Dim i As Integer, numfreeslots As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("sounds.h", ForReading, False) - - Do While InStr(ts.ReadLine, "List of sounds (don't modify this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - lstSounds.Clear - - Do While InStr(line, "sfx_freeslot0") = 0 - startclip = InStr(line, "sfx_") - If InStr(line, "sfx_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - lstSounds.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing - -'Populate the free slots! - numfreeslots = 800 - - For i = 1 To numfreeslots - If i < 10 Then - addstring = number & " - " & "sfx_fre00" & i & " (free slot)" - ElseIf i < 100 Then - addstring = number & " - " & "sfx_fre0" & i & " (free slot)" - Else - addstring = number & " - " & "sfx_fre" & i & " (free slot)" - End If - lstSounds.AddItem addstring - number = number + 1 - Next - - For i = 0 To 127 - cmbPriority.AddItem i - Next -End Sub - -Private Sub lstSounds_Click() - Call ClearForm - If InStr(lstSounds.List(lstSounds.ListIndex), "(free slot)") = 0 Then - Call LoadSoundInfo(lstSounds.ListIndex) - End If - Call LoadSOCSoundInfo(lstSounds.ListIndex) -End Sub - -Private Sub LoadSOCSoundInfo(SoundNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "SOUND" And Val(word2) = SoundNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "SINGULAR" Then - If Val(word2) = 1 Then - chkSingularity.Value = 1 - Else - chkSingularity.Value = 0 - End If - ElseIf word = "PRIORITY" Then - cmbPriority.Text = Val(word2) - ElseIf word = "FLAGS" Then - ProcessSoundFlags (Val(word2)) - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub LoadSoundInfo(StateNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim token As String - Dim frame As Long - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("sounds.c", ForReading, False) - - Do While InStr(ts.ReadLine, "S_sfx[0] needs to be a dummy for odd reasons.") = 0 - Loop - - number = 0 - - Do While number <> StateNum - Do While InStr(ts.ReadLine, """") = 0 - Loop - number = number + 1 - Loop - - Do While InStr(line, """") = 0 - line = ts.ReadLine - Loop - - startclip = InStr(line, """") + 1 - line = Mid(line, startclip, Len(line) - startclip) - endclip = InStr(line, """") - 1 - token = TrimComplete(Left(line, endclip)) - - 'txtName.Text = line - - startclip = InStr(line, ",") + 1 - line = Mid(line, startclip, Len(line) - startclip) - endclip = InStr(line, ",") - 1 - token = TrimComplete(Left(line, endclip)) - - If token = "true" Then - chkSingularity.Value = 1 - Else - chkSingularity.Value = 0 - End If - - startclip = InStr(line, ",") + 1 - line = Mid(line, startclip, Len(line) - startclip) - endclip = InStr(line, ",") - 1 - token = TrimComplete(Left(line, endclip)) - cmbPriority.Text = token - - startclip = InStr(line, ",") + 1 - line = Mid(line, startclip, Len(line) - startclip) - endclip = InStr(line, ",") - 1 - token = TrimComplete(Left(line, endclip)) - - ProcessSoundFlags (Val(token)) - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub ProcessSoundFlags(flags As Long) - - chkTotallySingle.Value = 0 - chkMultiple.Value = 0 - chkOutside.Value = 0 - chkFourEx.Value = 0 - chkEightEx.Value = 0 - - If flags = -1 Then - Exit Sub - End If - - If flags And 1 Then - chkTotallySingle.Value = 1 - End If - - If flags And 2 Then - chkMultiple.Value = 1 - End If - - If flags And 4 Then - chkOutside.Value = 1 - End If - - If flags And 8 Then - chkFourEx.Value = 1 - End If - - If flags And 16 Then - chkEightEx.Value = 1 - End If - -End Sub - -Private Sub WriteSound(Remove As Boolean) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim flags As Long - Dim soundfound As Boolean - - soundfound = False - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the current sound exists in the SOC, delete it. - If word = "SOUND" And Val(word2) = lstSounds.ListIndex Then - soundfound = True - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not (tsSource.AtEndOfStream) - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "SOUND " & lstSounds.ListIndex - cmbPriority.Text = TrimComplete(cmbPriority.Text) - If cmbPriority.Text <> "" Then tsTarget.WriteLine "PRIORITY = " & Val(cmbPriority.Text) - If chkSingularity.Value = 1 Then tsTarget.WriteLine "SINGULAR = 1" - - flags = 0 - - If chkOutside.Value = 1 Then flags = flags + Val(chkOutside.Tag) - If chkMultiple.Value = 1 Then flags = flags + Val(chkMultiple.Tag) - If chkFourEx.Value = 1 Then flags = flags + Val(chkFourEx.Tag) - If chkEightEx.Value = 1 Then flags = flags + Val(chkEightEx.Tag) - If chkTotallySingle.Value = 1 Then flags = flags + Val(chkTotallySingle.Tag) - - If flags > 0 Then tsTarget.WriteLine "FLAGS = " & flags - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - If soundfound = True Then - MsgBox "Sound removed from SOC." - Else - MsgBox "Sound not found in SOC." - End If - Else - MsgBox "Sound Saved." - End If -End Sub - diff --git a/tools/SOCEdit/frmSoundEdit.frx b/tools/SOCEdit/frmSoundEdit.frx deleted file mode 100644 index 980538679..000000000 Binary files a/tools/SOCEdit/frmSoundEdit.frx and /dev/null differ diff --git a/tools/SOCEdit/frmStateEdit.frm b/tools/SOCEdit/frmStateEdit.frm deleted file mode 100644 index 4eca5a1bc..000000000 --- a/tools/SOCEdit/frmStateEdit.frm +++ /dev/null @@ -1,940 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmStateEdit - Caption = "State Edit" - ClientHeight = 6750 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 8970 - Icon = "frmStateEdit.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 6750 - ScaleWidth = 8970 - StartUpPosition = 3 'Windows Default - Begin VB.TextBox lblVar2Desc - Height = 495 - Left = 4440 - Locked = -1 'True - MultiLine = -1 'True - ScrollBars = 2 'Vertical - TabIndex = 25 - Top = 3000 - Width = 4455 - End - Begin VB.TextBox lblVar1Desc - Height = 495 - Left = 4440 - Locked = -1 'True - MultiLine = -1 'True - ScrollBars = 2 'Vertical - TabIndex = 24 - Top = 2400 - Width = 4455 - End - Begin VB.TextBox lblActionDesc - Height = 735 - Left = 4440 - Locked = -1 'True - MultiLine = -1 'True - ScrollBars = 2 'Vertical - TabIndex = 23 - Top = 1560 - Width = 4455 - End - Begin VB.ListBox lstThings - Height = 450 - ItemData = "frmStateEdit.frx":0442 - Left = 7440 - List = "frmStateEdit.frx":0444 - TabIndex = 22 - Top = 6120 - Visible = 0 'False - Width = 975 - End - Begin VB.TextBox txtFuncVar2 - Height = 285 - Left = 7200 - TabIndex = 19 - Top = 3600 - Width = 1215 - End - Begin VB.TextBox txtFuncVar1 - Height = 285 - Left = 5520 - TabIndex = 18 - Top = 3600 - Width = 1095 - End - Begin VB.CommandButton cmdCopy - Caption = "&Copy state to..." - Height = 495 - Left = 6120 - Style = 1 'Graphical - TabIndex = 17 - Top = 6120 - Width = 1095 - End - Begin VB.CommandButton cmdDelete - Caption = "&Delete State from SOC" - Height = 495 - Left = 6120 - Style = 1 'Graphical - TabIndex = 16 - Top = 5520 - Width = 1095 - End - Begin VB.CommandButton cmdReload - Caption = "&Load Code Default" - Height = 495 - Left = 4920 - Style = 1 'Graphical - TabIndex = 15 - Top = 5520 - Width = 1095 - End - Begin VB.CommandButton cmdSave - Caption = "&Save" - Height = 495 - Left = 7320 - TabIndex = 14 - Top = 5520 - Width = 1095 - End - Begin VB.ComboBox cmbTranslucency - Height = 315 - ItemData = "frmStateEdit.frx":0446 - Left = 6720 - List = "frmStateEdit.frx":045C - TabIndex = 12 - Top = 5040 - Width = 1695 - End - Begin VB.CheckBox chkFullbright - Caption = "Make sprite full-brightness (unaffected by lighting)" - Height = 495 - Left = 6240 - TabIndex = 11 - Top = 4440 - Width = 2175 - End - Begin VB.ComboBox cmbNextstate - Height = 315 - Left = 6120 - TabIndex = 9 - Top = 3960 - Width = 2295 - End - Begin VB.ComboBox cmbAction - Height = 315 - Left = 6000 - TabIndex = 7 - Top = 1200 - Width = 2295 - End - Begin VB.TextBox txtTics - Height = 285 - Left = 7800 - TabIndex = 5 - Top = 720 - Width = 495 - End - Begin VB.TextBox txtFrame - Height = 285 - Left = 5880 - MaxLength = 2 - TabIndex = 3 - Top = 720 - Width = 495 - End - Begin VB.ComboBox cmbSprite - Height = 315 - Left = 5880 - TabIndex = 1 - Top = 120 - Width = 2415 - End - Begin VB.ListBox lstStates - Height = 6495 - Left = 120 - TabIndex = 0 - Top = 120 - Width = 4215 - End - Begin VB.Label lblFuncVar2 - Alignment = 1 'Right Justify - Caption = "Var2:" - Height = 255 - Left = 6600 - TabIndex = 21 - Top = 3600 - Width = 495 - End - Begin VB.Label lblFuncVar1 - Alignment = 1 'Right Justify - Caption = "Var1:" - Height = 255 - Left = 4920 - TabIndex = 20 - Top = 3600 - Width = 495 - End - Begin VB.Label lblTranslucency - Alignment = 1 'Right Justify - Caption = "Translucency:" - Height = 255 - Left = 5520 - TabIndex = 13 - Top = 5040 - Width = 1095 - End - Begin VB.Label lblNextstate - Alignment = 1 'Right Justify - Caption = "Next State:" - Height = 255 - Left = 5160 - TabIndex = 10 - Top = 3960 - Width = 855 - End - Begin VB.Label lblAction - Alignment = 1 'Right Justify - Caption = "Function to Call:" - Height = 375 - Left = 5040 - TabIndex = 8 - Top = 1080 - Width = 855 - End - Begin VB.Label lblTics - Alignment = 1 'Right Justify - Caption = "Tics (-1 for infinite duration):" - Height = 495 - Left = 6480 - TabIndex = 6 - Top = 600 - Width = 1215 - End - Begin VB.Label lblFrame - Alignment = 1 'Right Justify - Caption = "Frame:" - Height = 255 - Left = 5160 - TabIndex = 4 - Top = 720 - Width = 615 - End - Begin VB.Label lblSprite - Alignment = 1 'Right Justify - Caption = "Sprite:" - Height = 255 - Left = 5160 - TabIndex = 2 - Top = 120 - Width = 615 - End -End -Attribute VB_Name = "frmStateEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmbAction_Click() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim index As Integer - Dim ActionName As String - - ActionName = cmbAction.List(cmbAction.ListIndex) - - If cmbAction.ListIndex = 0 Then - lblActionDesc.Text = "" - lblVar1Desc.Text = "" - lblVar2Desc.Text = "" - Exit Sub - End If - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("p_enemy.c", ForReading, False) - - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Mid(line, 4, 9) = "Function:" And InStr(line, ActionName) > 0 Then - ts.ReadLine ' // - line = ts.ReadLine ' // Description: - index = InStr(line, ":") - lblActionDesc.Text = Mid(line, index + 2, Len(line) - (index + 1)) - - ts.ReadLine ' // - line = ts.ReadLine ' // var1 = - If InStr(line, "var1:") Then - lblVar1Desc.Text = Mid(line, 4, Len(line) - 3) - line = ts.ReadLine - Do While Left(line, 7) <> "// var2" - lblVar1Desc.Text = lblVar1Desc.Text & vbCrLf & TrimComplete(Mid(line, 4, Len(line) - 3)) - line = ts.ReadLine - Loop - Else - lblVar1Desc.Text = Mid(line, 4, Len(line) - 3) - End If - - If Left(line, 7) <> "// var2" Then - line = ts.ReadLine ' // var2 = - End If - - If InStr(line, "var2:") Then - lblVar2Desc.Text = Mid(line, 4, Len(line) - 3) - line = ts.ReadLine - Do While Len(line) > 4 - lblVar2Desc.Text = lblVar2Desc.Text & vbCrLf & TrimComplete(Mid(line, 4, Len(line) - 3)) - line = ts.ReadLine - Loop - Else - lblVar2Desc.Text = Mid(line, 4, Len(line) - 3) - End If - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub cmdCopy_Click() - Dim Response As String - - Response$ = InputBox("Copy state to #:", "Copy State") - - If Response = "" Then Exit Sub - - Response = TrimComplete(Response) - - Call WriteState(False, Val(Response)) - - MsgBox "State copied to #" & Val(Response) -End Sub - -Private Sub cmdDelete_Click() - Call WriteState(True, lstStates.ListIndex) -End Sub - -Private Sub cmdReload_Click() - Call ClearForm - - If InStr(lstStates.List(lstStates.ListIndex), "S_FREESLOT") = 0 Then - LoadStateInfo (lstStates.ListIndex) - Else - MsgBox "Free slots do not have a code default." - End If -End Sub - -Private Sub cmdSave_Click() - If TrimComplete(txtFrame.Text) = "" And (chkFullbright.Value = 1 Or cmbTranslucency.ListIndex > 0) Then - MsgBox "ERROR: Frame field required for fullbright/translucency." - Exit Sub - End If - Call WriteState(False, lstStates.ListIndex) -End Sub - -Private Sub Form_Load() - Call Reload - lstStates.ListIndex = 0 -End Sub - -Private Sub ClearForm() - cmbNextstate.Text = "" - cmbSprite.Text = "" - txtFrame.Text = "" - cmbAction.Text = "" - txtFuncVar1.Text = "" - txtFuncVar2.Text = "" - lblActionDesc.Text = "" - lblVar1Desc.Text = "" - lblVar2Desc.Text = "" - chkFullbright.Value = False - cmbTranslucency.ListIndex = 0 -End Sub - -Private Sub Reload() - LoadStates - LoadSprites - LoadActions -End Sub - -Private Sub LoadStates() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - Dim numfreeslots As Integer, i As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Object states (don't modify this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - lstStates.Clear - - Do While InStr(line, "S_FIRSTFREESLOT") = 0 - startclip = InStr(line, "S_") - If InStr(line, "S_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - lstStates.AddItem addstring - cmbNextstate.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - - 'Populate the free slots! - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - line = ts.ReadLine - Do While InStr(line, "#define NUMMOBJFREESLOTS") = 0 - line = ts.ReadLine - Loop - - startclip = InStr(line, "SLOTS ") + 6 - numfreeslots = Val(Mid(line, startclip, Len(line) - startclip + 1)) * 6 - - For i = 1 To numfreeslots - addstring = number & " - " & "S_FREESLOT" & i - lstStates.AddItem addstring - cmbNextstate.AddItem addstring - number = number + 1 - Next - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub LoadSprites() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - Dim numfreeslots As Integer, i As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Hey, moron! If you change this table, don't forget about") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - cmbSprite.Clear - - Do While InStr(line, "SPR_FIRSTFREESLOT") = 0 - startclip = InStr(line, "SPR_") - If InStr(line, "SPR_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - addstring = number & " - " & line - cmbSprite.AddItem addstring - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - - 'Populate the free slots! - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - line = ts.ReadLine - Do While InStr(line, "#define NUMMOBJFREESLOTS") = 0 - line = ts.ReadLine - Loop - - startclip = InStr(line, "SLOTS ") + 6 - numfreeslots = Val(Mid(line, startclip, Len(line) - startclip + 1)) - - For i = 1 To numfreeslots - If i < 10 Then - addstring = number & " - " & "SPR_F00" & i & " (Free slot)" - ElseIf i < 100 Then - addstring = number & " - " & "SPR_F0" & i & " (Free slot)" - Else - addstring = number & " - " & "SPR_F" & i & " (Free slot)" - End If - - cmbSprite.AddItem addstring - number = number + 1 - Next - - ts.Close - - Set myFSO = Nothing -End Sub - -Private Sub LoadActions() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim addstring As String - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("dehacked.c", ForReading, False) - - Do While InStr(ts.ReadLine, "actionpointer_t actionpointers[]") = 0 - Loop - - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - cmbAction.Clear - - cmbAction.AddItem "None" - - Do While InStr(line, "NULL") = 0 - startclip = InStr(line, "A_") - If InStr(line, "A_") <> 0 Then - endclip = InStr(line, "}") - line = Mid(line, startclip, endclip - startclip) - cmbAction.AddItem line - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub lstStates_Click() - Call ClearForm - - If InStr(lstStates.List(lstStates.ListIndex), "S_FREESLOT") = 0 Then - LoadStateInfo (lstStates.ListIndex) - End If - - LoadSOCStateInfo (lstStates.ListIndex) -End Sub - -Private Sub LoadSOCStateInfo(StateNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim frameNum As Long - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "FRAME" And Val(word2) = StateNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "SPRITENUMBER" Then - cmbSprite.ListIndex = Val(word2) - ElseIf word = "SPRITESUBNUMBER" Then - frameNum = Val(word2) - - If frameNum >= 327680 Then ' 5 << 16 - cmbTranslucency.ListIndex = 5 - frameNum = frameNum And Not 327680 - ElseIf frameNum >= 262144 Then ' 4 << 16 - cmbTranslucency.ListIndex = 4 - frameNum = frameNum And Not 262144 - ElseIf frameNum >= 196608 Then ' 3 << 16 - cmbTranslucency.ListIndex = 3 - frameNum = frameNum And Not 196608 - ElseIf frameNum >= 131072 Then ' 2 << 16 - cmbTranslucency.ListIndex = 2 - frameNum = frameNum And Not 131072 - ElseIf frameNum >= 65536 Then ' 1 << 16 - cmbTranslucency.ListIndex = 1 - frameNum = frameNum And Not 65536 - End If - - If frameNum >= 32768 Then - chkFullbright.Value = 1 - frameNum = frameNum And Not 32768 - Else - chkFullbright.Value = 0 - End If - - txtFrame.Text = frameNum - ElseIf word = "DURATION" Then - txtTics.Text = Val(word2) - ElseIf word = "NEXT" Then - cmbNextstate.ListIndex = Val(word2) - ElseIf word = "ACTION" Then - Call FindComboIndex(cmbAction, UCase(SecondToken(line))) - ElseIf word = "VAR1" Then - txtFuncVar1.Text = Val(word2) - ElseIf word = "VAR2" Then - txtFuncVar2.Text = Val(word2) - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub LoadStateInfo(StateNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim token As String - Dim frame As Long - Dim templine As String - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("info.c", ForReading, False) - - Do While InStr(ts.ReadLine, "Keep this comment directly above S_NULL") = 0 - Loop - - number = 0 - - Do While number <> StateNum - Do While InStr(ts.ReadLine, "SPR_") = 0 - Loop - number = number + 1 - Loop - - Do While InStr(line, "SPR_") = 0 - line = ts.ReadLine - Loop - - startclip = InStr(line, "SPR_") - line = Mid(line, startclip, Len(line) - startclip) - endclip = InStr(line, ",") - 1 - token = Left(line, endclip) - Call FindComboIndex(cmbSprite, token) - - startclip = InStr(line, ",") + 1 - line = TrimComplete(Mid(line, startclip, Len(line) - startclip)) - endclip = InStr(line, ",") - 1 - frame = Val(Left(line, endclip)) - - If frame >= 32768 Then - chkFullbright.Value = 1 - frame = frame - 32768 - Else - chkFullbright.Value = 0 - End If - - txtFrame.Text = frame - - cmbTranslucency.ListIndex = 0 - - startclip = InStr(line, ",") + 1 - line = TrimComplete(Mid(line, startclip, Len(line) - startclip)) - endclip = InStr(line, ",") - 1 - txtTics.Text = Val(Left(line, endclip)) - - startclip = InStr(line, "{") + 1 - line = TrimComplete(Mid(line, startclip, Len(line) - startclip)) - endclip = InStr(line, "}") - 1 - cmbAction.Text = TrimComplete(Left(line, endclip)) - If cmbAction.Text = "NULL" Then cmbAction.Text = "None" - - startclip = InStr(line, ",") + 1 - line = TrimComplete(Mid(line, startclip, Len(line) - startclip)) - endclip = InStr(line, ",") - 1 - templine = Left(line, endclip) - - templine = TrimComplete(templine) - 'Check for *FRACUNIT values - endclip = InStr(templine, "*FRACUNIT") - If endclip <> 0 Then - templine = Left(templine, endclip - 1) - templine = Val(templine) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(templine, "MT_") - If endclip <> 0 Then - templine = FindThingNum(templine) & " - " & templine - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(templine, "pw_") - If endclip <> 0 Then - templine = FindPowerNum(templine) & " - " & templine - End If - txtFuncVar1.Text = templine - - startclip = InStr(line, ",") + 1 - line = TrimComplete(Mid(line, startclip, Len(line) - startclip)) - endclip = InStr(line, ",") - 1 - templine = Left(line, endclip) - - templine = TrimComplete(templine) - 'Check for *FRACUNIT values - endclip = InStr(templine, "*FRACUNIT") - If endclip <> 0 Then - templine = Left(templine, endclip - 1) - templine = Val(templine) * 65536 - End If - 'Check for crazy-odd MT_ usage - endclip = InStr(templine, "MT_") - If endclip <> 0 Then - templine = FindThingNum(templine) & " - " & templine - End If - 'Check for crazy-odd pw_ usage - endclip = InStr(templine, "pw_") - If endclip <> 0 Then - templine = FindPowerNum(templine) & " - " & templine - End If - txtFuncVar2.Text = templine - - startclip = InStr(line, ",") + 1 - line = TrimComplete(Mid(line, startclip, Len(line) - startclip)) - endclip = InStr(line, "}") - 1 - Call FindComboIndex(cmbNextstate, TrimComplete(Left(line, endclip))) - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub FindComboIndex(ByRef Box As ComboBox, line As String) - Dim i As Integer - - For i = 0 To Box.ListCount - If InStr(UCase(Box.List(i)), UCase(line)) Then - Box.ListIndex = i - Exit For - End If - Next -End Sub - -Private Sub WriteState(Remove As Boolean, num As Integer) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim flags As Long - Dim statefound As Boolean - - statefound = False - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the current sound exists in the SOC, delete it. - If word = "FRAME" And Val(word2) = num Then - statefound = True - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not (tsSource.AtEndOfStream) - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "FRAME " & num - cmbSprite.Text = TrimComplete(cmbSprite.Text) - txtFrame.Text = TrimComplete(txtFrame.Text) - txtTics.Text = TrimComplete(txtTics.Text) - cmbAction.Text = TrimComplete(cmbAction.Text) - txtFuncVar1.Text = TrimComplete(txtFuncVar1.Text) - txtFuncVar2.Text = TrimComplete(txtFuncVar2.Text) - cmbNextstate.Text = TrimComplete(cmbNextstate.Text) - cmbTranslucency.Text = TrimComplete(cmbTranslucency.Text) - - If cmbSprite.Text <> "" Then tsTarget.WriteLine "SPRITENUMBER = " & cmbSprite.ListIndex - - flags = Val(txtFrame.Text) - If chkFullbright.Value = 1 Then flags = flags + 32768 - - ' Grrr VB doesn't have bitshifts!! - If cmbTranslucency.Text <> "" Then - flags = flags + cmbTranslucency.ListIndex * 65536 - End If - - If txtFrame.Text <> "" Then tsTarget.WriteLine "SPRITESUBNUMBER = " & flags - If txtTics.Text <> "" Then tsTarget.WriteLine "DURATION = " & Val(txtTics.Text) - If cmbNextstate.Text <> "" Then tsTarget.WriteLine "NEXT = " & cmbNextstate.ListIndex - If cmbAction.Text <> "" Then tsTarget.WriteLine "ACTION " & cmbAction.Text - If txtFuncVar1.Text <> "" Then tsTarget.WriteLine "VAR1 = " & Val(txtFuncVar1.Text) - If txtFuncVar2.Text <> "" Then tsTarget.WriteLine "VAR2 = " & Val(txtFuncVar2.Text) - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - If statefound = True Then - MsgBox "State removed from SOC." - Else - MsgBox "State not found in SOC." - End If - Else - MsgBox "State Saved." - End If -End Sub - -Private Sub LoadThings() - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer, endclip As Integer - Dim numfreeslots As Integer, i As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Little flag for SOC editor (don't change this comment!)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - lstThings.Clear - - Do While InStr(line, "MT_FIRSTFREESLOT") = 0 - startclip = InStr(line, "MT_") - If InStr(line, "MT_") <> 0 Then - endclip = InStr(line, ",") - line = Mid(line, startclip, endclip - startclip) - lstThings.AddItem number & " - " & line - number = number + 1 - End If - line = ts.ReadLine - Loop - - ts.Close - - 'Populate the free slots! - Set ts = myFSO.OpenTextFile("info.h", ForReading, False) - - line = ts.ReadLine - Do While InStr(line, "#define NUMMOBJFREESLOTS") = 0 - line = ts.ReadLine - Loop - - startclip = InStr(line, "SLOTS ") + 6 - numfreeslots = Val(Mid(line, startclip, Len(line) - startclip + 1)) - - For i = 1 To numfreeslots - lstThings.AddItem number & " - " & "MT_FREESLOT" & i - number = number + 1 - Next - - ts.Close - Set myFSO = Nothing -End Sub - -Private Function FindThingNum(ThingName As String) As Integer - Dim i As Integer - Dim temp As String - Dim startpoint As Integer - Dim endpoint As Integer - - lstThings.Clear - LoadThings - - For i = 0 To lstThings.ListCount - 1 - temp = lstThings.List(i) - startpoint = InStr(temp, "-") + 2 - endpoint = Len(temp) - startpoint + 1 - temp = Mid(temp, startpoint, endpoint) - If temp = ThingName Then - FindThingNum = Val(lstThings.List(i)) - Exit For - End If - Next -End Function - -Private Function FindPowerNum(PowerName As String) As Integer - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim number As Integer - Dim startclip As Integer - - ChDir SourcePath - Set ts = myFSO.OpenTextFile("d_player.h", ForReading, False) - - Do While InStr(ts.ReadLine, "Player powers. (don't edit this comment)") = 0 - Loop - - ts.SkipLine ' typedef enum - ts.SkipLine ' { - - line = ts.ReadLine - number = 0 - - Do While InStr(line, "NUMPOWERS") = 0 - startclip = InStr(line, PowerName) - If startclip <> 0 Then - FindPowerNum = number - Exit Do - End If - number = number + 1 - line = ts.ReadLine - Loop - - ts.Close - Set myFSO = Nothing -End Function diff --git a/tools/SOCEdit/frmStateEdit.frx b/tools/SOCEdit/frmStateEdit.frx deleted file mode 100644 index 8069c37e0..000000000 Binary files a/tools/SOCEdit/frmStateEdit.frx and /dev/null differ diff --git a/tools/SOCEdit/frmUnlockablesEdit.frm b/tools/SOCEdit/frmUnlockablesEdit.frm deleted file mode 100644 index f43209a78..000000000 --- a/tools/SOCEdit/frmUnlockablesEdit.frm +++ /dev/null @@ -1,391 +0,0 @@ -VERSION 5.00 -Begin VB.Form frmUnlockablesEdit - Caption = "Unlockables Edit" - ClientHeight = 3675 - ClientLeft = 60 - ClientTop = 345 - ClientWidth = 8130 - Icon = "frmUnlockablesEdit.frx":0000 - LinkTopic = "Form1" - MaxButton = 0 'False - ScaleHeight = 3675 - ScaleWidth = 8130 - StartUpPosition = 3 'Windows Default - Begin VB.CheckBox chkGrade - Caption = "Must have beaten Ultimate" - Height = 255 - Index = 4 - Left = 5400 - TabIndex = 20 - Tag = "1024" - Top = 2160 - Width = 2655 - End - Begin VB.CheckBox chkGrade - Caption = "Must have beaten Very Hard" - Height = 255 - Index = 3 - Left = 5400 - TabIndex = 19 - Tag = "128" - Top = 1800 - Width = 2655 - End - Begin VB.CheckBox chkGrade - Caption = "Must have all emblems" - Height = 255 - Index = 2 - Left = 5400 - TabIndex = 18 - Tag = "16" - Top = 1440 - Width = 2055 - End - Begin VB.CheckBox chkGrade - Caption = "Must have gotten all 7 emeralds" - Height = 255 - Index = 1 - Left = 5400 - TabIndex = 17 - Tag = "8" - Top = 1080 - Width = 2655 - End - Begin VB.CheckBox chkGrade - Caption = "Game must be completed" - Height = 255 - Index = 0 - Left = 5400 - TabIndex = 16 - Tag = "1" - Top = 720 - Width = 2175 - End - Begin VB.TextBox txtVar - Height = 285 - Left = 4320 - TabIndex = 14 - Top = 2640 - Width = 615 - End - Begin VB.ComboBox cmbType - Height = 315 - ItemData = "frmUnlockablesEdit.frx":0442 - Left = 3360 - List = "frmUnlockablesEdit.frx":044C - TabIndex = 12 - Top = 2160 - Width = 1575 - End - Begin VB.TextBox txtNeededTime - Height = 285 - Left = 4080 - TabIndex = 10 - Top = 1680 - Width = 855 - End - Begin VB.TextBox txtNeededEmblems - Height = 285 - Left = 4440 - TabIndex = 9 - Top = 1200 - Width = 495 - End - Begin VB.TextBox txtObjective - Height = 285 - Left = 3240 - TabIndex = 7 - Top = 720 - Width = 1695 - End - Begin VB.TextBox txtName - Height = 285 - Left = 3240 - TabIndex = 5 - Top = 240 - Width = 1695 - End - Begin VB.CommandButton cmdDelete - Caption = "&Delete from SOC" - Height = 375 - Left = 3480 - TabIndex = 3 - Top = 3120 - Width = 1575 - End - Begin VB.CommandButton cmdSave - Caption = "&Save Changes" - Height = 375 - Left = 1800 - TabIndex = 2 - Top = 3120 - Width = 1575 - End - Begin VB.ListBox lstUnlockables - Height = 2985 - ItemData = "frmUnlockablesEdit.frx":046A - Left = 120 - List = "frmUnlockablesEdit.frx":049B - TabIndex = 0 - Top = 480 - Width = 1215 - End - Begin VB.Label lblNote - Caption = "Note: All requirements are combinable." - Height = 495 - Left = 6000 - TabIndex = 22 - Top = 2760 - Width = 1695 - End - Begin VB.Label lblOtherReqs - Caption = "Other Requirements:" - Height = 255 - Left = 5400 - TabIndex = 21 - Top = 360 - Width = 1935 - End - Begin VB.Label lblVar - Alignment = 1 'Right Justify - Caption = "Map # to warp to:" - Height = 255 - Left = 2880 - TabIndex = 15 - Top = 2640 - Width = 1335 - End - Begin VB.Label lblType - Alignment = 1 'Right Justify - Caption = "Type of Unlockable:" - Height = 255 - Left = 1800 - TabIndex = 13 - Top = 2160 - Width = 1455 - End - Begin VB.Label lblNeededTime - Alignment = 1 'Right Justify - Caption = "Needed time on Time Attack rank (in seconds):" - Height = 375 - Left = 1440 - TabIndex = 11 - Top = 1560 - Width = 2535 - End - Begin VB.Label lblNeededEmblems - Alignment = 1 'Right Justify - Caption = "# of Emblems Needed:" - Height = 255 - Left = 2640 - TabIndex = 8 - Top = 1200 - Width = 1695 - End - Begin VB.Label lblObjective - Alignment = 1 'Right Justify - Caption = "Objective:" - Height = 255 - Left = 2400 - TabIndex = 6 - Top = 720 - Width = 735 - End - Begin VB.Label lblName - Alignment = 1 'Right Justify - Caption = "Name:" - Height = 255 - Left = 2640 - TabIndex = 4 - Top = 240 - Width = 495 - End - Begin VB.Label lblHUDItems - Caption = "Unlockables:" - Height = 255 - Left = 120 - TabIndex = 1 - Top = 240 - Width = 975 - End -End -Attribute VB_Name = "frmUnlockablesEdit" -Attribute VB_GlobalNameSpace = False -Attribute VB_Creatable = False -Attribute VB_PredeclaredId = True -Attribute VB_Exposed = False -Option Explicit - -Private Sub cmdDelete_Click() - Call WriteUnlockableItem(True) -End Sub - -Private Sub cmdSave_Click() - Call WriteUnlockableItem(False) -End Sub - -Private Sub Form_Load() - Call Reload -End Sub - -Private Sub Reload() - txtName.Text = "" - txtObjective.Text = "" - txtNeededEmblems.Text = "" - txtNeededTime.Text = "" - cmbType.Text = "" - txtVar.Text = "" - - Dim i As Integer - - For i = 0 To chkGrade.Count - 1 - chkGrade(i).Value = 0 - Next i - - lstUnlockables.ListIndex = 0 -End Sub - -Private Sub lstUnlockables_Click() - Call ReadSOC(lstUnlockables.ListIndex + 1) -End Sub - -Private Sub ReadSOC(UnlockableNum As Integer) - Dim myFSO As New Scripting.FileSystemObject - Dim ts As TextStream - Dim line As String - Dim word As String - Dim word2 As String - - Set ts = myFSO.OpenTextFile(SOCFile, ForReading, False) - -SOCLoad: - Do While Not ts.AtEndOfStream - line = ts.ReadLine - - If Left(line, 1) = "#" Then GoTo SOCLoad - - If Left(line, 1) = vbCrLf Then GoTo SOCLoad - - If Len(line) < 1 Then GoTo SOCLoad - - word = FirstToken(line) - word2 = SecondToken(line) - - If UCase(word) = "UNLOCKABLE" And Val(word2) = UnlockableNum Then - Do While Len(line) > 0 And Not ts.AtEndOfStream - line = ts.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondTokenEqual(line)) - - If word = "NAME" Then - txtName.Text = word2 - ElseIf word = "OBJECTIVE" Then - txtObjective.Text = word2 - ElseIf word = "NEEDEDEMBLEMS" Then - txtNeededEmblems.Text = Val(word2) - ElseIf word = "NEEDEDTIME" Then - txtNeededTime.Text = Val(word2) - ElseIf word = "TYPE" Then - cmbType.ListIndex = Val(word2) - ElseIf word = "VAR" Then - txtVar.Text = Val(word2) - ElseIf word = "NEEDEDGRADE" Then - Dim i As Integer - - For i = 0 To chkGrade.Count - 1 - If Val(word2) And chkGrade(i).Tag Then - chkGrade(i).Tag = True - End If - Next i - ElseIf Len(line) > 0 And Left(line, 1) <> "#" Then - MsgBox "Error in SOC!" & vbCrLf & "Unknown line: " & line - End If - Loop - Exit Do - End If - Loop - - ts.Close - Set myFSO = Nothing -End Sub - -Private Sub WriteUnlockableItem(Remove As Boolean) - Dim myFSOSource As New Scripting.FileSystemObject - Dim tsSource As TextStream - Dim myFSOTarget As New Scripting.FileSystemObject - Dim tsTarget As TextStream - Dim line As String - Dim word As String - Dim word2 As String - Dim unlockableremoved As Boolean - - unlockableremoved = False - - Set tsSource = myFSOSource.OpenTextFile(SOCFile, ForReading, False) - Set tsTarget = myFSOTarget.OpenTextFile(SOCTemp, ForWriting, True) - - Do While Not tsSource.AtEndOfStream - line = tsSource.ReadLine - word = UCase(FirstToken(line)) - word2 = UCase(SecondToken(line)) - - 'If the current item exists in the SOC, delete it. - If word = "UNLOCKABLE" And Val(word2) = lstUnlockables.ListIndex + 1 Then - unlockableremoved = True - Do While Len(TrimComplete(tsSource.ReadLine)) > 0 And Not tsSource.AtEndOfStream - Loop - Else - tsTarget.WriteLine line - End If - Loop - - tsSource.Close - Set myFSOSource = Nothing - - If Remove = False Then - If line <> "" Then tsTarget.WriteLine "" - - tsTarget.WriteLine "UNLOCKABLE " & lstUnlockables.ListIndex + 1 - txtName.Text = TrimComplete(txtName.Text) - txtObjective.Text = TrimComplete(txtObjective.Text) - txtNeededEmblems.Text = TrimComplete(txtNeededEmblems.Text) - txtNeededTime.Text = TrimComplete(txtNeededTime.Text) - txtVar.Text = TrimComplete(txtVar.Text) - - If txtName.Text <> "" Then tsTarget.WriteLine "NAME = " & txtName.Text - If txtObjective.Text <> "" Then tsTarget.WriteLine "OBJECTIVE = " & txtObjective.Text - If txtNeededEmblems.Text <> "" Then tsTarget.WriteLine "NEEDEDEMBLEMS = " & txtNeededEmblems.Text - If txtNeededTime.Text <> "" Then tsTarget.WriteLine "NEEDEDTIME = " & txtNeededTime.Text - If cmbType.ListIndex <> -1 Then tsTarget.WriteLine "TYPE = " & cmbType.ListIndex - If txtVar.Text <> "" Then tsTarget.WriteLine "VAR = " & txtVar.Text - - Dim writegrade As Long - Dim i As Integer - writegrade = 0 - - For i = 0 To chkGrade.Count - 1 - If chkGrade(i).Value = 1 Then - writegrade = writegrade + chkGrade(i).Tag - End If - Next i - - If writegrade > 0 Then tsTarget.WriteLine "NEEDEDGRADE = " & writegrade - End If - - tsTarget.Close - Set myFSOTarget = Nothing - - FileCopy SOCTemp, SOCFile - - Kill SOCTemp - - If Remove = True Then - If unlockableremoved = True Then - MsgBox "Unlockable deleted from SOC." - Else - MsgBox "Couldn't find Unlockable in SOC." - End If - Else - MsgBox "Unlockable Saved." - End If -End Sub diff --git a/tools/SOCEdit/frmUnlockablesEdit.frx b/tools/SOCEdit/frmUnlockablesEdit.frx deleted file mode 100644 index d9d464d4e..000000000 Binary files a/tools/SOCEdit/frmUnlockablesEdit.frx and /dev/null differ diff --git a/tools/SOCEdit/icon1.ico b/tools/SOCEdit/icon1.ico deleted file mode 100644 index 1ea9d1005..000000000 Binary files a/tools/SOCEdit/icon1.ico and /dev/null differ diff --git a/tools/SRB2Launcher/ReadMe.txt b/tools/SRB2Launcher/ReadMe.txt deleted file mode 100644 index 9aafe08b8..000000000 --- a/tools/SRB2Launcher/ReadMe.txt +++ /dev/null @@ -1,35 +0,0 @@ -======================================================================== - WIN32 APPLICATION : SRB2Launcher -======================================================================== - - -AppWizard has created this SRB2Launcher application for you. - -This file contains a summary of what you will find in each of the files that -make up your SRB2Launcher application. - -SRB2Launcher.cpp - This is the main application source file. - -SRB2Launcher.dsp - This file (the project file) contains information at the project level and - is used to build a single project or subproject. Other users can share the - project (.dsp) file, but they should export the makefiles locally. - - -///////////////////////////////////////////////////////////////////////////// -Other standard files: - -StdAfx.h, StdAfx.cpp - These files are used to build a precompiled header (PCH) file - named SRB2Launcher.pch and a precompiled types file named StdAfx.obj. - - -///////////////////////////////////////////////////////////////////////////// -Other notes: - -AppWizard uses "TODO:" to indicate parts of the source code you -should add to or customize. - - -///////////////////////////////////////////////////////////////////////////// diff --git a/tools/SRB2Launcher/SRB2Launcher.cpp b/tools/SRB2Launcher/SRB2Launcher.cpp deleted file mode 100644 index 4138676d3..000000000 --- a/tools/SRB2Launcher/SRB2Launcher.cpp +++ /dev/null @@ -1,1155 +0,0 @@ -///////////////////////////// -// // -// Sonic Robo Blast 2 // -// Official Win32 Launcher // -// // -// By // -// SSNTails // -// ah518@tcnet.org // -// (Sonic Team Junior) // -// http://www.srb2.org // -// // -///////////////////////////// -// -// This source code is released under -// Public Domain. I hope it helps you -// learn how to write exciting Win32 -// applications in C! -// -// However, you may not alter this -// program and continue to call it -// the "Official Sonic Robo Blast 2 -// Launcher". -// -// NOTE: Not all files in this project -// are released under this license. -// Any license mentioned in accompanying -// source files overrides the license -// mentioned here, sorry! -// -// SRB2Launcher.cpp : Defines the entry point for the application. -// - -#include "stdafx.h" -#include -#include -#include "SRB2Launcher.h" - -char TempString[256]; - -char Arguments[16384]; - -HWND mainHWND; -HWND hostHWND; -HWND joinHWND; -HINSTANCE g_hInst; - -HANDLE ServerlistThread = 0; - -typedef struct -{ - char nospecialrings; - char suddendeath; - char scoringtype[16]; - char matchboxes[16]; - int respawnitemtime; - int timelimit; - int pointlimit; -} matchsettings_t; - -typedef struct -{ - char raceitemboxes[16]; - int numlaps; -} racesettings_t; - -typedef struct -{ - char nospecialrings; - char matchboxes[16]; - int respawnitemtime; - int timelimit; - int pointlimit; -} tagsettings_t; - -typedef struct -{ - char nospecialrings; - char matchboxes[16]; - int respawnitemtime; - int timelimit; - int flagtime; - int pointlimit; -} ctfsettings_t; - -typedef struct -{ - char nofile; - char nodownload; -} joinsettings_t; - -typedef struct -{ - matchsettings_t match; - racesettings_t race; - tagsettings_t tag; - ctfsettings_t ctf; - char gametype[16]; - char startmap[9]; - int maxplayers; - char advancestage[16]; - int inttime; - char forceskin; - char noautoaim; - char nosend; - char noadvertise; - - // Monitor Toggles... - char teleporters[8]; - char superring[8]; - char silverring[8]; - char supersneakers[8]; - char invincibility[8]; - char jumpshield[8]; - char watershield[8]; - char ringshield[8]; - char fireshield[8]; - char bombshield[8]; - char oneup[8]; - char eggmanbox[8]; -} hostsettings_t; - -typedef struct -{ - hostsettings_t host; - joinsettings_t join; - char EXEName[1024]; - char ConfigFile[1024]; - char ManualParameters[8192]; - char PlayerName[24]; - char PlayerColor[16]; - char PlayerSkin[24]; -} settings_t; - -// Whole structure is just dumped to a binary file when settings are saved. -settings_t launchersettings; - -#define APPTITLE "Official Sonic Robo Blast 2 Launcher" -#define APPVERSION "v0.1" -#define APPAUTHOR "SSNTails" -#define APPCOMPANY "Sonic Team Junior" - -LRESULT CALLBACK MainProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - -// -// RunSRB2 -// -// Runs SRB2 -// returns true if successful -// -BOOL RunSRB2(void) -{ - SHELLEXECUTEINFO lpExecInfo; - BOOL result; - char EXEName[1024]; - - memset(&lpExecInfo, 0, sizeof(SHELLEXECUTEINFO)); - - lpExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); - - SendMessage(GetDlgItem(mainHWND, IDC_EXENAME), WM_GETTEXT, sizeof(EXEName), (LPARAM)(LPCSTR)EXEName); - lpExecInfo.lpFile = EXEName; - lpExecInfo.lpParameters = Arguments; - lpExecInfo.nShow = SW_SHOWNORMAL; - lpExecInfo.hwnd = mainHWND; - lpExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; - lpExecInfo.lpVerb = "open"; - - result = ShellExecuteEx(&lpExecInfo); - - if(!result) - { - MessageBox(mainHWND, "Error starting the game!", "Error", MB_OK|MB_APPLMODAL|MB_ICONERROR); - return false; - } - - return true; -} - -// -// ChooseEXEName -// -// Provides a common dialog box -// for selecting the desired executable. -// -void ChooseEXEName(void) -{ - OPENFILENAME ofn; - char FileBuffer[256]; - - ZeroMemory(&ofn, sizeof(ofn)); - ofn.hwndOwner = NULL; - FileBuffer[0] = '\0'; - ofn.lpstrFilter = "Executable Files\0*.exe\0All Files\0*.*\0\0"; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFile = FileBuffer; - ofn.lStructSize = sizeof(ofn); - ofn.nMaxFile = sizeof(FileBuffer); - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - if(GetOpenFileName(&ofn)) - { - SendMessage(GetDlgItem(mainHWND, IDC_EXENAME), WM_SETTEXT, 0, (LPARAM)(LPCSTR)FileBuffer); - strcpy(launchersettings.EXEName, FileBuffer); - } -} - -// -// ChooseConfigName -// -// Provides a common dialog box -// for selecting the desired cfg file. -// -void ChooseConfigName(void) -{ - OPENFILENAME ofn; - char FileBuffer[256]; - - ZeroMemory(&ofn, sizeof(ofn)); - ofn.hwndOwner = NULL; - FileBuffer[0] = '\0'; - ofn.lpstrFilter = "Config Files\0*.cfg\0All Files\0*.*\0\0"; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFile = FileBuffer; - ofn.lStructSize = sizeof(ofn); - ofn.nMaxFile = sizeof(FileBuffer); - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - if(GetOpenFileName(&ofn)) - { - SendMessage(GetDlgItem(mainHWND, IDC_CONFIGFILE), WM_SETTEXT, 0, (LPARAM)(LPCSTR)FileBuffer); - strcpy(launchersettings.ConfigFile, FileBuffer); - } -} - -// -// Add External File -// -// Provides a common dialog box -// for adding an external file. -// -void AddExternalFile(void) -{ - OPENFILENAME ofn; - char FileBuffer[256]; - - ZeroMemory(&ofn, sizeof(ofn)); - ofn.hwndOwner = NULL; - FileBuffer[0] = '\0'; - ofn.lpstrFilter = "WAD/SOC Files\0*.soc;*.wad\0All Files\0*.*\0\0"; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFile = FileBuffer; - ofn.lStructSize = sizeof(ofn); - ofn.nMaxFile = sizeof(FileBuffer); - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - if(GetOpenFileName(&ofn) && SendMessage(GetDlgItem(mainHWND, IDC_EXTFILECOMBO), CB_FINDSTRING, -1, (LPARAM)(LPCSTR)FileBuffer) == CB_ERR) - SendMessage(GetDlgItem(mainHWND, IDC_EXTFILECOMBO), CB_ADDSTRING, 0, (LPARAM)(LPCSTR)FileBuffer); -} - -// -// CompileArguments -// -// Go through ALL of the settings -// and put them into a parameter -// string. Yikes! -// -void CompileArguments(void) -{ - HWND temp; - int numitems; - int i; - - // Clear out the arguments, if any existed. - memset(Arguments, 0, sizeof(Arguments)); - - - // WAD/SOC Files Added - temp = GetDlgItem(mainHWND, IDC_EXTFILECOMBO); - - if ((numitems = SendMessage(temp, CB_GETCOUNT, 0, 0)) > 0) - { - char tempbuffer[1024]; - - strcpy(Arguments, "-file "); - - for (i = 0; i < numitems; i++) - { - SendMessage(temp, CB_GETLBTEXT, i, (LPARAM)(LPCSTR)tempbuffer); - strcat(Arguments, tempbuffer); - strcat(Arguments, " "); - } - } - - // Manual Parameters - temp = GetDlgItem(mainHWND, IDC_PARAMETERS); - - if (SendMessage(temp, WM_GETTEXTLENGTH, 0, 0) > 0) - { - char tempbuffer[8192]; - - SendMessage(temp, WM_GETTEXT, 8192, (LPARAM)(LPCSTR)tempbuffer); - - strcat(Arguments, tempbuffer); - } -} - -// -// GetConfigVariable -// -// Pulls a value out of the chosen -// config.cfg and places it into the -// string supplied in 'dest' -// -BOOL GetConfigVariable(char* varname, char* dest) -{ - FILE* f; - int size = 0; - char* buffer; - char* posWeWant; - char* stringstart; - char varnamecpy[256]; - - varnamecpy[0] = '\n'; - - strncpy(varnamecpy+1, varname, 255); - - if(!(f = fopen(launchersettings.ConfigFile, "rb"))) - return false; // Oops! - - // Get file size - while(!feof(f)) - { - size++; - fgetc(f); - } - - fseek(f, 0, SEEK_SET); - - buffer = (char*)malloc(size); - - fread(buffer, size, 1, f); - fclose(f); - - posWeWant = strstr(buffer, varname); - - if(posWeWant == NULL) - { - free(buffer); - return false; - } - - posWeWant++; - - // We are now at the line we want. - // Get the variable from it - - while(*posWeWant != '\"') posWeWant++; - - posWeWant++; - - stringstart = posWeWant; - - while(*posWeWant != '\"') posWeWant++; - - *posWeWant = '\0'; - - strcpy(dest, stringstart); - - free(buffer); - - // Phew! - return true; -} - -SOCKET ConnectSocket(char* IPAddress, int portnumber) -{ - DWORD dwDestAddr; - SOCKADDR_IN sockAddrDest; - SOCKET sockDest; - - // Create socket - sockDest = socket(AF_INET, SOCK_STREAM, 0); - - if(sockDest == SOCKET_ERROR) - { -// printf("Could not create socket: %d\n", WSAGetLastError()); - return INVALID_SOCKET; - } - - // Convert address to in_addr (binary) format - dwDestAddr = inet_addr(IPAddress); - - if(dwDestAddr == INADDR_NONE) - { - // It's not a xxx.xxx.xxx.xxx IP, so resolve through DNS - struct hostent* pHE = gethostbyname(IPAddress); - if(pHE == 0) - { -// printf("Unable to resolve address.\n"); - return INVALID_SOCKET; - } - - dwDestAddr = *((u_long*)pHE->h_addr_list[0]); - } - - // Initialize SOCKADDR_IN with IP address, port number and address family - memcpy(&sockAddrDest.sin_addr, &dwDestAddr, sizeof(DWORD)); - - sockAddrDest.sin_port = htons(portnumber); - sockAddrDest.sin_family = AF_INET; - - // Attempt to connect to server - if(connect(sockDest, (LPSOCKADDR)&sockAddrDest, sizeof(sockAddrDest)) == SOCKET_ERROR) - { -// printf("Could not connect to server socket: %d\n", WSAGetLastError()); - closesocket(sockDest); - return INVALID_SOCKET; - } - - return sockDest; -} - -// -// MS_Write(): -// -static int MS_Write(msg_t *msg, SOCKET socket) -{ -#ifdef NONET - msg = NULL; - return MS_WRITE_ERROR; -#else - int len; - - if (msg->length < 0) - msg->length = (long)strlen(msg->buffer); - len = msg->length + HEADER_SIZE; - - msg->type = htonl(msg->type); - msg->length = htonl(msg->length); - - if (send(socket, (char *)msg, len, 0) != len) - return MS_WRITE_ERROR; - return 0; -#endif -} - -// -// MS_Read(): -// -static int MS_Read(msg_t *msg, SOCKET socket) -{ -#ifdef NONET - msg = NULL; - return MS_READ_ERROR; -#else - if (recv(socket, (char *)msg, HEADER_SIZE, 0) != HEADER_SIZE) - return MS_READ_ERROR; - - msg->type = ntohl(msg->type); - msg->length = ntohl(msg->length); - - if (!msg->length) // fix a bug in Windows 2000 - return 0; - - if (recv(socket, (char *)msg->buffer, msg->length, 0) != msg->length) - return MS_READ_ERROR; - return 0; -#endif -} - -/** Gets a list of game servers from the master server. - */ -static inline int GetServersList(SOCKET socket) -{ - msg_t msg; - int count = 0; - - msg.type = GET_SERVER_MSG; - msg.length = 0; - if (MS_Write(&msg, socket) < 0) - return MS_WRITE_ERROR; - - while (MS_Read(&msg, socket) >= 0) - { - if (!msg.length) - { -// if (!count) -// printf("No server currently running.\n"); - return MS_NO_ERROR; - } - count++; - printf(msg.buffer); - } - - return MS_READ_ERROR; -} - -// -// RunSocketStuff -// -// Thread that checks the masterserver for new games. -void RunSocketStuff(HWND hListView) -{ - WSADATA wsaData; - SOCKET sock; - int i = 0; - char ServerAddressAndPort[256]; - char Address[256]; - char Port[8]; - - if(!GetConfigVariable("masterserver", ServerAddressAndPort)) // srb2.servegame.org:28900 - { - ServerlistThread = NULL; - return; - } - - strcpy(Address, ServerAddressAndPort); - - for(i = 0; i < (signed)strlen(Address); i++) - { - if(Address[i] == ':') - { - Address[i] = '\0'; - break; - } - } - - for(i = 0; i < (signed)strlen(ServerAddressAndPort); i++) - { - if(ServerAddressAndPort[i] == ':') - { - strcpy(Port, &ServerAddressAndPort[i+1]); - break; - } - } - - // Address now contains the hostname or IP - // Port now contains the port number - - - // Initialize WinSock - if(WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) - { -// printf("Could not initialize sockets.\n"); - ServerlistThread = NULL; - return; - } - - // Create socket and connect to server - sock = ConnectSocket(/*IPAddress*/0, /*PortNumber*/0); - if(sock == INVALID_SOCKET) - { -// printf("Socket Error: %d\n", WSAGetLastError()); - ServerlistThread = NULL; - return; - } - - // We're connected! - // Now get information from server - - - // Add games to listview box. - ListView_DeleteAllItems(hListView); - -/* - while (MoreServersStillExist) - { - GetTheNextServerInformation(); - AddItemToList(hListView, servername, ping, players, gametype, level); - } -*/ - - // close socket - closesocket(sock); - - // Clean up WinSock - if(WSACleanup() == SOCKET_ERROR) - { -// printf("Could not cleanup sockets: %d\n", WSAGetLastError()); - ServerlistThread = NULL; - return; - } - - printf("Winsock thread terminated successfully.\n"); - ServerlistThread = NULL; - - return; -} - -BOOL GetGameList(HWND hListView) -{ - DWORD dwThreadID; - ServerlistThread = CreateThread( NULL, // default security - 0, // default stack - (LPTHREAD_START_ROUTINE)(void*)RunSocketStuff, // thread function - hListView, // arguments - 0, // default flags - &dwThreadID); // don't need this, but it makes it happy (and compatible with old Win32 OSes) - - if(ServerlistThread == NULL) - return false; - - return true; -} - -void RegisterDialogClass(char* name, WNDPROC callback) -{ - WNDCLASS wnd; - - wnd.style = CS_HREDRAW | CS_VREDRAW; - wnd.cbWndExtra = DLGWINDOWEXTRA; - wnd.cbClsExtra = 0; - wnd.hCursor = LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW)); - wnd.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_ICON1)); - wnd.hInstance = g_hInst; - wnd.lpfnWndProc = callback; - wnd.lpszClassName = name; - wnd.lpszMenuName = NULL; - wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW); - - if(!RegisterClass(&wnd)) - { - return; - } -} - -int APIENTRY WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - // Prevent multiples instances of this app. - CreateMutex(NULL, true, APPTITLE); - - if(GetLastError() == ERROR_ALREADY_EXISTS) - return 0; - - g_hInst = hInstance; - - RegisterDialogClass("SRB2Launcher", MainProc); - - DialogBox(g_hInst, (LPCSTR)IDD_MAIN, NULL, (DLGPROC)MainProc); - - return 0; -} - -// -// InitHostOptionsComboBoxes -// -// Does what it says. -// -void InitHostOptionsComboBoxes(HWND hwnd) -{ - HWND ctrl; - - ctrl = GetDlgItem(hwnd, IDC_MATCHBOXES); - - if(ctrl) - { - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Normal (Default)"); - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Random"); - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Non-Random"); - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); - } - - ctrl = GetDlgItem(hwnd, IDC_RACEITEMBOXES); - - if(ctrl) - { - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Normal (Default)"); - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Random"); - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Teleports"); - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); - } - - ctrl = GetDlgItem(hwnd, IDC_MATCH_SCORING); - - if(ctrl) - { - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Normal (Default)"); - SendMessage(ctrl, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Classic"); - } -} - -LRESULT CALLBACK MatchOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - InitHostOptionsComboBoxes(hwnd); - break; - - case WM_DESTROY: - EndDialog(hwnd, LOWORD(wParam)); - break; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - PostMessage(hwnd, WM_DESTROY, 0, 0); - break; - default: - break; - } - - break; - } - } - - return 0; -} - -LRESULT CALLBACK RaceOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - InitHostOptionsComboBoxes(hwnd); - break; - - case WM_DESTROY: - EndDialog(hwnd, LOWORD(wParam)); - break; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - PostMessage(hwnd, WM_DESTROY, 0, 0); - break; - default: - break; - } - - break; - } - } - - return 0; -} - -LRESULT CALLBACK TagOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - InitHostOptionsComboBoxes(hwnd); - break; - - case WM_DESTROY: - EndDialog(hwnd, LOWORD(wParam)); - break; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - PostMessage(hwnd, WM_DESTROY, 0, 0); - break; - default: - break; - } - - break; - } - } - - return 0; -} - -LRESULT CALLBACK CTFOptionsDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - InitHostOptionsComboBoxes(hwnd); - break; - - case WM_DESTROY: - EndDialog(hwnd, LOWORD(wParam)); - break; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - PostMessage(hwnd, WM_DESTROY, 0, 0); - break; - default: - break; - } - - break; - } - } - - return 0; -} - -LRESULT CALLBACK HostProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND temp; - - switch(message) - { - case WM_INITDIALOG: - hostHWND = hwnd; - - temp = GetDlgItem(hwnd, IDC_ADVANCEMAP); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Off"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Next (Default)"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Random"); - - temp = GetDlgItem(hwnd, IDC_GAMETYPE); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Coop"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Match"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Team Match"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Race"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Time-Only Race"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Tag"); - SendMessage(temp, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"CTF"); - - break; - - case WM_CREATE: - { - - break; - } - - case WM_DESTROY: - { - hostHWND = NULL; - EndDialog(hwnd, LOWORD(wParam)); - break; - } - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - PostMessage(hwnd, WM_DESTROY, 0, 0); - break; - case IDC_OPTIONS: - { - int gametype; - int dialognum; - DLGPROC callbackfunc; - - // Grab the current gametype from the IDC_GAMETYPE - // combo box and then display the appropriate - // options dialog. - temp = GetDlgItem(hostHWND, IDC_GAMETYPE); - switch(SendMessage(temp, CB_GETCURSEL, 0, 0)) - { - case 0: - gametype = 0; - break; - case 1: - gametype = 1; - break; - case 2: - gametype = 1; - break; - case 3: - gametype = 2; - break; - case 4: - gametype = 2; - break; - case 5: - gametype = 3; - break; - case 6: - gametype = 4; - break; - } - - switch(gametype) - { - case 1: - dialognum = IDD_MATCHOPTIONS; - callbackfunc = (DLGPROC)MatchOptionsDlgProc; - break; - case 2: - dialognum = IDD_RACEOPTIONS; - callbackfunc = (DLGPROC)RaceOptionsDlgProc; - break; - case 3: - dialognum = IDD_TAGOPTIONS; - callbackfunc = (DLGPROC)TagOptionsDlgProc; - break; - case 4: - dialognum = IDD_CTFOPTIONS; - callbackfunc = (DLGPROC)CTFOptionsDlgProc; - break; - case 0: - default: // ??? - dialognum = 0; - callbackfunc = NULL; - MessageBox(hostHWND, "This gametype does not have any additional options.", "Not Available", MB_OK|MB_APPLMODAL); - break; - } - - if(dialognum) - DialogBox(g_hInst, (LPCSTR)dialognum, hostHWND, callbackfunc); - } - break; - default: - break; - } - - break; - } - - case WM_PAINT: - { - break; - } - } - - return 0; -} - -// -// AddItemToList -// -// Adds a game to the list view. -// -void AddItemToList(HWND hListView, char* servername, - char* ping, char* players, - char* gametype, char* level) -{ - LVITEM lvTest; - - lvTest.mask = LVIF_TEXT | LVIF_STATE; - - lvTest.pszText = servername; - lvTest.iIndent = 0; - lvTest.stateMask = 0; - lvTest.state = 0; - - lvTest.iSubItem = 0; - lvTest.iItem = ListView_InsertItem(hListView, &lvTest); - - ListView_SetItemText(hListView,lvTest.iItem,1,ping); - - ListView_SetItemText(hListView,lvTest.iItem,2,players); - - ListView_SetItemText(hListView,lvTest.iItem,3,gametype); - - ListView_SetItemText(hListView,lvTest.iItem,4,level); -} - -// -// InitJoinGameColumns -// -// Initializes the column headers on the listview control -// on the Join Game page. -// -void InitJoinGameColumns(HWND hDlg) -{ - HWND hItemList; - LVCOLUMN columns[10]; - int i = 0; - - //Create the columns in the list control - hItemList = GetDlgItem(hDlg, IDC_GAMELIST); - - columns[i].mask = LVCF_TEXT | LVCF_WIDTH; - columns[i].pszText = "Server Name"; - columns[i].cchTextMax = 256; - columns[i].cx = 120; - columns[i].fmt = LVCFMT_LEFT; - ListView_InsertColumn(hItemList, i, &columns[i]); - - i++; - - columns[i].mask = LVCF_TEXT | LVCF_WIDTH; - columns[i].pszText = "Ping"; - columns[i].cchTextMax = 256; - columns[i].cx = 80; - columns[i].fmt = LVCFMT_LEFT; - ListView_InsertColumn(hItemList, i, &columns[i]); - - i++; - - columns[i].mask = LVCF_TEXT | LVCF_WIDTH; - columns[i].pszText = "Players"; - columns[i].cchTextMax = 256; - columns[i].cx = 80; - columns[i].fmt = LVCFMT_LEFT; - ListView_InsertColumn(hItemList, i, &columns[i]); - - i++; - - columns[i].mask = LVCF_TEXT | LVCF_WIDTH; - columns[i].pszText = "Game Type"; - columns[i].cchTextMax = 256; - columns[i].cx = 80; - columns[i].fmt = LVCFMT_LEFT; - ListView_InsertColumn(hItemList, i, &columns[i]); - - i++; - - columns[i].mask = LVCF_TEXT | LVCF_WIDTH; - columns[i].pszText = "Level"; - columns[i].cchTextMax = 256; - columns[i].cx = 120; - columns[i].fmt = LVCFMT_LEFT; - ListView_InsertColumn(hItemList, i, &columns[i]); -} - -LRESULT CALLBACK JoinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - joinHWND = hwnd; - InitJoinGameColumns(hwnd); - // Start server listing thread - // and grab game list. - GetGameList(GetDlgItem(hwnd, IDC_GAMELIST)); - break; - - case WM_DESTROY: - joinHWND = NULL; - // Terminate server listing thread. - EndDialog(hwnd, LOWORD(wParam)); - break; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - PostMessage(hwnd, WM_DESTROY, 0, 0); - break; - case IDC_SEARCHGAMES: - if(ServerlistThread == NULL) - GetGameList(GetDlgItem(hwnd, IDC_GAMELIST)); - break; - default: - break; - } - - break; - } - - case WM_PAINT: - { - break; - } - } - - return 0; -} - -void InitializeDefaults(void) -{ - memset(&launchersettings, 0, sizeof(launchersettings)); - strcpy(launchersettings.EXEName, "srb2win.exe"); - strcpy(launchersettings.ConfigFile, "config.cfg"); -} - -LRESULT CALLBACK MainProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - HWND temp; - - switch(message) - { - case WM_INITDIALOG: - mainHWND = hwnd; - InitializeDefaults(); - SendMessage(GetDlgItem(hwnd, IDC_EXENAME), WM_SETTEXT, 0, (LPARAM)(LPCSTR)launchersettings.EXEName); - SendMessage(GetDlgItem(hwnd, IDC_CONFIGFILE), WM_SETTEXT, 0, (LPARAM)(LPCSTR)launchersettings.ConfigFile); - break; - - case WM_CREATE: - { - - break; - } - - case WM_DESTROY: - { - PostQuitMessage(0); - break; - } - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - PostMessage(hwnd, WM_DESTROY, 0, 0); - break; - case IDC_ABOUT: // The About button. - sprintf(TempString, "%s %s by %s - %s", APPTITLE, APPVERSION, APPAUTHOR, APPCOMPANY); - MessageBox(mainHWND, TempString, "About", MB_OK|MB_APPLMODAL); - break; - case IDC_FINDEXENAME: - ChooseEXEName(); - break; - case IDC_FINDCONFIGNAME: - ChooseConfigName(); - break; - case IDC_ADDFILE: - AddExternalFile(); - break; - case IDC_REMOVEFILE: - temp = GetDlgItem(mainHWND, IDC_EXTFILECOMBO); - SendMessage(temp, CB_DELETESTRING, SendMessage(temp, CB_GETCURSEL, 0, 0), 0); - break; - case IDC_HOSTGAME: - DialogBox(g_hInst, (LPCSTR)IDD_HOSTGAME, mainHWND, (DLGPROC)HostProc); - break; - case IDC_JOINGAME: - DialogBox(g_hInst, (LPCSTR)IDD_JOINGAME, mainHWND, (DLGPROC)JoinProc); - break; - case IDC_GO: - CompileArguments(); - RunSRB2(); - break; - default: - break; - } - - break; - } - - case WM_PAINT: - { - break; - } - } - - return 0; -} - diff --git a/tools/SRB2Launcher/SRB2Launcher.dsp b/tools/SRB2Launcher/SRB2Launcher.dsp deleted file mode 100644 index 386dc301c..000000000 --- a/tools/SRB2Launcher/SRB2Launcher.dsp +++ /dev/null @@ -1,144 +0,0 @@ -# Microsoft Developer Studio Project File - Name="SRB2Launcher" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=SRB2Launcher - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SRB2Launcher.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SRB2Launcher.mak" CFG="SRB2Launcher - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SRB2Launcher - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "SRB2Launcher - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SRB2Launcher - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:windows /machine:I386 - -!ELSEIF "$(CFG)" == "SRB2Launcher - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "SRB2Launcher - Win32 Release" -# Name "SRB2Launcher - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\SRB2Launcher.cpp -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.cpp -# ADD CPP /Yc"stdafx.h" -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\lilsocklib.h -# End Source File -# Begin Source File - -SOURCE=.\resource.h -# End Source File -# Begin Source File - -SOURCE=.\SRB2Launcher.h -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# Begin Source File - -SOURCE=.\bitmap1.bmp -# End Source File -# Begin Source File - -SOURCE=.\icon1.ico -# End Source File -# Begin Source File - -SOURCE=.\Script1.rc -# End Source File -# End Group -# Begin Source File - -SOURCE=.\ReadMe.txt -# End Source File -# End Target -# End Project diff --git a/tools/SRB2Launcher/SRB2Launcher.dsw b/tools/SRB2Launcher/SRB2Launcher.dsw deleted file mode 100644 index b716faced..000000000 --- a/tools/SRB2Launcher/SRB2Launcher.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SRB2Launcher"=.\SRB2Launcher.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/tools/SRB2Launcher/SRB2Launcher.h b/tools/SRB2Launcher/SRB2Launcher.h deleted file mode 100644 index 3b9049f82..000000000 --- a/tools/SRB2Launcher/SRB2Launcher.h +++ /dev/null @@ -1,8 +0,0 @@ -extern char TempString[256]; -extern char EXEName[1024]; -extern char Arguments[16384]; - -#define APPTITLE "Official Sonic Robo Blast 2 Launcher" -#define APPVERSION "v0.1" -#define APPAUTHOR "SSNTails" -#define APPCOMPANY "Sonic Team Junior" diff --git a/tools/SRB2Launcher/Script1.rc b/tools/SRB2Launcher/Script1.rc deleted file mode 100644 index 1a27c0414..000000000 --- a/tools/SRB2Launcher/Script1.rc +++ /dev/null @@ -1,355 +0,0 @@ -//Microsoft Developer Studio generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_MAIN DIALOG DISCARDABLE 0, 0, 272, 226 -STYLE DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU -CAPTION "Official Sonic Robo Blast 2 Launcher v0.1" -FONT 8, "MS Sans Serif" -BEGIN - COMBOBOX IDC_LAUNCHCONFIG,125,15,135,155,CBS_DROPDOWNLIST | - CBS_SORT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Saved Launch Configuration",IDC_STATIC,120,5,145,45 - GROUPBOX "WAD/SOC Files",IDC_STATIC,120,55,145,45 - COMBOBOX IDC_EXTFILECOMBO,125,65,135,95,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - CONTROL 102,IDC_STATIC,"Static",SS_BITMAP,5,90,107,79 - PUSHBUTTON "&About",IDC_ABOUT,125,210,25,10 - DEFPUSHBUTTON "&Go!",IDC_GO,60,150,50,14 - PUSHBUTTON "Add",IDC_ADDFILE,225,80,35,15 - PUSHBUTTON "Remove",IDC_REMOVEFILE,185,80,35,15 - PUSHBUTTON "Save",IDC_SAVELAUNCHCFG,220,30,40,15 - GROUPBOX "Multiplayer",IDC_STATIC,5,5,105,50 - PUSHBUTTON "&Join A Game",IDC_JOINGAME,10,15,50,15 - PUSHBUTTON "&Host A Game",IDC_HOSTGAME,55,35,50,15 - EDITTEXT IDC_PARAMETERS,160,190,105,30,ES_MULTILINE | - ES_AUTOVSCROLL | WS_VSCROLL - RTEXT "Manual Parameters:",IDC_STATIC,115,190,40,15 - GROUPBOX "Executable Name",IDC_STATIC,120,105,145,50 - EDITTEXT IDC_EXENAME,125,115,95,12,ES_AUTOHSCROLL - PUSHBUTTON "Choose...",IDC_FINDEXENAME,225,115,35,10 - PUSHBUTTON "General &Options",IDC_OPTIONS,55,60,50,20,BS_MULTILINE - EDITTEXT IDC_CONFIGFILE,125,140,95,12,ES_AUTOHSCROLL - LTEXT "Configuration File:",IDC_STATIC,125,130,60,10 - PUSHBUTTON "Choose...",IDC_FINDCONFIGNAME,225,140,35,10 - CONTROL "List1",IDC_LIST1,"SysListView32",WS_BORDER | WS_TABSTOP, - 20,180,85,40 -END - -IDD_JOINGAME DIALOG DISCARDABLE 0, 0, 367, 166 -STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU -CAPTION "Join Game" -FONT 8, "MS Sans Serif" -BEGIN - PUSHBUTTON "&Refresh List",IDC_SEARCHGAMES,5,140,55,20,BS_MULTILINE - CONTROL "List1",IDC_GAMELIST,"SysListView32",LVS_REPORT | - LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,5,15,240,120 - EDITTEXT IDC_NAME,295,10,65,12,ES_AUTOHSCROLL - COMBOBOX IDC_COLOR,295,30,65,130,CBS_DROPDOWNLIST | CBS_SORT | - WS_VSCROLL | WS_TABSTOP - RTEXT "Name:",IDC_STATIC,265,10,25,10 - RTEXT "Color:",IDC_STATIC,265,30,25,10 - COMBOBOX IDC_SKIN,295,50,65,110,CBS_DROPDOWNLIST | CBS_SORT | - WS_VSCROLL | WS_TABSTOP - RTEXT "Character:",IDC_STATIC,255,50,35,10 - EDITTEXT IDC_ADDRESS,255,115,70,12,ES_AUTOHSCROLL - LTEXT "Manual Address:",IDC_STATIC,255,105,60,10 - CONTROL "Don't check server for files.",IDC_NOFILE,"Button", - BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,255,70,105, - 10 - DEFPUSHBUTTON "&Go!",IDC_JOINSTART,330,115,30,15 - LTEXT "Double-Click on a game to join:",IDC_STATIC,5,5,215,10 - CONTROL "Don't download files",IDC_NODOWNLOAD,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,255,90,105,10 -END - -IDD_HOSTGAME DIALOG DISCARDABLE 0, 0, 287, 156 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Host Game" -FONT 8, "MS Sans Serif" -BEGIN - GROUPBOX "Game Type",IDC_STATIC,5,5,110,65 - PUSHBUTTON "&Options...",IDC_OPTIONS,55,30,40,15 - COMBOBOX IDC_GAMETYPE,10,15,85,100,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - RTEXT "Max # of players:",IDC_STATIC,35,86,70,10 - EDITTEXT IDC_MAXPLAYERS,110,86,20,12,ES_AUTOHSCROLL - GROUPBOX "General Options",IDC_STATIC,5,75,275,75 - COMBOBOX IDC_STARTMAP,40,50,70,95,CBS_DROPDOWN | CBS_SORT | - WS_VSCROLL | WS_TABSTOP - RTEXT "Start on map #:",IDC_STATIC,10,45,25,20 - CONTROL "Force players to use host's character",IDC_FORCESKIN, - "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,140, - 85,135,10 - COMBOBOX IDC_ADVANCEMAP,45,105,85,50,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP - RTEXT "Advance Stage:",IDC_STATIC,10,100,30,20 - CONTROL "Don't advertise server on Internet",IDC_INTERNETSERVER, - "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,140, - 130,120,10 - RTEXT "Intermission Delay Between Levels (in seconds):", - IDC_STATIC,10,125,90,15 - EDITTEXT IDC_INTTIME,105,130,20,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Don't allow autoaim",IDC_DISABLEAUTOAIM,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,140,100,75,10 - CONTROL "Disable WAD/SOC Downloading",IDC_NODOWNLOAD,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,140,115,120,10 - PUSHBUTTON "Monitor &Toggles...",IDC_MONITORTOGGLES,125,45,40,20, - BS_MULTILINE -END - -IDD_MATCHOPTIONS DIALOG DISCARDABLE 0, 0, 142, 141 -STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU -CAPTION "Match Options" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "Don't use special ring weapons.",IDC_SPECIALRINGS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,5,115,10 - RTEXT "Item Box Behavior:",IDC_STATIC,5,50,60,10 - EDITTEXT IDC_RESPAWNITEMTIME,115,70,20,12,ES_AUTOHSCROLL | - ES_NUMBER - COMBOBOX IDC_MATCHBOXES,70,50,65,65,CBS_DROPDOWN | CBS_SORT | - WS_VSCROLL | WS_TABSTOP - RTEXT "Item Respawn Time (in seconds):",IDC_STATIC,5,70,105,10 - EDITTEXT IDC_TIMELIMIT,115,84,20,12,ES_AUTOHSCROLL | ES_NUMBER - RTEXT "Time Limit (in minutes):",IDC_STATIC,35,84,75,10 - RTEXT "Point Limit:",IDC_STATIC,70,100,40,10 - EDITTEXT IDC_POINTLIMIT,115,100,20,12,ES_AUTOHSCROLL | ES_NUMBER - CONTROL "Sudden Death Mode",IDC_SUDDENDEATH,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,15,20,80,10 - COMBOBOX IDC_MATCH_SCORING,70,35,65,65,CBS_DROPDOWNLIST | - CBS_SORT | WS_VSCROLL | WS_TABSTOP - RTEXT "Scoring Type:",IDC_STATIC,15,35,50,10 - PUSHBUTTON "Cance&l",IDC_CANCEL,100,120,35,15 - DEFPUSHBUTTON "O&K",IDC_OK,60,120,35,15 -END - -IDD_RACEOPTIONS DIALOG DISCARDABLE 0, 0, 142, 71 -STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU -CAPTION "Race Options" -FONT 8, "MS Sans Serif" -BEGIN - RTEXT "Item Box Behavior:",IDC_STATIC,5,10,60,10 - COMBOBOX IDC_RACEITEMBOXES,70,10,65,55,CBS_DROPDOWNLIST | - CBS_SORT | WS_VSCROLL | WS_TABSTOP - EDITTEXT IDC_NUMLAPS,115,30,20,12,ES_AUTOHSCROLL | ES_NUMBER - RTEXT "Number of Laps:",IDC_STATIC,55,30,55,10 - PUSHBUTTON "Cance&l",IDC_CANCEL,100,50,35,15 - DEFPUSHBUTTON "O&K",IDC_OK,60,50,35,15 -END - -IDD_CTFOPTIONS DIALOG DISCARDABLE 0, 0, 142, 126 -STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU -CAPTION "CTF Options" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "Don't use special ring weapons.",IDC_SPECIALRINGS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,5,115,10 - RTEXT "Item Box Behavior:",IDC_STATIC,5,20,60,10 - COMBOBOX IDC_MATCHBOXES,70,20,65,60,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - RTEXT "Item Respawn Time (in seconds):",IDC_STATIC,5,40,105,10 - EDITTEXT IDC_RESPAWNITEMTIME,115,40,20,12,ES_AUTOHSCROLL | - ES_NUMBER - RTEXT "Time Limit (in minutes):",IDC_STATIC,35,70,75,10 - EDITTEXT IDC_TIMELIMIT,115,70,20,12,ES_AUTOHSCROLL | ES_NUMBER - RTEXT "Point Limit:",IDC_STATIC,70,86,40,10 - EDITTEXT IDC_POINTLIMIT,115,86,20,12,ES_AUTOHSCROLL | ES_NUMBER - RTEXT "Flag Respawn Time (in seconds):",IDC_STATIC,5,55,105,10 - EDITTEXT IDC_FLAGTIME,115,55,20,12,ES_AUTOHSCROLL | ES_NUMBER - PUSHBUTTON "Cance&l",IDC_CANCEL,100,105,35,15 - DEFPUSHBUTTON "O&K",IDC_OK,60,105,35,15 -END - -IDD_TAGOPTIONS DIALOG DISCARDABLE 0, 0, 142, 111 -STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU -CAPTION "Tag Options" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "Don't use special ring weapons.",IDC_SPECIALRINGS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,5,115,10 - COMBOBOX IDC_MATCHBOXES,70,20,65,60,CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - RTEXT "Item Box Behavior:",IDC_STATIC,5,20,60,10 - DEFPUSHBUTTON "O&K",IDC_OK,60,90,35,15 - PUSHBUTTON "Cance&l",IDC_CANCEL,100,90,35,15 - RTEXT "Item Respawn Time (in seconds):",IDC_STATIC,5,40,105,10 - EDITTEXT IDC_RESPAWNITEMTIME,115,40,20,12,ES_AUTOHSCROLL | - ES_NUMBER - RTEXT "Time Limit (in minutes):",IDC_STATIC,35,55,75,10 - EDITTEXT IDC_TIMELIMIT,115,55,20,12,ES_AUTOHSCROLL | ES_NUMBER - RTEXT "Point Limit:",IDC_STATIC,70,70,40,10 - EDITTEXT IDC_POINTLIMIT,115,70,20,12,ES_AUTOHSCROLL | ES_NUMBER -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO DISCARDABLE -BEGIN - IDD_MAIN, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 265 - TOPMARGIN, 7 - BOTTOMMARGIN, 219 - END - - IDD_JOINGAME, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 360 - TOPMARGIN, 7 - BOTTOMMARGIN, 159 - END - - IDD_HOSTGAME, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 280 - TOPMARGIN, 7 - BOTTOMMARGIN, 149 - END - - IDD_MATCHOPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 135 - TOPMARGIN, 7 - BOTTOMMARGIN, 134 - END - - IDD_RACEOPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 135 - TOPMARGIN, 7 - BOTTOMMARGIN, 64 - END - - IDD_CTFOPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 135 - TOPMARGIN, 7 - BOTTOMMARGIN, 119 - END - - IDD_TAGOPTIONS, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 135 - TOPMARGIN, 7 - BOTTOMMARGIN, 104 - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE DISCARDABLE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE DISCARDABLE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE DISCARDABLE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDB_BITMAP1 BITMAP DISCARDABLE "bitmap1.bmp" - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ICON1 ICON DISCARDABLE "icon1.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog Info -// - -IDD_JOINGAME DLGINIT -BEGIN - IDC_SKIN, 0x403, 6, 0 -0x6f53, 0x696e, 0x0063, - IDC_SKIN, 0x403, 6, 0 -0x6154, 0x6c69, 0x0073, - IDC_SKIN, 0x403, 9, 0 -0x6e4b, 0x6375, 0x6c6b, 0x7365, "\000" - 0 -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/tools/SRB2Launcher/StdAfx.cpp b/tools/SRB2Launcher/StdAfx.cpp deleted file mode 100644 index 444cafebf..000000000 --- a/tools/SRB2Launcher/StdAfx.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// SRB2Launcher.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/tools/SRB2Launcher/StdAfx.h b/tools/SRB2Launcher/StdAfx.h deleted file mode 100644 index 549cbf9ee..000000000 --- a/tools/SRB2Launcher/StdAfx.h +++ /dev/null @@ -1,29 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) -#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include -#include -#include -#include -#include -#include "lilsocklib.h" -#include "resource.h" - - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/tools/SRB2Launcher/bitmap1.bmp b/tools/SRB2Launcher/bitmap1.bmp deleted file mode 100644 index 01b7cecd9..000000000 Binary files a/tools/SRB2Launcher/bitmap1.bmp and /dev/null differ diff --git a/tools/SRB2Launcher/i_tcp.c b/tools/SRB2Launcher/i_tcp.c deleted file mode 100644 index 259b416d3..000000000 --- a/tools/SRB2Launcher/i_tcp.c +++ /dev/null @@ -1,57 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// MSERV SDK -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Adapted by Oogaland. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// -// DESCRIPTION: -// TCP/IP stuff. -// -//----------------------------------------------------------------------------- - - - - -#include -#include - - -#include "launcher.h" -#include "mserv.h" //Hurdler: support master server - - - - -static int init_tcp_driver = 0; - - -void I_InitTcpDriver(void) -{ - if (!init_tcp_driver) - { -#ifdef __WIN32__ - WSADATA winsockdata; - if( WSAStartup(MAKEWORD(1,1),&winsockdata) ) - I_Error("No Tcp/Ip driver detected"); -#endif -#ifdef __DJGPP_ - if( !__lsck_init() ) - I_Error("No Tcp/Ip driver detected"); -#endif - init_tcp_driver = 1; - } -} diff --git a/tools/SRB2Launcher/i_tcp.h b/tools/SRB2Launcher/i_tcp.h deleted file mode 100644 index 9cd34f930..000000000 --- a/tools/SRB2Launcher/i_tcp.h +++ /dev/null @@ -1,34 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// MSERV SDK -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Adapted by Oogaland. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// -// DESCRIPTION: -// Header file for the TCP/IP routines -// -//----------------------------------------------------------------------------- - - -#ifndef _I_TCP_H_ -#define _I_TCP_H_ - -extern int sock_port; - -void I_InitTcpDriver(void); - -#endif // !defined(_I_TCP_H_) diff --git a/tools/SRB2Launcher/icon1.ico b/tools/SRB2Launcher/icon1.ico deleted file mode 100644 index f54ce0d6a..000000000 Binary files a/tools/SRB2Launcher/icon1.ico and /dev/null differ diff --git a/tools/SRB2Launcher/launcher.c b/tools/SRB2Launcher/launcher.c deleted file mode 100644 index 4967a95cc..000000000 --- a/tools/SRB2Launcher/launcher.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#include "launcher.h" - -int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved) -{ - return TRUE; -} - - -void CONS_Printf(char *fmt, ...) -{ - MessageBox(NULL, fmt, "Master Server", 0); -} - -void I_Error (char *error, ...) -{ - MessageBox(NULL, error, "Master Server", MB_ICONERROR); -} diff --git a/tools/SRB2Launcher/launcher.h b/tools/SRB2Launcher/launcher.h deleted file mode 100644 index 12b10aad5..000000000 --- a/tools/SRB2Launcher/launcher.h +++ /dev/null @@ -1,34 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// MSERV SDK -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Adapted by Oogaland. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// -// DESCRIPTION: -// Header file for the launcher routines -// -//----------------------------------------------------------------------------- - - -#ifndef _LAUNCHER_H_ -#define _LAUNCHER_H_ - - -void CONS_Printf(char *fmt, ...); -void I_Error (char *error, ...); - -#endif // !defined(_LAUNCHER_H_) diff --git a/tools/SRB2Launcher/lilsocklib.h b/tools/SRB2Launcher/lilsocklib.h deleted file mode 100644 index 232f3753a..000000000 --- a/tools/SRB2Launcher/lilsocklib.h +++ /dev/null @@ -1,52 +0,0 @@ -// Unlike lilsocklib.c, since this takes code from SRB2, -// it is under the GPL, rather than public domain. =( -// -#ifndef __LILSOCKLIB_H__ -#define __LILSOCKLIB_H__ - -#define SD_BOTH 0x02 - -#define PACKET_SIZE 1024 - -#define MS_NO_ERROR 0 -#define MS_SOCKET_ERROR -201 -#define MS_CONNECT_ERROR -203 -#define MS_WRITE_ERROR -210 -#define MS_READ_ERROR -211 -#define MS_CLOSE_ERROR -212 -#define MS_GETHOSTBYNAME_ERROR -220 -#define MS_GETHOSTNAME_ERROR -221 -#define MS_TIMEOUT_ERROR -231 - -// see master server code for the values -#define ADD_SERVER_MSG 101 -#define REMOVE_SERVER_MSG 103 -#ifdef MASTERSERVERS12 -#define ADD_SERVERv2_MSG 104 -#endif -#define GET_SERVER_MSG 200 -#define GET_SHORT_SERVER_MSG 205 -#ifdef MASTERSERVERS12 -#define ASK_SERVER_MSG 206 -#define ANSWER_ASK_SERVER_MSG 207 -#endif - -#define HEADER_SIZE ((long)sizeof (long)*3) - -#define HEADER_MSG_POS 0 -#define IP_MSG_POS 16 -#define PORT_MSG_POS 32 -#define HOSTNAME_MSG_POS 40 - -/** A message to be exchanged with the master server. - */ -typedef struct -{ - long id; ///< Unused? - long type; ///< Type of message. - long length; ///< Length of the message. - char buffer[PACKET_SIZE]; ///< Actual contents of the message. -} msg_t; - -SOCKET ConnectSocket(char* IPAddress); -#endif diff --git a/tools/SRB2Launcher/mserv.c b/tools/SRB2Launcher/mserv.c deleted file mode 100644 index 0dd00e2bb..000000000 --- a/tools/SRB2Launcher/mserv.c +++ /dev/null @@ -1,400 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// MSERV SDK -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Adapted by Oogaland. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// -// DESCRIPTION: -// Commands used to communicate with the master server -// -//----------------------------------------------------------------------------- - - -#ifdef WIN32 -#include // socket(),... -#else -#include -#endif - - - - -#include "launcher.h" - -#include "mserv.h" -#include "i_tcp.h" - - - - - -// ================================ DEFINITIONS =============================== - -#define PACKET_SIZE 1024 - -#define MS_NO_ERROR 0 -#define MS_SOCKET_ERROR -201 -#define MS_CONNECT_ERROR -203 -#define MS_WRITE_ERROR -210 -#define MS_READ_ERROR -211 -#define MS_CLOSE_ERROR -212 -#define MS_GETHOSTBYNAME_ERROR -220 -#define MS_GETHOSTNAME_ERROR -221 -#define MS_TIMEOUT_ERROR -231 - -// see master server code for the values -#define GET_SERVER_MSG 200 - - -#define HEADER_SIZE ((long)sizeof(long)*3) - -#define HEADER_MSG_POS 0 -#define IP_MSG_POS 16 -#define PORT_MSG_POS 32 -#define HOSTNAME_MSG_POS 40 - -#ifndef SOCKET -#define SOCKET int -#endif - -typedef struct { - long id; - long type; - long length; - char buffer[PACKET_SIZE]; -} msg_t; - - -// win32 or djgpp -#if defined( WIN32) || defined( __DJGPP__ ) -#define ioctl ioctlsocket -#define close closesocket -#endif - -#if defined( WIN32) || defined( __OS2__) -// it seems windows doesn't define that... maybe some other OS? OS/2 -int inet_aton(char *hostname, struct in_addr *addr) -{ - return ( (addr->s_addr=inet_addr(hostname)) != INADDR_NONE ); -} -#endif - - - -enum { MSCS_NONE, MSCS_WAITING, MSCS_REGISTERED, MSCS_FAILED } con_state = MSCS_NONE; - - -static SOCKET socket_fd = -1; // TCP/IP socket -static struct sockaddr_in addr; -static struct timeval select_timeout; -static fd_set wset; - -int MS_Connect(char *ip_addr, char *str_port, int async); -static int MS_Read(msg_t *msg); -static int MS_Write(msg_t *msg); -static int MS_GetIP(char *); - -void ExtractServerInfo(char *serverout, struct SERVERLIST *serverlist); - - - - - - - - - - -void CloseConnection(void) -{ - if(socket_fd > 0) close(socket_fd); - socket_fd = -1; -} - - - - -/* -** MS_GetIP() -*/ -static int MS_GetIP(char *hostname) -{ - struct hostent *host_ent; - - if (!inet_aton(hostname, &addr.sin_addr)) { - //TODO: only when we are connected to Internet, or use a non bloking call - host_ent = gethostbyname(hostname); - if (host_ent==NULL) - return MS_GETHOSTBYNAME_ERROR; - memcpy(&addr.sin_addr, host_ent->h_addr_list[0], sizeof(struct in_addr)); - } - return 0; -} - - - - - - -/* -** MS_Connect() -*/ -int MS_Connect(char *ip_addr, char *str_port, int async) -{ - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - I_InitTcpDriver(); // this is done only if not already done - - if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return MS_SOCKET_ERROR; - - if (MS_GetIP(ip_addr)==MS_GETHOSTBYNAME_ERROR) - return MS_GETHOSTBYNAME_ERROR; - addr.sin_port = htons((u_short)atoi(str_port)); - - if (async) // do asynchronous connection - { - int res = 1; - - ioctl(socket_fd, FIONBIO, &res); - res = connect(socket_fd, (struct sockaddr *) &addr, sizeof(addr)); - if (res < 0) - { - // humm, on win32 it doesn't work with EINPROGRESS (stupid windows) - if (WSAGetLastError() != WSAEWOULDBLOCK) - { - con_state = MSCS_FAILED; - CloseConnection(); - return MS_CONNECT_ERROR; - } - } - con_state = MSCS_WAITING; - FD_ZERO(&wset); - FD_SET(socket_fd, &wset); - select_timeout.tv_sec = 0, select_timeout.tv_usec = 0; - } - else - { - if (connect(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) - return MS_CONNECT_ERROR; - } - - return 0; -} - - - - - - -/* - * MS_Write(): - */ -static int MS_Write(msg_t *msg) -{ - int len; - - if (msg->length < 0) - msg->length = strlen(msg->buffer); - len = msg->length+HEADER_SIZE; - - //msg->id = htonl(msg->id); - msg->type = htonl(msg->type); - msg->length = htonl(msg->length); - - if (send(socket_fd, (char*)msg, len, 0) != len) - return MS_WRITE_ERROR; - - return 0; -} - - - - - - -/* - * MS_Read(): - */ -static int MS_Read(msg_t *msg) -{ - if (recv(socket_fd, (char*)msg, HEADER_SIZE, 0) != HEADER_SIZE) - return MS_READ_ERROR; - - msg->type = ntohl(msg->type); - msg->length = ntohl(msg->length); - - if (!msg->length) //Hurdler: fix a bug in Windows 2000 - return 0; - - if (recv(socket_fd, (char*)msg->buffer, msg->length, 0) != msg->length) - return MS_READ_ERROR; - - return 0; -} - - - - - - - - -/***************************************************************************/ - - - - - - - - - -/* GetServerListEx */ -EXPORT int __stdcall GetServerListEx(char *host, char *str_port, struct SERVERLIST serverlist[], short max_servers) -{ - msg_t msg; - int count = 0; - - - /* Attempt to connect to list server. */ - MS_Connect(host, str_port, 0); - - /* Poll the list server. If it fails, depart with an error code of -1. */ - msg.type = GET_SERVER_MSG; - msg.length = 0; - if (MS_Write(&msg) < 0) - return -1; - - - - /* Get a description of each server in turn. */ - /* What we get is exactly the same as the output to the console when using LISTSERV. */ - while (MS_Read(&msg) >= 0) - { - if(msg.length == 0 || count >= max_servers) - { - CloseConnection(); - return count; - } - - ExtractServerInfo(msg.buffer, &serverlist[count]); - - count++; - } - - - CloseConnection(); - return -2; -} - - - - - - - - - - - -/* GetServerList */ -/* Warning: Large kludge follows! This function is only included for backwards-compatibility. */ -/* Use GetServerListVB or GetServerListEx instead. */ -EXPORT int __stdcall GetServerList(char *host, char *str_port, - - struct SERVERLIST *serverlist1,struct SERVERLIST *serverlist2,struct SERVERLIST *serverlist3, - struct SERVERLIST *serverlist4,struct SERVERLIST *serverlist5,struct SERVERLIST *serverlist6, - struct SERVERLIST *serverlist7,struct SERVERLIST *serverlist8,struct SERVERLIST *serverlist9, - struct SERVERLIST *serverlist10,struct SERVERLIST *serverlist11,struct SERVERLIST *serverlist12, - struct SERVERLIST *serverlist13,struct SERVERLIST *serverlist14,struct SERVERLIST *serverlist15, - struct SERVERLIST *serverlist16) -{ - msg_t msg; - int count = 0; - struct SERVERLIST *serverlist[16]; - - - /* Attempt to connect to list server. */ - MS_Connect(host, str_port, 0); - - /* Poll the list server. If it fails, bomb with an error code of -1. */ - msg.type = GET_SERVER_MSG; - msg.length = 0; - if (MS_Write(&msg) < 0) - return -1; - - serverlist[0] = serverlist1; - serverlist[1] = serverlist2; - serverlist[2] = serverlist3; - serverlist[3] = serverlist4; - serverlist[4] = serverlist5; - serverlist[5] = serverlist6; - serverlist[6] = serverlist7; - serverlist[7] = serverlist8; - serverlist[8] = serverlist9; - serverlist[9] = serverlist10; - serverlist[10] = serverlist11; - serverlist[11] = serverlist12; - serverlist[12] = serverlist13; - serverlist[13] = serverlist14; - serverlist[14] = serverlist15; - serverlist[15] = serverlist16; - - - - - while (MS_Read(&msg) >= 0 && count < 16) - { - if(msg.length == 0 || count >= 16) - { - CloseConnection(); - return count; - } - - ExtractServerInfo(msg.buffer, serverlist[count]); - - count++; - } - - - CloseConnection(); - - - return -2; -} - - - -void ExtractServerInfo(char *serverout, struct SERVERLIST *serverlist) -{ - char *lines[5]; - int i; - - i=0; - lines[0] = strtok(serverout, "\r\n"); - for(i=1; i<5; i++) - { - lines[i] = strtok(NULL, "\r\n"); - } - - strcpy(serverlist->ip, strstr(lines[0], ": ")+2); - strcpy(serverlist->port, strstr(lines[1], ": ")+2); - strcpy(serverlist->name, strstr(lines[2], ": ")+2); - strcpy(serverlist->version, strstr(lines[3], ": ")+2); - strcpy(serverlist->perm, strstr(lines[4], ": ")+2); -} diff --git a/tools/SRB2Launcher/mserv.h b/tools/SRB2Launcher/mserv.h deleted file mode 100644 index 8f32ae632..000000000 --- a/tools/SRB2Launcher/mserv.h +++ /dev/null @@ -1,64 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// MSERV SDK -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Adapted by Oogaland. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// -// DESCRIPTION: -// Header file for the master server routines -// -//----------------------------------------------------------------------------- - -#ifndef _MSERV_H_ -#define _MSERV_H_ - - - -#ifndef EXPORT -#ifdef __cplusplus -#define EXPORT extern "C" __declspec (dllexport) -#else -#define EXPORT __declspec (dllexport) -#endif -#endif - - - -struct SERVERLIST -{ - char ip[16]; - char port[6]; - char name[32]; - char version[16]; - char perm[4]; -}; - - - -EXPORT int __stdcall GetServerListEx(char *ip_addr, char *str_port, struct SERVERLIST serverlist[], short max_servers); -EXPORT int __stdcall GetServerList(char *ip_addr, char *str_port, - struct SERVERLIST *serverlist1,struct SERVERLIST *serverlist2,struct SERVERLIST *serverlist3, - struct SERVERLIST *serverlist4,struct SERVERLIST *serverlist5,struct SERVERLIST *serverlist6, - struct SERVERLIST *serverlist7,struct SERVERLIST *serverlist8,struct SERVERLIST *serverlist9, - struct SERVERLIST *serverlist10,struct SERVERLIST *serverlist11,struct SERVERLIST *serverlist12, - struct SERVERLIST *serverlist13,struct SERVERLIST *serverlist14,struct SERVERLIST *serverlist15, - struct SERVERLIST *serverlist16); - - - - -#endif // !defined(_MSERV_H_) diff --git a/tools/SRB2Launcher/mservsdk.h b/tools/SRB2Launcher/mservsdk.h deleted file mode 100644 index 722288e0b..000000000 --- a/tools/SRB2Launcher/mservsdk.h +++ /dev/null @@ -1,65 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// MSERV SDK -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// Adapted by Oogaland. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// -// -// DESCRIPTION: -// Header file for the master server SDK. -// -//----------------------------------------------------------------------------- - -#ifndef _MSERVSDK_H_ -#define _MSERVSDK_H_ - - - -#ifndef IMPORT -#ifdef __cplusplus -#define IMPORT extern "C" __declspec (dllimport) -#else -#define IMPORT __declspec (dllimport) -#endif -#endif - - - - -struct SERVERLIST -{ - char ip[16]; - char port[6]; - char name[32]; - char version[16]; - char perm[4]; -}; - - - -IMPORT int __stdcall GetServerListEx(char *host, char *str_port, struct SERVERLIST serverlist[], short max_servers); -IMPORT int __stdcall GetServerList(char *host, char *str_port, - struct SERVERLIST *serverlist1,struct SERVERLIST *serverlist2,struct SERVERLIST *serverlist3, - struct SERVERLIST *serverlist4,struct SERVERLIST *serverlist5,struct SERVERLIST *serverlist6, - struct SERVERLIST *serverlist7,struct SERVERLIST *serverlist8,struct SERVERLIST *serverlist9, - struct SERVERLIST *serverlist10,struct SERVERLIST *serverlist11,struct SERVERLIST *serverlist12, - struct SERVERLIST *serverlist13,struct SERVERLIST *serverlist14,struct SERVERLIST *serverlist15, - struct SERVERLIST *serverlist16); - - - - -#endif // !defined(_MSERVSDK_H_) diff --git a/tools/SRB2Launcher/resource.h b/tools/SRB2Launcher/resource.h deleted file mode 100644 index d787fef41..000000000 --- a/tools/SRB2Launcher/resource.h +++ /dev/null @@ -1,71 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by Script1.rc -// -#define IDD_MAIN 101 -#define IDB_BITMAP1 102 -#define IDI_ICON1 103 -#define IDD_JOINGAME 104 -#define IDD_HOSTGAME 106 -#define IDD_MATCHOPTIONS 108 -#define IDD_RACEOPTIONS 109 -#define IDD_CTFOPTIONS 110 -#define IDD_TAGOPTIONS 111 -#define IDC_GO 1001 -#define IDC_LAUNCHCONFIG 1002 -#define IDC_EXTFILECOMBO 1003 -#define IDC_ABOUT 1005 -#define IDC_ADDFILE 1006 -#define IDC_REMOVEFILE 1007 -#define IDC_SAVELAUNCHCFG 1008 -#define IDC_JOINGAME 1010 -#define IDC_HOSTGAME 1011 -#define IDC_SOUNDOPTS 1012 -#define IDC_PARAMETERS 1013 -#define IDC_EXENAME 1014 -#define IDC_FINDEXENAME 1015 -#define IDC_SEARCHGAMES 1016 -#define IDC_GAMELIST 1018 -#define IDC_NAME 1020 -#define IDC_COLOR 1021 -#define IDC_SKIN 1022 -#define IDC_ADDRESS 1023 -#define IDC_NOFILE 1024 -#define IDC_JOINSTART 1026 -#define IDC_NODOWNLOAD 1027 -#define IDC_OPTIONS 1028 -#define IDC_GAMETYPE 1029 -#define IDC_MAXPLAYERS 1030 -#define IDC_STARTMAP 1031 -#define IDC_FORCESKIN 1032 -#define IDC_ADVANCEMAP 1033 -#define IDC_INTERNETSERVER 1034 -#define IDC_SPECIALRINGS 1036 -#define IDC_MATCHBOXES 1037 -#define IDC_OK 1038 -#define IDC_CANCEL 1039 -#define IDC_RESPAWNITEMTIME 1040 -#define IDC_TIMELIMIT 1041 -#define IDC_POINTLIMIT 1042 -#define IDC_FLAGTIME 1048 -#define IDC_RACEITEMBOXES 1051 -#define IDC_NUMLAPS 1052 -#define IDC_SUDDENDEATH 1060 -#define IDC_MATCH_SCORING 1061 -#define IDC_INTTIME 1064 -#define IDC_DISABLEAUTOAIM 1065 -#define IDC_MONITORTOGGLES 1067 -#define IDC_CONFIGFILE 1069 -#define IDC_FINDCONFIGNAME 1070 -#define IDC_LIST1 1071 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 117 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1072 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/tools/SRB2MP/Makefile b/tools/SRB2MP/Makefile deleted file mode 100644 index 92e112d7a..000000000 --- a/tools/SRB2MP/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# Makfile of SRB2MP - -CFLAGS +=-Wall -mms-bitfields -fno-exceptions -LDFLAGS +=-mwindows -lfmod -WINDRESFLAGS= - -SRC=lump.c SRB2MP.c - -ifdef DEBUGMODE -CFLAGS +=-g -D_DEBUG -LDFLAGS +=-g -else -CFLAGS :=-Os -s $(CFLAGS) -LDFLAGS :=-s $(LDFLAGS) -endif - -OBJ=$(SRC:.c=.o) # replaces the .c from SRC with .o -EXTRAOBJ=Script1.res -EXE=SRB2MP.exe - -ifdef PREFIX -CC=$(PREFIX)-gcc -WINDRES ?=$(PREFIX)-windres -endif - -WINDRES ?=windres - -RM=rm - -%.o: %.c StdAfx.h lump.h resource.h - $(CC) $(CFLAGS) -o $@ -c $< - -%.res: %.rc resource.h - $(WINDRES) -i $< -O rc $(WINDRESFLAGS) -o $@ -O coff - -.PHONY : all # .PHONY ignores files named all -all: $(EXE) # all is dependent on $(EXE) to be complete - -$(EXE): $(OBJ) $(EXTRAOBJ) # $(EXE) is dependent on all of the files in $(OBJ) to exist - $(CC) $(OBJ) $(EXTRAOBJ) $(LDFLAGS) -o $@ - -.PHONY : clean # .PHONY ignores files named clean -clean: - -$(RM) $(OBJ) $(EXTRAOBJ) diff --git a/tools/SRB2MP/SRB2MP.c b/tools/SRB2MP/SRB2MP.c deleted file mode 100644 index 69cc21040..000000000 --- a/tools/SRB2MP/SRB2MP.c +++ /dev/null @@ -1,464 +0,0 @@ -// SRB2MP.cpp : Defines the entry point for the application. -// - -#include "StdAfx.h" -#include "lump.h" - -#define APPTITLE "SRB2 Music Player" -#define APPVERSION "v0.1" -#define APPAUTHOR "SSNTails" -#define APPCOMPANY "Sonic Team Junior" - -static FSOUND_STREAM *fmus = NULL; -static int fsoundchannel = -1; -static FMUSIC_MODULE *mod = NULL; -static struct wadfile* wfptr = NULL; - -static inline VOID M_SetVolume(int volume) -{ - if (mod && FMUSIC_GetType(mod) != FMUSIC_TYPE_NONE) - FMUSIC_SetMasterVolume(mod, volume); - if (fsoundchannel != -1) - FSOUND_SetVolume(fsoundchannel, volume); -} - -static inline BOOL M_InitMusic(VOID) -{ - if (FSOUND_GetVersion() < FMOD_VERSION) - { - printf("Error : You are using the wrong DLL version!\nYou should be using FMOD %.02f\n", FMOD_VERSION); - return FALSE; - } - -#ifdef _DEBUG - FSOUND_SetOutput(FSOUND_OUTPUT_WINMM); -#endif - - if (!FSOUND_Init(44100, 1, FSOUND_INIT_GLOBALFOCUS)) - { - printf("%s\n", FMOD_ErrorString(FSOUND_GetError())); - return FALSE; - } - return TRUE; -} - -static inline VOID M_FreeMusic(VOID) -{ - if (mod) - { - FMUSIC_StopSong(mod); - FMUSIC_FreeSong(mod); - mod = NULL; - } - if (fmus) - { - FSOUND_Stream_Stop(fmus); - FSOUND_Stream_Close(fmus); - fmus = NULL; - fsoundchannel = -1; - } -} - -static inline VOID M_ShutdownMusic(VOID) -{ - M_FreeMusic(); - FSOUND_Close(); - //remove(musicfile); // Delete the temp file -} - -static inline VOID M_PauseMusic(VOID) -{ - if (mod && !FMUSIC_GetPaused(mod)) - FMUSIC_SetPaused(mod, TRUE); - if (fsoundchannel != -1 && FSOUND_IsPlaying(fsoundchannel)) - FSOUND_SetPaused(fsoundchannel, TRUE); -} - -static inline VOID M_ResumeMusic(VOID) -{ - if (mod && FMUSIC_GetPaused(mod)) - FMUSIC_SetPaused(mod, FALSE); - if (fsoundchannel != -1 && FSOUND_GetPaused(fsoundchannel)) - FSOUND_SetPaused(fsoundchannel, FALSE); -} - -static inline VOID M_StopMusic(VOID) -{ - if (mod) - FMUSIC_StopSong(mod); - if (fsoundchannel != -1 && fmus && FSOUND_IsPlaying(fsoundchannel)) - FSOUND_Stream_Stop(fmus); -} - -static inline VOID M_StartFMODSong(LPVOID data, int len, int looping, HWND hDlg) -{ - const int loops = FSOUND_LOOP_NORMAL|FSOUND_LOADMEMORY; - const int nloop = FSOUND_LOADMEMORY; - M_FreeMusic(); - - if (looping) - mod = FMUSIC_LoadSongEx(data, 0, len, loops, NULL, 0); - else - mod = FMUSIC_LoadSongEx(data, 0, len, nloop, NULL, 0); - - if (mod) - { - FMUSIC_SetLooping(mod, (signed char)looping); - FMUSIC_SetPanSeperation(mod, 0.0f); - } - else - { - if (looping) - fmus = FSOUND_Stream_Open(data, loops, 0, len); - else - fmus = FSOUND_Stream_Open(data, nloop, 0, len); - } - - if (!fmus && !mod) - { - MessageBoxA(hDlg, FMOD_ErrorString(FSOUND_GetError()), "Error", MB_OK|MB_APPLMODAL); - return; - } - - // Scan the OGG for the COMMENT= field for a custom loop point - if (looping && fmus) - { - const BYTE *origpos, *dataum = data; - size_t scan, size = len; - - CHAR buffer[512]; - BOOL titlefound = FALSE, artistfound = FALSE; - - unsigned int loopstart = 0; - - origpos = dataum; - - for(scan = 0; scan < size; scan++) - { - if (!titlefound) - { - if (*dataum++ == 'T') - if (*dataum++ == 'I') - if (*dataum++ == 'T') - if (*dataum++ == 'L') - if (*dataum++ == 'E') - if (*dataum++ == '=') - { - size_t titlecount = 0; - CHAR title[256]; - BYTE length = *(dataum-10) - 6; - - while(titlecount < length) - title[titlecount++] = *dataum++; - - title[titlecount] = '\0'; - - sprintf(buffer, "Title: %s", title); - - SendMessage(GetDlgItem(hDlg, IDC_TITLE), WM_SETTEXT, 0, (LPARAM)(LPCSTR)buffer); - - titlefound = TRUE; - } - } - } - - dataum = origpos; - - for(scan = 0; scan < size; scan++) - { - if (!artistfound) - { - if (*dataum++ == 'A') - if (*dataum++ == 'R') - if (*dataum++ == 'T') - if (*dataum++ == 'I') - if (*dataum++ == 'S') - if (*dataum++ == 'T') - if (*dataum++ == '=') - { - size_t artistcount = 0; - CHAR artist[256]; - BYTE length = *(dataum-11) - 7; - - while(artistcount < length) - artist[artistcount++] = *dataum++; - - artist[artistcount] = '\0'; - - sprintf(buffer, "By: %s", artist); - - SendMessage(GetDlgItem(hDlg, IDC_ARTIST), WM_SETTEXT, 0, (LPARAM)(LPCSTR)buffer); - - artistfound = TRUE; - } - } - } - - dataum = origpos; - - for(scan = 0; scan < size; scan++) - { - if (*dataum++ == 'C'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'M'){ - if (*dataum++ == 'M'){ - if (*dataum++ == 'E'){ - if (*dataum++ == 'N'){ - if (*dataum++ == 'T'){ - if (*dataum++ == '='){ - if (*dataum++ == 'L'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'P'){ - if (*dataum++ == 'P'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'I'){ - if (*dataum++ == 'N'){ - if (*dataum++ == 'T'){ - if (*dataum++ == '=') - { - size_t newcount = 0; - CHAR looplength[64]; - while (*dataum != 1 && newcount < 63) - { - looplength[newcount++] = *dataum++; - } - - looplength[newcount] = '\n'; - - loopstart = atoi(looplength); - } - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - } - - if (loopstart > 0) - { - const int length = FSOUND_Stream_GetLengthMs(fmus); - const int freq = 44100; - const unsigned int loopend = (unsigned int)((freq/1000.0f)*length-(freq/1000.0f)); - if (!FSOUND_Stream_SetLoopPoints(fmus, loopstart, loopend)) - { - printf("FMOD(Start,FSOUND_Stream_SetLoopPoints): %s\n", - FMOD_ErrorString(FSOUND_GetError())); - } - } - } - - if (mod) - FMUSIC_PlaySong(mod); - if (fmus) - fsoundchannel = FSOUND_Stream_PlayEx(FSOUND_FREE, fmus, NULL, FALSE); - - M_SetVolume(128); -} - -static inline VOID FreeWADLumps(VOID) -{ - M_FreeMusic(); - if (wfptr) free_wadfile(wfptr); - wfptr = NULL; -} - -static inline VOID ReadWADLumps(LPCSTR WADfilename, HWND hDlg) -{ - HWND listbox = GetDlgItem(hDlg, IDC_PLAYLIST); - FILE* f; - struct lumplist *curlump; - - SendMessage(listbox, LB_RESETCONTENT, 0, 0); - FreeWADLumps(); - f = fopen(WADfilename, "rb"); - wfptr = read_wadfile(f); - fclose(f); - - /* start of C_LIST */ - /* Loop through the lump list, printing lump info */ - for(curlump = wfptr->head->next; curlump; curlump = curlump->next) - { - LPCSTR lumpname = get_lump_name(curlump->cl); - if (!strncmp(lumpname, "O_", 2) || !strncmp(lumpname, "D_", 2)) - SendMessage(listbox, LB_ADDSTRING, 0, (LPARAM)(LPCSTR)get_lump_name(curlump->cl)); - } - /* end of C_LIST */ -} - -// -// OpenWadfile -// -// Provides a common dialog box -// for selecting the desired wad file. -// -static inline VOID OpenWadfile(HWND hDlg) -{ - OPENFILENAMEA ofn; - CHAR FileBuffer[256] = ""; - - ZeroMemory(&ofn, sizeof(ofn)); - ofn.hwndOwner = hDlg; - ofn.lpstrFilter = "WAD Files\0*.wad\0All Files\0*.*\0\0"; - ofn.lpstrInitialDir = NULL; - ofn.lpstrFile = FileBuffer; - ofn.lStructSize = sizeof(ofn); - ofn.nMaxFile = sizeof(FileBuffer); - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - - if (GetOpenFileNameA(&ofn)) - ReadWADLumps(FileBuffer, hDlg); -} - -static inline VOID PlayLump(HWND hDlg) -{ - HWND listbox = GetDlgItem(hDlg, IDC_PLAYLIST); - LRESULT cursel = SendMessage(listbox, LB_GETCURSEL, 0, 0); - - /* Start of C_EXTRACT */ - CHAR argv[9]; - - SendMessage(listbox, LB_GETTEXT, cursel, (LPARAM)(LPCSTR)argv); - - /* Extract LUMPNAME FILENAME pairs */ - if (wfptr) - { - struct lumplist *extracted; - - printf("Extracting lump %s...\n", argv); - /* Find the lump to extract */ - extracted = find_previous_lump(wfptr->head, NULL, argv); - if (extracted == NULL || (extracted = extracted->next) == NULL) - return; - - /* Extract lump */ - M_StartFMODSong(extracted->cl->data, extracted->cl->len, FALSE, hDlg); - - /* end of extracting LUMPNAME FILENAME pairs */ - - } /* end of C_EXTRACT */ - return; -} - -static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - return DefWindowProc(hWnd, message, wParam, lParam); -} - -static INT_PTR CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch(message) - { - case WM_INITDIALOG: - M_InitMusic(); - break; - - case WM_CLOSE: - EndDialog(hDlg, message); - break; - - case WM_DESTROY: - FreeWADLumps(); - M_ShutdownMusic(); - break; - - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case 2: - EndDialog(hDlg, message); - return TRUE; - case IDC_ABOUT: // The About button. - { - char TempString[256]; - sprintf(TempString, "%s %s by %s - %s", APPTITLE, APPVERSION, APPAUTHOR, APPCOMPANY); - MessageBoxA(hDlg, TempString, "About", MB_OK|MB_APPLMODAL); - } - return TRUE; - case IDC_OPEN: - OpenWadfile(hDlg); - return TRUE; - case IDC_PLAY: - PlayLump(hDlg); - return TRUE; - default: - break; - } - break; - } - } - - return FALSE; -} - -static inline VOID RegisterDialogClass(LPCSTR name, WNDPROC callback, HINSTANCE hInst) -{ - WNDCLASSA wnd; - - wnd.style = CS_HREDRAW | CS_VREDRAW; - wnd.cbWndExtra = DLGWINDOWEXTRA; - wnd.cbClsExtra = 0; - wnd.hCursor = LoadCursorA(NULL,(LPCSTR)MAKEINTRESOURCE(IDC_ARROW)); - wnd.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_ICON1)); - wnd.hInstance = hInst; - wnd.lpfnWndProc = callback; - wnd.lpszClassName = name; - wnd.lpszMenuName = NULL; - wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW); - - if (!RegisterClassA(&wnd)) - { - return; - } -} - -int APIENTRY WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - // Prevent multiples instances of this app. - CreateMutexA(NULL, TRUE, APPTITLE); - - if (GetLastError() == ERROR_ALREADY_EXISTS) - return 0; - - RegisterDialogClass("SRB2MP", MainWndproc, hInstance); - - DialogBoxA(hInstance, (LPCSTR)IDD_MAIN, NULL, DialogProc); - - return 0; -} diff --git a/tools/SRB2MP/SRB2MP.dsp b/tools/SRB2MP/SRB2MP.dsp deleted file mode 100644 index f2e700fb5..000000000 --- a/tools/SRB2MP/SRB2MP.dsp +++ /dev/null @@ -1,148 +0,0 @@ -# Microsoft Developer Studio Project File - Name="SRB2MP" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Application" 0x0101 - -CFG=SRB2MP - Win32 Debug -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "SRB2MP.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "SRB2MP.mak" CFG="SRB2MP - Win32 Debug" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "SRB2MP - Win32 Release" (based on "Win32 (x86) Application") -!MESSAGE "SRB2MP - Win32 Debug" (based on "Win32 (x86) Application") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName "" -# PROP Scc_LocalPath "" -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "SRB2MP - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Release" -# PROP BASE Intermediate_Dir "Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib fmodvc.lib /nologo /subsystem:windows /machine:I386 - -!ELSEIF "$(CFG)" == "SRB2MP - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" -# PROP Intermediate_Dir "Debug" -# PROP Ignore_Export_Lib 0 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c -# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib fmodvc.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept - -!ENDIF - -# Begin Target - -# Name "SRB2MP - Win32 Release" -# Name "SRB2MP - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# Begin Source File - -SOURCE=.\lump.c -# End Source File -# Begin Source File - -SOURCE=.\SRB2MP.c -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.c -# ADD CPP /Yc"stdafx.h" -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=.\lump.h -# End Source File -# Begin Source File - -SOURCE=.\resource.h -# End Source File -# Begin Source File - -SOURCE=.\StdAfx.h -# End Source File -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# Begin Source File - -SOURCE=.\icon1.ico -# End Source File -# Begin Source File - -SOURCE=.\icon2.ico -# End Source File -# Begin Source File - -SOURCE=.\icon3.ico -# End Source File -# Begin Source File - -SOURCE=.\Script1.rc -# End Source File -# End Group -# Begin Source File - -SOURCE=.\ReadMe.txt -# End Source File -# End Target -# End Project diff --git a/tools/SRB2MP/SRB2MP.dsw b/tools/SRB2MP/SRB2MP.dsw deleted file mode 100644 index b73bd1ac7..000000000 --- a/tools/SRB2MP/SRB2MP.dsw +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Developer Studio Workspace File, Format Version 6.00 -# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! - -############################################################################### - -Project: "SRB2MP"=.\SRB2MP.dsp - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Global: - -Package=<5> -{{{ -}}} - -Package=<3> -{{{ -}}} - -############################################################################### - diff --git a/tools/SRB2MP/Script1.aps b/tools/SRB2MP/Script1.aps deleted file mode 100644 index 994653cb1..000000000 Binary files a/tools/SRB2MP/Script1.aps and /dev/null differ diff --git a/tools/SRB2MP/Script1.rc b/tools/SRB2MP/Script1.rc deleted file mode 100644 index 3fa7bd572..000000000 --- a/tools/SRB2MP/Script1.rc +++ /dev/null @@ -1,118 +0,0 @@ -//Microsoft Developer Studio generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_MAIN DIALOG DISCARDABLE 0, 0, 262, 170 -STYLE DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | - WS_SYSMENU -CAPTION "SRB2 Music Player" -FONT 8, "MS Sans Serif" -BEGIN - PUSHBUTTON "E&xit",IDCANCEL,205,145,50,19 - PUSHBUTTON "&About",IDC_ABOUT,230,15,23,10 - LISTBOX IDC_WADLIST,5,30,112,110,LBS_SORT | LBS_NOINTEGRALHEIGHT | - WS_VSCROLL | WS_TABSTOP - LISTBOX IDC_PLAYLIST,140,30,114,110,LBS_SORT | - LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Play",IDC_PLAY,140,145,60,20 - PUSHBUTTON "->",IDC_ADD,120,35,15,15 - PUSHBUTTON "<-",IDC_REMOVE,120,55,15,15 - PUSHBUTTON "&Open WAD...",IDC_OPEN,5,10,50,15 - ICON IDI_ICON1,IDC_STATIC,205,5,20,20 - LTEXT "Title:",IDC_TITLE,5,140,125,10 - LTEXT "By:",IDC_ARTIST,5,150,125,15 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO DISCARDABLE -BEGIN - IDD_MAIN, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 255 - TOPMARGIN, 7 - BOTTOMMARGIN, 163 - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE DISCARDABLE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE DISCARDABLE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE DISCARDABLE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ICON1 ICON DISCARDABLE "icon1.ico" -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/tools/SRB2MP/StdAfx.c b/tools/SRB2MP/StdAfx.c deleted file mode 100644 index 4f305cd1a..000000000 --- a/tools/SRB2MP/StdAfx.c +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// SRB2MP.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "StdAfx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/tools/SRB2MP/StdAfx.h b/tools/SRB2MP/StdAfx.h deleted file mode 100644 index 84ac428b8..000000000 --- a/tools/SRB2MP/StdAfx.h +++ /dev/null @@ -1,35 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) -#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ - -//#define UNICODE - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include -#include -#include -#include - -// TODO: reference additional headers your program requires here -#ifdef __MINGW32__ -#include -#include -#else -#include -#include -#endif -#include "resource.h" - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) diff --git a/tools/SRB2MP/icon1.ico b/tools/SRB2MP/icon1.ico deleted file mode 100644 index 7548e7caf..000000000 Binary files a/tools/SRB2MP/icon1.ico and /dev/null differ diff --git a/tools/SRB2MP/lump.c b/tools/SRB2MP/lump.c deleted file mode 100644 index 4cf355401..000000000 --- a/tools/SRB2MP/lump.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - LumpMod v0.21, a command-line utility for working with lumps in wad files. - Copyright (C) 2003 Thunder Palace Entertainment. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - lump.c: Provides functions for dealing with lumps -*/ - -#include "StdAfx.h" -#include -#include -#include "lump.h" - -/* Read contents of a wad file and store them in memory. - * fpoint is the file to read, opened with "rb" mode. - * A pointer to a new wadfile struct will be returned, or NULL on error. - */ -struct wadfile *read_wadfile(FILE *fpoint) { - struct wadfile *wfptr; - struct lumplist *curlump; - unsigned long diroffset, filelen; - unsigned long count; - - /* Allocate memory for wadfile struct */ - wfptr = (struct wadfile*)malloc(sizeof(struct wadfile)); - if(wfptr == NULL) return NULL; - - /* Read first four characters (PWAD or IWAD) */ - if(fread(wfptr->id, 4, 1, fpoint) < 1) { - free(wfptr); - return NULL; - } - - /* Read number of lumps */ - if(fread(&(wfptr->numlumps), 4, 1, fpoint) < 1) { - free(wfptr); - return NULL; - } - - /* If number of lumps is zero, nothing more needs to be done */ - if(wfptr->numlumps == 0) { - wfptr->head = NULL; - return wfptr; - } - - /* Read offset of directory */ - if(fread(&diroffset, 4, 1, fpoint) < 1) { - free(wfptr); - return NULL; - } - - /* Verify that the directory as long as it needs to be */ - fseek(fpoint, 0, SEEK_END); - filelen = ftell(fpoint); - if((filelen - diroffset) / DIRENTRYLEN < wfptr->numlumps) { - free(wfptr); - return NULL; - } - - /* Allocate memory for head lumplist item and set head pointer */ - curlump = (struct lumplist*)malloc(sizeof(struct lumplist)); - if(curlump == NULL) { - free(wfptr); - return NULL; - } - wfptr->head = curlump; - curlump->cl = NULL; - - /* Read directory entries and lumps */ - for(count = 0; count < wfptr->numlumps; count++) { - long lumpdataoffset; - - /* Advance to a new list item */ - curlump->next = (struct lumplist*)malloc(sizeof(struct lumplist)); - if(curlump->next == NULL) { - free_wadfile(wfptr); - return NULL; - } - curlump = curlump->next; - curlump->next = NULL; - - /* Allocate memory for the lump info */ - curlump->cl = (struct lump*)malloc(sizeof(struct lump)); - if(curlump->cl == NULL) { - free_wadfile(wfptr); - return NULL; - } - - /* Seek to the proper position in the file */ - if(fseek(fpoint, diroffset + (count * DIRENTRYLEN), SEEK_SET) != 0) { - free_wadfile(wfptr); - return NULL; - } - - /* Read offset of lump data */ - if(fread(&lumpdataoffset, 4, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - - /* Read size of lump in bytes */ - if(fread(&(curlump->cl->len), 4, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - - /* Read lump name */ - if(fread(curlump->cl->name, 8, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - - /* Read actual lump data, unless lump size is 0 */ - if(curlump->cl->len > 0) { - if(fseek(fpoint, lumpdataoffset, SEEK_SET) != 0) { - free_wadfile(wfptr); - return NULL; - } - - /* Allocate memory for data */ - curlump->cl->data = (unsigned char*)malloc(curlump->cl->len); - if(curlump->cl->data == NULL) { - free_wadfile(wfptr); - return NULL; - } - - /* Fill the data buffer */ - if(fread(curlump->cl->data, curlump->cl->len, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - } else curlump->cl->data = NULL; - } /* End of directory reading loop */ - - return wfptr; -} - -/* Free a wadfile from memory as well as all related structures. - */ -void free_wadfile(struct wadfile *wfptr) { - struct lumplist *curlump, *nextlump; - - if(wfptr == NULL) return; - curlump = wfptr->head; - - /* Free items in the lump list */ - while(curlump != NULL) { - - /* Free the actual lump and its data, if necessary */ - if(curlump->cl != NULL) { - if(curlump->cl->data != NULL) free(curlump->cl->data); - free(curlump->cl); - } - - /* Advance to next lump and free this one */ - nextlump = curlump->next; - free(curlump); - curlump = nextlump; - } - - free(wfptr); -} - -/* Write complete wadfile to a file stream, opened with "wb" mode. - * fpoint is the stream to write to. - * wfptr is a pointer to the wadfile structure to use. - * Return zero on success, nonzero on failure. - */ -int write_wadfile(FILE *fpoint, struct wadfile *wfptr) { - struct lumplist *curlump; - long lumpdataoffset, diroffset; - - if(wfptr == NULL) return 1; - - /* Write four-character ID ("PWAD" or "IWAD") */ - if(fwrite(wfptr->id, 4, 1, fpoint) < 1) return 2; - - /* Write number of lumps */ - if(fwrite(&(wfptr->numlumps), 4, 1, fpoint) < 1) return 3; - - /* Offset of directory is not known yet. For now, write number of lumps - * again, just to fill the space. - */ - if(fwrite(&(wfptr->numlumps), 4, 1, fpoint) < 1) return 4; - - /* Loop through lump list, writing lump data */ - for(curlump = wfptr->head; curlump != NULL; curlump = curlump->next) { - - /* Don't write anything for the head of the lump list or for lumps of - zero length */ - if(curlump->cl == NULL || curlump->cl->data == NULL) continue; - - /* Write the data */ - if(fwrite(curlump->cl->data, curlump->cl->len, 1, fpoint) < 1) - return 5; - } - - /* Current position is where directory will start */ - diroffset = ftell(fpoint); - - /* Offset for the first lump's data is always 12 */ - lumpdataoffset = 12; - - /* Loop through lump list again, this time writing directory entries */ - for(curlump = wfptr->head; curlump != NULL; curlump = curlump->next) { - - /* Don't write anything for the head of the lump list */ - if(curlump->cl == NULL) continue; - - /* Write offset for lump data */ - if(fwrite(&lumpdataoffset, 4, 1, fpoint) < 1) return 6; - - /* Write size of lump data */ - if(fwrite(&(curlump->cl->len), 4, 1, fpoint) < 1) return 7; - - /* Write lump name */ - if(fwrite(curlump->cl->name, 8, 1, fpoint) < 1) return 8; - - /* Increment lumpdataoffset variable as appropriate */ - lumpdataoffset += curlump->cl->len; - } - - /* Go back to header and write the proper directory offset */ - fseek(fpoint, 8, SEEK_SET); - if(fwrite(&diroffset, 4, 1, fpoint) < 1) return 9; - - return 0; -} - -/* Get the name of a lump, as a null-terminated string. - * item is a pointer to the lump (not lumplist) whose name will be obtained. - * Return NULL on error. - */ -char *get_lump_name(struct lump *item) { - char convname[9], *retname; - - if(item == NULL) return NULL; - memcpy(convname, item->name, 8); - convname[8] = '\0'; - - retname = (char*)malloc(strlen(convname) + 1); - if(retname != NULL) strcpy(retname, convname); - return retname; -} - -/* Find the lump after start and before end having a certain name. - * Return a pointer to the list item for that lump, or return NULL if no lump - * by that name is found or lumpname is too long. - * lumpname is a null-terminated string. - * If end parameter is NULL, search to the end of the entire list. - */ -struct lumplist *find_previous_lump(struct lumplist *start, struct lumplist - *end, char *lumpname) { - struct lumplist *curlump, *lastlump; - char *curname; - int found = 0; - - /* Verify that parameters are valid */ - if(start==NULL || start==end || lumpname==NULL || strlen(lumpname) > 8) - return NULL; - - /* Loop through the list from start parameter */ - lastlump = start; - for(curlump = start->next; curlump != end && curlump != NULL; - curlump = curlump->next) { - - /* Skip header lump */ - if(curlump->cl == NULL) continue; - - /* Find name of this lump */ - curname = get_lump_name(curlump->cl); - if(curname == NULL) continue; - - /* Compare names to see if this is the lump we want */ - if(strcmp(curname, lumpname) == 0) { - found = 1; - break; - } - - /* Free memory allocated to curname */ - free(curname); - - lastlump = curlump; - } - - if(found) return lastlump; - return NULL; -} - -/* Remove a lump from the list, free it, and free its data. - * before is the lump immediately preceding the lump to be removed. - * wfptr is a pointer to the wadfile structure to which the removed lump - * belongs, so that numlumps can be decreased. - */ -void remove_next_lump(struct wadfile *wfptr, struct lumplist *before) { - struct lumplist *removed; - - /* Verify that parameters are valid */ - if(before == NULL || before->next == NULL || wfptr == NULL) return; - - /* Update linked list to omit removed lump */ - removed = before->next; - before->next = removed->next; - - /* Free lump info and data if necessary */ - if(removed->cl != NULL) { - if(removed->cl->data != NULL) free(removed->cl->data); - free(removed->cl); - } - - free(removed); - - /* Decrement numlumps */ - wfptr->numlumps--; -} - -/* Add a lump. - * The lump will follow prev in the list and be named name, with a data size - * of len. - * A copy will be made of the data. - * Return zero on success or nonzero on failure. - */ -int add_lump(struct wadfile *wfptr, struct lumplist *prev, char *name, long - len, unsigned char *data) { - struct lump *newlump; - struct lumplist *newlumplist; - unsigned char *copydata; - - /* Verify that parameters are valid */ - if(wfptr == NULL || prev == NULL || name == NULL || strlen(name) > 8) - return 1; - - /* Allocate space for newlump and newlumplist */ - newlump = (struct lump*)malloc(sizeof(struct lump)); - newlumplist = (struct lumplist*)malloc(sizeof(struct lumplist)); - if(newlump == NULL || newlumplist == NULL) return 2; - - /* Copy lump data and set up newlump */ - if(len == 0 || data == NULL) { - newlump->len = 0; - newlump->data = NULL; - } else { - newlump->len = len; - copydata = (unsigned char*)malloc(len); - if(copydata == NULL) return 3; - memcpy(copydata, data, len); - newlump->data = copydata; - } - - /* Set name of newlump */ - memset(newlump->name, '\0', 8); - if(strlen(name) == 8) memcpy(newlump->name, name, 8); - else strcpy(newlump->name, name); - - /* Set up newlumplist and alter prev appropriately */ - newlumplist->cl = newlump; - newlumplist->next = prev->next; - prev->next = newlumplist; - - /* Increment numlumps */ - wfptr->numlumps++; - - return 0; -} - -/* Rename a lump. - * renamed is a pointer to the lump (not lumplist) that needs renaming. - * newname is a null-terminated string with the new name. - * Return zero on success or nonzero on failure. - */ -int rename_lump(struct lump *renamed, char *newname) { - - /* Verify that parameters are valid. */ - if(newname == NULL || renamed == NULL || strlen(newname) > 8) return 1; - - /* Do the renaming. */ - memset(renamed->name, '\0', 8); - if(strlen(newname) == 8) memcpy(renamed->name, newname, 8); - else strcpy(renamed->name, newname); - - return 0; -} - -/* Find the last lump in a wadfile structure. - * Return this lump or NULL on failure. - */ -struct lumplist *find_last_lump(struct wadfile *wfptr) { - struct lumplist *curlump; - - if(wfptr == NULL || wfptr->head == NULL) return NULL; - curlump = wfptr->head; - - while(curlump->next != NULL) curlump = curlump->next; - return curlump; -} - -/* Find the last lump between start and end. - * Return this lump or NULL on failure. - */ -struct lumplist *find_last_lump_between(struct lumplist *start, struct - lumplist *end) { - struct lumplist *curlump; - - if(start == NULL) return NULL; - curlump = start; - - while(curlump->next != end) { - curlump = curlump->next; - if(curlump == NULL) break; - } - - return curlump; -} - -/* Find the next section lump. A section lump is MAPxx (0 <= x <= 9), ExMy - * (0 <= x <= 9, 0 <= y <= 9), or any lump whose name ends in _START or _END. - * Return NULL if there are no section lumps after start. - */ -struct lumplist *find_next_section_lump(struct lumplist *start) { - struct lumplist *curlump, *found = NULL; - char *curname; - - /* Verify that parameter is valid */ - if(start == NULL || start->next == NULL) return NULL; - - /* Loop through the list from start parameter */ - for(curlump = start->next; curlump != NULL && found == NULL; - curlump = curlump->next) { - - /* Skip header lump */ - if(curlump->cl == NULL) continue; - - /* Find name of this lump */ - curname = get_lump_name(curlump->cl); - if(curname == NULL) continue; - - /* Check to see if this is a section lump */ - if(strlen(curname) == 5 && strncmp("MAP", curname, 3) == 0 && - isdigit(curname[3]) && isdigit(curname[4])) - found = curlump; - else if(strlen(curname) == 4 && curname[0] == 'E' && curname[2] == - 'M' && isdigit(curname[1]) && isdigit(curname[3])) - found = curlump; - else if(strlen(curname) == 7 && strcmp("_START", &curname[1]) == 0) - found = curlump; - else if(strlen(curname) == 8 && strcmp("_START", &curname[2]) == 0) - found = curlump; - else if(strlen(curname) == 5 && strcmp("_END", &curname[1]) == 0) - found = curlump; - else if(strlen(curname) == 6 && strcmp("_END", &curname[2]) == 0) - found = curlump; - - /* Free memory allocated to curname */ - free(curname); - } - - return found; -} diff --git a/tools/SRB2MP/lump.h b/tools/SRB2MP/lump.h deleted file mode 100644 index b36b84441..000000000 --- a/tools/SRB2MP/lump.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - LumpMod v0.21, a command-line utility for working with lumps in wad files. - Copyright (C) 2003 Thunder Palace Entertainment. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - lump.h: Defines constants, structures, and functions used in lump.c -*/ - -#ifndef __LUMP_H -#define __LUMP_H - -/* Entries in the wadfile directory are 16 bytes */ -#define DIRENTRYLEN 16 - -/* Lumps and associated info */ -struct lump { - long len; - unsigned char *data; - char name[8]; -}; - -/* Linked list of lumps */ -struct lumplist { - struct lump *cl; /* actual content of the lump */ - struct lumplist *next; -}; - -/* Structure to contain all wadfile data */ -struct wadfile { - char id[4]; /* IWAD or PWAD */ - unsigned long numlumps; /* 32-bit integer */ - struct lumplist *head; /* points to first entry */ -}; - -/* Function declarations */ -struct wadfile *read_wadfile(FILE *); -void free_wadfile(struct wadfile *); -int write_wadfile(FILE *, struct wadfile *); -char *get_lump_name(struct lump *); -struct lumplist *find_previous_lump(struct lumplist *, struct lumplist *, char *); -void remove_next_lump(struct wadfile *, struct lumplist *); -int add_lump(struct wadfile *, struct lumplist *, char *, long, unsigned char *); -int rename_lump(struct lump *, char *); -struct lumplist *find_last_lump(struct wadfile *); -struct lumplist *find_last_lump_between(struct lumplist *, struct lumplist *); -struct lumplist *find_next_section_lump(struct lumplist *); - -#endif diff --git a/tools/SRB2MP/resource.h b/tools/SRB2MP/resource.h deleted file mode 100644 index 56924e34a..000000000 --- a/tools/SRB2MP/resource.h +++ /dev/null @@ -1,26 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by Script1.rc -// -#define IDD_MAIN 101 -#define IDI_ICON1 102 -#define IDC_ABOUT 1000 -#define IDC_WADLIST 1001 -#define IDC_PLAYLIST 1002 -#define IDC_PLAY 1003 -#define IDC_ADD 1004 -#define IDC_REMOVE 1005 -#define IDC_OPEN 1006 -#define IDC_TITLE 1007 -#define IDC_ARTIST 1008 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1009 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/tools/SRB2Updater/Bunny.cs b/tools/SRB2Updater/Bunny.cs deleted file mode 100644 index 71934ee31..000000000 --- a/tools/SRB2Updater/Bunny.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -namespace SRB2Updater -{ - public class Bunny - { - List Keys = new List{System.Windows.Forms.Keys.Up, System.Windows.Forms.Keys.Up, - System.Windows.Forms.Keys.Down, System.Windows.Forms.Keys.Down, - System.Windows.Forms.Keys.Left, System.Windows.Forms.Keys.Right, - System.Windows.Forms.Keys.Left, System.Windows.Forms.Keys.Right, - System.Windows.Forms.Keys.B, System.Windows.Forms.Keys.A}; - private int mPosition = -1; - - public int Position - { - get { return mPosition; } - private set { mPosition = value; } - } - - public bool IsCompletedBy(Keys key) - { - - if (Keys[Position + 1] == key) - { - // move to next - Position++; - } - else if (Position == 1 && key == System.Windows.Forms.Keys.Up) - { - // stay where we are - } - else if (Keys[0] == key) - { - // restart at 1st - Position = 0; - } - else - { - // no match in sequence - Position = -1; - } - - if (Position == Keys.Count - 1) - { - Position = -1; - return true; - } - return false; - } - } -} diff --git a/tools/SRB2Updater/Debug.Designer.cs b/tools/SRB2Updater/Debug.Designer.cs deleted file mode 100644 index 6ec72f904..000000000 --- a/tools/SRB2Updater/Debug.Designer.cs +++ /dev/null @@ -1,266 +0,0 @@ -namespace SRB2Updater -{ - partial class Debug - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.lblOverallPercentage = new System.Windows.Forms.Label(); - this.lblPercent = new System.Windows.Forms.Label(); - this.lblOverall = new System.Windows.Forms.Label(); - this.lblCurrent = new System.Windows.Forms.Label(); - this.lblTotal = new System.Windows.Forms.Label(); - this.lblRead = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.label6 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.lblKonami = new System.Windows.Forms.Label(); - this.lblRandom = new System.Windows.Forms.Label(); - this.label9 = new System.Windows.Forms.Label(); - this.tableLayoutPanel1.SuspendLayout(); - this.SuspendLayout(); - // - // lblOverallPercentage - // - this.lblOverallPercentage.AutoSize = true; - this.lblOverallPercentage.Location = new System.Drawing.Point(176, 150); - this.lblOverallPercentage.Name = "lblOverallPercentage"; - this.lblOverallPercentage.Size = new System.Drawing.Size(21, 13); - this.lblOverallPercentage.TabIndex = 26; - this.lblOverallPercentage.Text = "0%"; - // - // lblPercent - // - this.lblPercent.AutoSize = true; - this.lblPercent.Location = new System.Drawing.Point(176, 90); - this.lblPercent.Name = "lblPercent"; - this.lblPercent.Size = new System.Drawing.Size(21, 13); - this.lblPercent.TabIndex = 25; - this.lblPercent.Text = "0%"; - // - // lblOverall - // - this.lblOverall.AutoSize = true; - this.lblOverall.Location = new System.Drawing.Point(176, 120); - this.lblOverall.Name = "lblOverall"; - this.lblOverall.Size = new System.Drawing.Size(41, 13); - this.lblOverall.TabIndex = 24; - this.lblOverall.Text = "0 bytes"; - // - // lblCurrent - // - this.lblCurrent.AutoSize = true; - this.lblCurrent.Location = new System.Drawing.Point(176, 60); - this.lblCurrent.Name = "lblCurrent"; - this.lblCurrent.Size = new System.Drawing.Size(41, 13); - this.lblCurrent.TabIndex = 23; - this.lblCurrent.Text = "0 bytes"; - // - // lblTotal - // - this.lblTotal.AutoSize = true; - this.lblTotal.Location = new System.Drawing.Point(176, 0); - this.lblTotal.Name = "lblTotal"; - this.lblTotal.Size = new System.Drawing.Size(41, 13); - this.lblTotal.TabIndex = 21; - this.lblTotal.Text = "0 bytes"; - // - // lblRead - // - this.lblRead.AutoSize = true; - this.lblRead.Location = new System.Drawing.Point(176, 30); - this.lblRead.Name = "lblRead"; - this.lblRead.Size = new System.Drawing.Size(41, 13); - this.lblRead.TabIndex = 22; - this.lblRead.Text = "0 bytes"; - this.lblRead.TextAlign = System.Drawing.ContentAlignment.TopRight; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(3, 0); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(105, 13); - this.label1.TabIndex = 27; - this.label1.Text = "Total Download Size"; - // - // tableLayoutPanel1 - // - this.tableLayoutPanel1.ColumnCount = 2; - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 66.66666F)); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); - this.tableLayoutPanel1.Controls.Add(this.label6, 0, 5); - this.tableLayoutPanel1.Controls.Add(this.label5, 0, 4); - this.tableLayoutPanel1.Controls.Add(this.label4, 0, 3); - this.tableLayoutPanel1.Controls.Add(this.label3, 0, 2); - this.tableLayoutPanel1.Controls.Add(this.label2, 0, 1); - this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); - this.tableLayoutPanel1.Controls.Add(this.lblOverallPercentage, 1, 5); - this.tableLayoutPanel1.Controls.Add(this.lblTotal, 1, 0); - this.tableLayoutPanel1.Controls.Add(this.lblOverall, 1, 4); - this.tableLayoutPanel1.Controls.Add(this.lblPercent, 1, 3); - this.tableLayoutPanel1.Controls.Add(this.lblRead, 1, 1); - this.tableLayoutPanel1.Controls.Add(this.lblCurrent, 1, 2); - this.tableLayoutPanel1.Controls.Add(this.label7, 0, 6); - this.tableLayoutPanel1.Controls.Add(this.lblKonami, 1, 6); - this.tableLayoutPanel1.Controls.Add(this.lblRandom, 1, 7); - this.tableLayoutPanel1.Controls.Add(this.label9, 0, 7); - this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.RowCount = 9; - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(260, 355); - this.tableLayoutPanel1.TabIndex = 28; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(3, 150); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(98, 13); - this.label6.TabIndex = 32; - this.label6.Text = "Overall Percentage"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(3, 120); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(132, 13); - this.label5.TabIndex = 31; - this.label5.Text = "Bytes Downloaded Overall"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(3, 90); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(118, 13); - this.label4.TabIndex = 30; - this.label4.Text = "Current File Percentage"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(3, 60); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(146, 13); - this.label3.TabIndex = 29; - this.label3.Text = "Downloaded from Current File"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(3, 30); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(62, 13); - this.label2.TabIndex = 28; - this.label2.Text = "Bytes Read"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(3, 180); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(42, 13); - this.label7.TabIndex = 33; - this.label7.Text = "Konami"; - // - // lblKonami - // - this.lblKonami.AutoSize = true; - this.lblKonami.Location = new System.Drawing.Point(176, 180); - this.lblKonami.Name = "lblKonami"; - this.lblKonami.Size = new System.Drawing.Size(16, 13); - this.lblKonami.TabIndex = 34; - this.lblKonami.Text = "-1"; - // - // lblRandom - // - this.lblRandom.AutoSize = true; - this.lblRandom.Location = new System.Drawing.Point(176, 210); - this.lblRandom.Name = "lblRandom"; - this.lblRandom.Size = new System.Drawing.Size(13, 13); - this.lblRandom.TabIndex = 37; - this.lblRandom.Text = "0"; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(3, 210); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(47, 13); - this.label9.TabIndex = 38; - this.label9.Text = "Random"; - // - // Debug - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(284, 379); - this.Controls.Add(this.tableLayoutPanel1); - this.Name = "Debug"; - this.Text = "Debug"; - this.tableLayoutPanel1.ResumeLayout(false); - this.tableLayoutPanel1.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Label lblOverallPercentage; - private System.Windows.Forms.Label lblPercent; - private System.Windows.Forms.Label lblOverall; - private System.Windows.Forms.Label lblCurrent; - private System.Windows.Forms.Label lblTotal; - private System.Windows.Forms.Label lblRead; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label lblKonami; - private System.Windows.Forms.Label lblRandom; - private System.Windows.Forms.Label label9; - } -} \ No newline at end of file diff --git a/tools/SRB2Updater/Debug.cs b/tools/SRB2Updater/Debug.cs deleted file mode 100644 index 5cb54dd37..000000000 --- a/tools/SRB2Updater/Debug.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; -using System.Windows.Forms; - -namespace SRB2Updater -{ - public partial class Debug : Form - { - public Debug() - { - InitializeComponent(); - } - - public String strOverall - { - get { return this.lblOverall.Text; } - set { this.lblOverall.Text = value; } - } - - public String strKonami - { - get { return this.lblKonami.Text; } - set { this.lblKonami.Text = value; } - } - - public String strRandom - { - get { return this.lblRandom.Text; } - set { this.lblRandom.Text = value; } - } - - public String strOverallPercentage - { - get { return this.lblOverallPercentage.Text; } - set { this.lblOverallPercentage.Text = value; } - } - - public String strCurrent - { - get { return this.lblCurrent.Text; } - set { this.lblCurrent.Text = value; } - } - - public String strPercent - { - get { return this.lblPercent.Text; } - set { this.lblPercent.Text = value; } - } - - public String strRead - { - get { return this.lblRead.Text; } - set { this.lblRead.Text = value; } - } - - public String strTotal - { - get { return this.lblTotal.Text; } - set { this.lblTotal.Text = value; } - } - } -} diff --git a/tools/SRB2Updater/Debug.resx b/tools/SRB2Updater/Debug.resx deleted file mode 100644 index ff31a6db5..000000000 --- a/tools/SRB2Updater/Debug.resx +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/tools/SRB2Updater/Launcher.Designer.cs b/tools/SRB2Updater/Launcher.Designer.cs deleted file mode 100644 index 9126eba54..000000000 --- a/tools/SRB2Updater/Launcher.Designer.cs +++ /dev/null @@ -1,766 +0,0 @@ -namespace SRB2Updater -{ - partial class Launcher - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Launcher)); - this.panel1 = new System.Windows.Forms.Panel(); - this.panel3 = new System.Windows.Forms.Panel(); - this.btnOptions = new System.Windows.Forms.Button(); - this.btnCheckFiles = new System.Windows.Forms.Button(); - this.btnStartSRB2 = new System.Windows.Forms.Button(); - this.panel2 = new System.Windows.Forms.Panel(); - this.lblProgress = new System.Windows.Forms.Label(); - this.update_optional = new System.Windows.Forms.CheckBox(); - this.progress_overall = new System.Windows.Forms.ProgressBar(); - this.progress_currentFile = new System.Windows.Forms.ProgressBar(); - this.tab_web = new System.Windows.Forms.TabControl(); - this.tabPage1 = new System.Windows.Forms.TabPage(); - this.panel10 = new System.Windows.Forms.Panel(); - this.webBrowser3 = new System.Windows.Forms.WebBrowser(); - this.tabPage2 = new System.Windows.Forms.TabPage(); - this.panel9 = new System.Windows.Forms.Panel(); - this.webBrowser1 = new System.Windows.Forms.WebBrowser(); - this.tabPage3 = new System.Windows.Forms.TabPage(); - this.panel8 = new System.Windows.Forms.Panel(); - this.fileList = new System.Windows.Forms.DataGridView(); - this.name = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.filename = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.status = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.localmd5 = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.md5 = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.optional = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.calculated = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.serverTab = new System.Windows.Forms.TabPage(); - this.panel6 = new System.Windows.Forms.Panel(); - this.listViewServers = new System.Windows.Forms.ListView(); - this.colhdrName = new System.Windows.Forms.ColumnHeader("(none)"); - this.colhdrGametype = new System.Windows.Forms.ColumnHeader(); - this.colhdrPing = new System.Windows.Forms.ColumnHeader(); - this.colhdrPlayers = new System.Windows.Forms.ColumnHeader(); - this.colhdrVersion = new System.Windows.Forms.ColumnHeader(); - this.panel4 = new System.Windows.Forms.Panel(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.label4 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); - this.button3 = new System.Windows.Forms.Button(); - this.btnConnect = new System.Windows.Forms.Button(); - this.panel5 = new System.Windows.Forms.Panel(); - this.bannerRandom = new System.Windows.Forms.Panel(); - this.backgroundWorkerQueryServers = new System.ComponentModel.BackgroundWorker(); - this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); - this.webBrowser2 = new System.Windows.Forms.WebBrowser(); - this.panel1.SuspendLayout(); - this.panel3.SuspendLayout(); - this.panel2.SuspendLayout(); - this.tab_web.SuspendLayout(); - this.tabPage1.SuspendLayout(); - this.panel10.SuspendLayout(); - this.tabPage2.SuspendLayout(); - this.panel9.SuspendLayout(); - this.tabPage3.SuspendLayout(); - this.panel8.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.fileList)).BeginInit(); - this.serverTab.SuspendLayout(); - this.panel6.SuspendLayout(); - this.panel4.SuspendLayout(); - this.groupBox1.SuspendLayout(); - this.panel5.SuspendLayout(); - this.SuspendLayout(); - // - // panel1 - // - this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.panel1.Controls.Add(this.panel3); - this.panel1.Controls.Add(this.panel2); - this.panel1.Location = new System.Drawing.Point(12, 415); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(772, 125); - this.panel1.TabIndex = 0; - // - // panel3 - // - this.panel3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel3.Controls.Add(this.btnOptions); - this.panel3.Controls.Add(this.btnCheckFiles); - this.panel3.Controls.Add(this.btnStartSRB2); - this.panel3.Location = new System.Drawing.Point(557, 10); - this.panel3.Name = "panel3"; - this.panel3.Size = new System.Drawing.Size(204, 104); - this.panel3.TabIndex = 1; - // - // btnOptions - // - this.btnOptions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.btnOptions.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnOptions.Location = new System.Drawing.Point(105, 72); - this.btnOptions.Name = "btnOptions"; - this.btnOptions.Size = new System.Drawing.Size(96, 29); - this.btnOptions.TabIndex = 2; - this.btnOptions.Text = "Options"; - this.btnOptions.UseVisualStyleBackColor = true; - this.btnOptions.Click += new System.EventHandler(this.btnOptions_Click); - // - // btnCheckFiles - // - this.btnCheckFiles.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.btnCheckFiles.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnCheckFiles.Location = new System.Drawing.Point(4, 72); - this.btnCheckFiles.Name = "btnCheckFiles"; - this.btnCheckFiles.Size = new System.Drawing.Size(96, 29); - this.btnCheckFiles.TabIndex = 1; - this.btnCheckFiles.Text = "Check Files"; - this.btnCheckFiles.UseVisualStyleBackColor = true; - this.btnCheckFiles.Click += new System.EventHandler(this.update_Load); - // - // btnStartSRB2 - // - this.btnStartSRB2.BackColor = System.Drawing.Color.Transparent; - this.btnStartSRB2.Font = new System.Drawing.Font("Arial Rounded MT Bold", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnStartSRB2.Location = new System.Drawing.Point(4, 4); - this.btnStartSRB2.Name = "btnStartSRB2"; - this.btnStartSRB2.Size = new System.Drawing.Size(197, 62); - this.btnStartSRB2.TabIndex = 0; - this.btnStartSRB2.Text = "Start"; - this.btnStartSRB2.UseVisualStyleBackColor = false; - this.btnStartSRB2.Click += new System.EventHandler(this.btnStartSRB2_Click); - // - // panel2 - // - this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); - this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel2.Controls.Add(this.lblProgress); - this.panel2.Controls.Add(this.update_optional); - this.panel2.Controls.Add(this.progress_overall); - this.panel2.Controls.Add(this.progress_currentFile); - this.panel2.Location = new System.Drawing.Point(10, 10); - this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(541, 105); - this.panel2.TabIndex = 0; - // - // lblProgress - // - this.lblProgress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.lblProgress.AutoSize = true; - this.lblProgress.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblProgress.ForeColor = System.Drawing.Color.Black; - this.lblProgress.Location = new System.Drawing.Point(6, 68); - this.lblProgress.Name = "lblProgress"; - this.lblProgress.Size = new System.Drawing.Size(299, 14); - this.lblProgress.TabIndex = 14; - this.lblProgress.Text = "Click \'Check Files\' to check for and apply updates."; - // - // update_optional - // - this.update_optional.AutoSize = true; - this.update_optional.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.update_optional.Location = new System.Drawing.Point(372, 68); - this.update_optional.Name = "update_optional"; - this.update_optional.Size = new System.Drawing.Size(160, 18); - this.update_optional.TabIndex = 13; - this.update_optional.Text = "Download Optional Updates"; - this.update_optional.UseVisualStyleBackColor = true; - // - // progress_overall - // - this.progress_overall.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.progress_overall.Location = new System.Drawing.Point(9, 36); - this.progress_overall.Name = "progress_overall"; - this.progress_overall.Size = new System.Drawing.Size(522, 26); - this.progress_overall.TabIndex = 1; - // - // progress_currentFile - // - this.progress_currentFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.progress_currentFile.Location = new System.Drawing.Point(9, 4); - this.progress_currentFile.Name = "progress_currentFile"; - this.progress_currentFile.Size = new System.Drawing.Size(522, 26); - this.progress_currentFile.TabIndex = 0; - // - // tab_web - // - this.tab_web.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.tab_web.Controls.Add(this.tabPage1); - this.tab_web.Controls.Add(this.tabPage2); - this.tab_web.Controls.Add(this.tabPage3); - this.tab_web.Controls.Add(this.serverTab); - this.tab_web.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F); - this.tab_web.Location = new System.Drawing.Point(0, 138); - this.tab_web.Name = "tab_web"; - this.tab_web.SelectedIndex = 0; - this.tab_web.Size = new System.Drawing.Size(770, 256); - this.tab_web.TabIndex = 1; - // - // tabPage1 - // - this.tabPage1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.tabPage1.Controls.Add(this.panel10); - this.tabPage1.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.tabPage1.Location = new System.Drawing.Point(4, 23); - this.tabPage1.Name = "tabPage1"; - this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(762, 229); - this.tabPage1.TabIndex = 0; - this.tabPage1.Text = "News & Updates"; - // - // panel10 - // - this.panel10.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel10.Controls.Add(this.webBrowser3); - this.panel10.Location = new System.Drawing.Point(4, 6); - this.panel10.Name = "panel10"; - this.panel10.Padding = new System.Windows.Forms.Padding(5); - this.panel10.Size = new System.Drawing.Size(748, 217); - this.panel10.TabIndex = 14; - // - // webBrowser3 - // - this.webBrowser3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.webBrowser3.Location = new System.Drawing.Point(8, 8); - this.webBrowser3.MinimumSize = new System.Drawing.Size(20, 20); - this.webBrowser3.Name = "webBrowser3"; - this.webBrowser3.Size = new System.Drawing.Size(732, 201); - this.webBrowser3.TabIndex = 0; - this.webBrowser3.Url = new System.Uri("http://update.srb2.org/files_beta/files_beta.xml", System.UriKind.Absolute); - // - // tabPage2 - // - this.tabPage2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.tabPage2.Controls.Add(this.panel9); - this.tabPage2.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F); - this.tabPage2.Location = new System.Drawing.Point(4, 23); - this.tabPage2.Name = "tabPage2"; - this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(762, 229); - this.tabPage2.TabIndex = 1; - this.tabPage2.Text = "Change Log"; - // - // panel9 - // - this.panel9.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel9.Controls.Add(this.webBrowser1); - this.panel9.Location = new System.Drawing.Point(4, 6); - this.panel9.Name = "panel9"; - this.panel9.Padding = new System.Windows.Forms.Padding(5); - this.panel9.Size = new System.Drawing.Size(748, 217); - this.panel9.TabIndex = 13; - // - // webBrowser1 - // - this.webBrowser1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.webBrowser1.Location = new System.Drawing.Point(8, 8); - this.webBrowser1.MinimumSize = new System.Drawing.Size(20, 20); - this.webBrowser1.Name = "webBrowser1"; - this.webBrowser1.Size = new System.Drawing.Size(732, 201); - this.webBrowser1.TabIndex = 0; - this.webBrowser1.Url = new System.Uri("http://update.srb2.org/files_beta/changelog.html", System.UriKind.Absolute); - // - // tabPage3 - // - this.tabPage3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.tabPage3.Controls.Add(this.panel8); - this.tabPage3.Location = new System.Drawing.Point(4, 23); - this.tabPage3.Name = "tabPage3"; - this.tabPage3.Padding = new System.Windows.Forms.Padding(3); - this.tabPage3.Size = new System.Drawing.Size(762, 229); - this.tabPage3.TabIndex = 2; - this.tabPage3.Text = "Download List"; - // - // panel8 - // - this.panel8.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel8.Controls.Add(this.fileList); - this.panel8.Location = new System.Drawing.Point(4, 6); - this.panel8.Name = "panel8"; - this.panel8.Padding = new System.Windows.Forms.Padding(5); - this.panel8.Size = new System.Drawing.Size(748, 217); - this.panel8.TabIndex = 12; - // - // fileList - // - this.fileList.AllowUserToAddRows = false; - this.fileList.AllowUserToDeleteRows = false; - this.fileList.AllowUserToResizeRows = false; - dataGridViewCellStyle1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - dataGridViewCellStyle1.Font = new System.Drawing.Font("Arial Rounded MT Bold", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - dataGridViewCellStyle1.ForeColor = System.Drawing.Color.Black; - dataGridViewCellStyle1.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - dataGridViewCellStyle1.SelectionForeColor = System.Drawing.Color.Black; - this.fileList.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1; - this.fileList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.fileList.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill; - this.fileList.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - this.fileList.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None; - dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - dataGridViewCellStyle2.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F); - dataGridViewCellStyle2.ForeColor = System.Drawing.Color.Black; - dataGridViewCellStyle2.Padding = new System.Windows.Forms.Padding(2); - dataGridViewCellStyle2.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - dataGridViewCellStyle2.SelectionForeColor = System.Drawing.Color.Black; - dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.True; - this.fileList.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle2; - this.fileList.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this.fileList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { - this.name, - this.filename, - this.status, - this.localmd5, - this.md5, - this.optional, - this.calculated}); - dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - dataGridViewCellStyle4.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F); - dataGridViewCellStyle4.ForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle4.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - dataGridViewCellStyle4.SelectionForeColor = System.Drawing.Color.Black; - dataGridViewCellStyle4.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this.fileList.DefaultCellStyle = dataGridViewCellStyle4; - this.fileList.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.fileList.Location = new System.Drawing.Point(8, 8); - this.fileList.MultiSelect = false; - this.fileList.Name = "fileList"; - this.fileList.ReadOnly = true; - dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle5.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - dataGridViewCellStyle5.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F); - dataGridViewCellStyle5.ForeColor = System.Drawing.SystemColors.WindowText; - dataGridViewCellStyle5.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - dataGridViewCellStyle5.SelectionForeColor = System.Drawing.Color.Black; - dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.True; - this.fileList.RowHeadersDefaultCellStyle = dataGridViewCellStyle5; - this.fileList.RowHeadersVisible = false; - dataGridViewCellStyle6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - dataGridViewCellStyle6.ForeColor = System.Drawing.Color.Black; - dataGridViewCellStyle6.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - dataGridViewCellStyle6.SelectionForeColor = System.Drawing.Color.Black; - this.fileList.RowsDefaultCellStyle = dataGridViewCellStyle6; - this.fileList.RowTemplate.DefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - this.fileList.RowTemplate.DefaultCellStyle.Font = new System.Drawing.Font("Arial", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.fileList.RowTemplate.DefaultCellStyle.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - this.fileList.RowTemplate.DefaultCellStyle.SelectionForeColor = System.Drawing.Color.Black; - this.fileList.RowTemplate.ReadOnly = true; - this.fileList.Size = new System.Drawing.Size(732, 201); - this.fileList.TabIndex = 11; - // - // name - // - this.name.DataPropertyName = "name"; - dataGridViewCellStyle3.BackColor = System.Drawing.Color.White; - this.name.DefaultCellStyle = dataGridViewCellStyle3; - this.name.FillWeight = 128.7982F; - this.name.HeaderText = "Name"; - this.name.Name = "name"; - this.name.ReadOnly = true; - // - // filename - // - this.filename.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; - this.filename.DataPropertyName = "filename"; - this.filename.HeaderText = "File"; - this.filename.Name = "filename"; - this.filename.ReadOnly = true; - this.filename.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.filename.Width = 150; - // - // status - // - this.status.DataPropertyName = "status"; - this.status.FillWeight = 128.7982F; - this.status.HeaderText = "Status"; - this.status.Name = "status"; - this.status.ReadOnly = true; - // - // localmd5 - // - this.localmd5.DataPropertyName = "localmd5"; - this.localmd5.FillWeight = 13.60544F; - this.localmd5.HeaderText = "localmd5"; - this.localmd5.Name = "localmd5"; - this.localmd5.ReadOnly = true; - this.localmd5.Visible = false; - // - // md5 - // - this.md5.DataPropertyName = "md5"; - this.md5.FillWeight = 128.7982F; - this.md5.HeaderText = "md5"; - this.md5.Name = "md5"; - this.md5.ReadOnly = true; - this.md5.Visible = false; - // - // optional - // - this.optional.DataPropertyName = "optional"; - this.optional.HeaderText = "optional"; - this.optional.Name = "optional"; - this.optional.ReadOnly = true; - this.optional.Visible = false; - // - // calculated - // - this.calculated.DataPropertyName = "calculated"; - this.calculated.HeaderText = "calculated"; - this.calculated.Name = "calculated"; - this.calculated.ReadOnly = true; - this.calculated.Visible = false; - // - // serverTab - // - this.serverTab.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.serverTab.Controls.Add(this.panel6); - this.serverTab.Controls.Add(this.panel4); - this.serverTab.Location = new System.Drawing.Point(4, 23); - this.serverTab.Name = "serverTab"; - this.serverTab.Padding = new System.Windows.Forms.Padding(3); - this.serverTab.Size = new System.Drawing.Size(762, 229); - this.serverTab.TabIndex = 3; - this.serverTab.Text = "Master Server"; - // - // panel6 - // - this.panel6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel6.Controls.Add(this.listViewServers); - this.panel6.Location = new System.Drawing.Point(4, 6); - this.panel6.Name = "panel6"; - this.panel6.Padding = new System.Windows.Forms.Padding(5); - this.panel6.Size = new System.Drawing.Size(603, 217); - this.panel6.TabIndex = 6; - // - // listViewServers - // - this.listViewServers.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.listViewServers.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - this.listViewServers.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.listViewServers.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.colhdrName, - this.colhdrGametype, - this.colhdrPing, - this.colhdrPlayers, - this.colhdrVersion}); - this.listViewServers.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.listViewServers.FullRowSelect = true; - this.listViewServers.HideSelection = false; - this.listViewServers.Location = new System.Drawing.Point(9, 8); - this.listViewServers.Name = "listViewServers"; - this.listViewServers.ShowItemToolTips = true; - this.listViewServers.Size = new System.Drawing.Size(586, 201); - this.listViewServers.TabIndex = 1; - this.listViewServers.UseCompatibleStateImageBehavior = false; - this.listViewServers.View = System.Windows.Forms.View.Details; - this.listViewServers.ItemActivate += new System.EventHandler(this.listViewServers_ItemActivate); - this.listViewServers.SelectedIndexChanged += new System.EventHandler(this.listViewServers_SelectedIndexChanged); - this.listViewServers.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listViewServers_ColumnClick); - // - // colhdrName - // - this.colhdrName.Tag = ""; - this.colhdrName.Text = "Server Name"; - this.colhdrName.Width = 231; - // - // colhdrGametype - // - this.colhdrGametype.Text = "Gametype"; - this.colhdrGametype.Width = 92; - // - // colhdrPing - // - this.colhdrPing.Text = "Ping (ms)"; - this.colhdrPing.Width = 87; - // - // colhdrPlayers - // - this.colhdrPlayers.Text = "Players"; - this.colhdrPlayers.Width = 88; - // - // colhdrVersion - // - this.colhdrVersion.Text = "Version"; - this.colhdrVersion.Width = 87; - // - // panel4 - // - this.panel4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel4.Controls.Add(this.groupBox1); - this.panel4.Controls.Add(this.button1); - this.panel4.Controls.Add(this.button3); - this.panel4.Controls.Add(this.btnConnect); - this.panel4.Location = new System.Drawing.Point(613, 6); - this.panel4.Name = "panel4"; - this.panel4.Padding = new System.Windows.Forms.Padding(5); - this.panel4.Size = new System.Drawing.Size(139, 217); - this.panel4.TabIndex = 5; - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.label4); - this.groupBox1.Controls.Add(this.label3); - this.groupBox1.Controls.Add(this.label2); - this.groupBox1.Controls.Add(this.label1); - this.groupBox1.Location = new System.Drawing.Point(9, 114); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(122, 95); - this.groupBox1.TabIndex = 5; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Key"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label4.ForeColor = System.Drawing.Color.Black; - this.label4.Location = new System.Drawing.Point(6, 77); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(87, 14); - this.label4.TabIndex = 3; - this.label4.Text = "Normal Game"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label3.ForeColor = System.Drawing.Color.DimGray; - this.label3.Location = new System.Drawing.Point(6, 57); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(78, 14); - this.label3.TabIndex = 2; - this.label3.Text = "Game is Full"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label2.ForeColor = System.Drawing.Color.Green; - this.label2.Location = new System.Drawing.Point(6, 37); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(99, 14); - this.label2.TabIndex = 1; - this.label2.Text = "Cheats Enabled"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label1.ForeColor = System.Drawing.Color.Red; - this.label1.Location = new System.Drawing.Point(6, 17); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(57, 14); - this.label1.TabIndex = 0; - this.label1.Text = "Modified"; - // - // button1 - // - this.button1.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9.75F); - this.button1.Location = new System.Drawing.Point(8, 8); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(123, 29); - this.button1.TabIndex = 2; - this.button1.Text = "Refresh List"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.btnRefresh_Click); - // - // button3 - // - this.button3.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9.75F); - this.button3.Location = new System.Drawing.Point(8, 78); - this.button3.Name = "button3"; - this.button3.Size = new System.Drawing.Size(123, 29); - this.button3.TabIndex = 4; - this.button3.Text = "Join Game (IP)"; - this.button3.UseVisualStyleBackColor = true; - // - // btnConnect - // - this.btnConnect.Enabled = false; - this.btnConnect.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9.75F); - this.btnConnect.Location = new System.Drawing.Point(8, 43); - this.btnConnect.Name = "btnConnect"; - this.btnConnect.Size = new System.Drawing.Size(123, 29); - this.btnConnect.TabIndex = 3; - this.btnConnect.Text = "Join Game (List)"; - this.btnConnect.UseVisualStyleBackColor = true; - this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click); - // - // panel5 - // - this.panel5.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel5.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; - this.panel5.Controls.Add(this.tab_web); - this.panel5.Controls.Add(this.bannerRandom); - this.panel5.Location = new System.Drawing.Point(12, 13); - this.panel5.Name = "panel5"; - this.panel5.Size = new System.Drawing.Size(772, 396); - this.panel5.TabIndex = 1; - // - // bannerRandom - // - this.bannerRandom.BackgroundImage = global::SRB2Updater.Properties.Resources.Banner4; - this.bannerRandom.Location = new System.Drawing.Point(0, -2); - this.bannerRandom.Name = "bannerRandom"; - this.bannerRandom.Size = new System.Drawing.Size(768, 123); - this.bannerRandom.TabIndex = 3; - // - // backgroundWorkerQueryServers - // - this.backgroundWorkerQueryServers.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerQueryServers_DoWork); - // - // openFileDialog1 - // - this.openFileDialog1.DefaultExt = "exe"; - this.openFileDialog1.Filter = "Executables files|*.exe|All files|*.*"; - // - // webBrowser2 - // - this.webBrowser2.Location = new System.Drawing.Point(8, 8); - this.webBrowser2.MinimumSize = new System.Drawing.Size(20, 20); - this.webBrowser2.Name = "webBrowser2"; - this.webBrowser2.Size = new System.Drawing.Size(567, 201); - this.webBrowser2.TabIndex = 0; - this.webBrowser2.Url = new System.Uri("http://update.srb2.org/files_beta/changelog.html", System.UriKind.Absolute); - // - // Launcher - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.ClientSize = new System.Drawing.Size(796, 552); - this.Controls.Add(this.panel5); - this.Controls.Add(this.panel1); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.KeyPreview = true; - this.Name = "Launcher"; - this.Text = "Launcher"; - this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Launcher_FormClosed); - this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Launcher_KeyUp); - this.panel1.ResumeLayout(false); - this.panel3.ResumeLayout(false); - this.panel2.ResumeLayout(false); - this.panel2.PerformLayout(); - this.tab_web.ResumeLayout(false); - this.tabPage1.ResumeLayout(false); - this.panel10.ResumeLayout(false); - this.tabPage2.ResumeLayout(false); - this.panel9.ResumeLayout(false); - this.tabPage3.ResumeLayout(false); - this.panel8.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.fileList)).EndInit(); - this.serverTab.ResumeLayout(false); - this.panel6.ResumeLayout(false); - this.panel4.ResumeLayout(false); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.panel5.ResumeLayout(false); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Panel panel1; - private System.Windows.Forms.Panel panel2; - private System.Windows.Forms.Panel panel3; - private System.Windows.Forms.Button btnOptions; - private System.Windows.Forms.Button btnCheckFiles; - private System.Windows.Forms.Button btnStartSRB2; - private System.Windows.Forms.TabControl tab_web; - private System.Windows.Forms.TabPage tabPage1; - private System.Windows.Forms.TabPage tabPage2; - private System.Windows.Forms.Panel panel5; - private System.Windows.Forms.WebBrowser webBrowser1; - private System.Windows.Forms.Panel bannerRandom; - private System.Windows.Forms.ProgressBar progress_overall; - private System.Windows.Forms.ProgressBar progress_currentFile; - private System.Windows.Forms.TabPage tabPage3; - private System.Windows.Forms.DataGridView fileList; - private System.Windows.Forms.CheckBox update_optional; - private System.Windows.Forms.Label lblProgress; - private System.Windows.Forms.DataGridViewTextBoxColumn name; - private System.Windows.Forms.DataGridViewTextBoxColumn filename; - private System.Windows.Forms.DataGridViewTextBoxColumn status; - private System.Windows.Forms.DataGridViewTextBoxColumn localmd5; - private System.Windows.Forms.DataGridViewTextBoxColumn md5; - private System.Windows.Forms.DataGridViewTextBoxColumn optional; - private System.Windows.Forms.DataGridViewTextBoxColumn calculated; - private System.Windows.Forms.TabPage serverTab; - private System.Windows.Forms.ListView listViewServers; - private System.Windows.Forms.ColumnHeader colhdrName; - private System.Windows.Forms.ColumnHeader colhdrGametype; - private System.Windows.Forms.ColumnHeader colhdrPing; - private System.Windows.Forms.ColumnHeader colhdrPlayers; - private System.Windows.Forms.ColumnHeader colhdrVersion; - private System.ComponentModel.BackgroundWorker backgroundWorkerQueryServers; - private System.Windows.Forms.Panel panel4; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Button button3; - private System.Windows.Forms.Button btnConnect; - private System.Windows.Forms.OpenFileDialog openFileDialog1; - private System.Windows.Forms.Panel panel6; - private System.Windows.Forms.Panel panel8; - private System.Windows.Forms.Panel panel9; - private System.Windows.Forms.Panel panel10; - private System.Windows.Forms.WebBrowser webBrowser3; - private System.Windows.Forms.WebBrowser webBrowser2; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label4; - } -} \ No newline at end of file diff --git a/tools/SRB2Updater/Launcher.cs b/tools/SRB2Updater/Launcher.cs deleted file mode 100644 index df2fdf712..000000000 --- a/tools/SRB2Updater/Launcher.cs +++ /dev/null @@ -1,658 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -//using System.Data.OleDb; -using System.Xml; -//using System.Drawing; -using System.Text; -using System.Windows.Forms; -using System.Net; -using System.IO; -using System.Threading; -using System.Security.Cryptography; -//using System.Runtime.InteropServices; -using System.Diagnostics; -using System.Drawing; -using System.Media; - -namespace SRB2Updater -{ - public partial class Launcher : Form - { - private Settings settings = new Settings(); - private Debug debug = new Debug(); - // The thread inside which the download happens - private Thread thrDownload; - private Thread thrTotal; - // The stream of data retrieved from the web server - private Stream strResponse; - // The stream of data that we write to the harddrive - private Stream strLocal; - // The request to the web server for file information - private HttpWebRequest webRequest; - // The response from the web server containing information about the file - private HttpWebResponse webResponse; - // The progress of the download in percentage - private static int PercentProgress; - private static int OverallPercentProgress; - // Overall progress as a percentage - private static Int64 OverallProgress; - // Progress stored, for calculating overall - private static Int64 CurrentProgress; - // Total File Size of entire update - private static Int64 TotalSize; - // The delegate which we will call from the thread to update the form - private delegate void UpdateProgessCallback(Int64 BytesRead, Int64 TotalBytes); - private delegate void OverallProgessCallback(Int64 BytesRead); - // When to pause - bool goPause = false; - // Download Details - string downFile; - // Updating - bool filesGot = false; - bool downloadStatus = false; - bool doneCalculate = false; - string formTitle = "Sonic Robo Blast 2 Launcher"; - bool loadedBat = false; - ProcessStartInfo startinfo = new ProcessStartInfo(); - private ServerQuerier sq; - private string MSFail; - - public Launcher(string[] args) - { - InitializeComponent(); - settings.GetSettings(); - sq = new ServerQuerier(); - ServerInfoListViewAdder silva = new ServerInfoListViewAdder(sq, this); - try - { - sq.SetMasterServer(settings.msAddress, Convert.ToUInt16(settings.msPort)); - } - catch (Exception exception) - { - MSFail = exception.Message; - } - sq.StartListening(silva); - backgroundWorkerQueryServers.RunWorkerAsync(); - foreach (string arg in args) - { - if (arg == "-debug") - { - debug.Show(); - break; - } - } - RandomBanner(); - } - - public string getMD5(string filename) - { - StringBuilder sb = new StringBuilder(); - FileInfo f = new FileInfo(filename); - FileStream fs = f.OpenRead(); - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] hash = md5.ComputeHash(fs); - fs.Close(); - foreach (byte hex in hash) - sb.Append(hex.ToString("x2")); - string md5sum = sb.ToString(); - return md5sum; - } - - public void PlayIt() - { - SoundPlayer player = new SoundPlayer(Properties.Resources.Kotaku); - player.Play(); - } - - public void RandomBanner() - { - Random random = new Random(); - int rand = random.Next(0, 4); - //this.bannerRandom.BackgroundImage = global::SRB2Updater.Properties.Resources.Banner; - switch (rand) - { - case 0: - bannerRandom.BackgroundImage = global::SRB2Updater.Properties.Resources.Banner; - break; - case 1: - bannerRandom.BackgroundImage = global::SRB2Updater.Properties.Resources.Banner2; - break; - case 2: - bannerRandom.BackgroundImage = global::SRB2Updater.Properties.Resources.Banner3; - break; - case 3: - bannerRandom.BackgroundImage = global::SRB2Updater.Properties.Resources.Banner4; - break; - default: - bannerRandom.BackgroundImage = global::SRB2Updater.Properties.Resources.Banner; - break; - } - - debug.strRandom = Convert.ToString(rand); - } - - private void updateList(bool doCalculate) - { - if (filesGot == false) - { - - XmlDataDocument xmlDatadoc = new XmlDataDocument(); - xmlDatadoc.DataSet.ReadXml("http://update.srb2.org/files_beta/files_beta.xml"); - DataSet ds = new DataSet("Files DataSet"); - ds = xmlDatadoc.DataSet; - fileList.DataSource = ds.DefaultViewManager; - fileList.DataMember = "File"; - filesGot = true; - } - if (downloadStatus == false) - { - foreach (DataGridViewRow fileRow in fileList.Rows) - { - if (!File.Exists(fileRow.Cells["filename"].Value.ToString()) && fileRow.Cells["filename"].Value.ToString() != "srb2update.update") - { -// fileRow.DefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192))))); - fileRow.Cells["localmd5"].Value = "not_found"; - } else { - if (fileRow.Cells["filename"].Value.ToString() == "srb2update.update") - fileRow.Cells["localmd5"].Value = getMD5("srb2update.exe"); - else - fileRow.Cells["localmd5"].Value = getMD5(fileRow.Cells["filename"].Value.ToString()); - } - if (fileRow.Cells["localmd5"].Value.ToString() != fileRow.Cells["md5"].Value.ToString()) - { -// if (fileRow.Cells["localmd5"].Value.ToString() != "not_found") -// fileRow.DefaultCellStyle.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(224)))), ((int)(((byte)(206))))); - fileRow.Cells["status"].Value = "Queued"; - - } - else - { - fileRow.Cells["status"].Value = "Up to date"; - } - } - if (doCalculate) - { - thrTotal = new Thread(new ParameterizedThreadStart(CalculateTotalSize)); - thrTotal.Start(0); - } - if (doneCalculate) - { - foreach (DataGridViewRow fileRow in fileList.Rows) - { - if (fileRow.Cells["localmd5"].Value.ToString() != fileRow.Cells["md5"].Value.ToString()) - { - if (fileRow.Cells["optional"].Value.ToString() == "1" && !update_optional.Checked) - fileRow.Cells["Status"].Value = "Skipped (Optional)"; - else - { - downFile = fileRow.Cells["filename"].Value.ToString(); - thrDownload = new Thread(new ParameterizedThreadStart(Download)); - thrDownload.Start(0); - fileRow.Cells["Status"].Value = "Downloading..."; - downloadStatus = true; - break; - } - } - else - { - fileRow.Cells["Status"].Value = "Up to date"; - } - CurrentProgress = 0; - } - } - } - } - - private void UpdateProgress(Int64 BytesRead, Int64 TotalBytes) - { - // Calculate the download progress in percentages - PercentProgress = Convert.ToInt32((BytesRead * 100) / TotalBytes); - // Make progress on the progress bar - progress_currentFile.Value = PercentProgress; - // Display the current progress on the form - lblProgress.Text = downFile + " - " + (BytesRead / 1024) + "KB of " + (TotalBytes / 1024) + "KB (" + PercentProgress + "%)"; - this.Text = formTitle + " :: Downloading " + downFile + " (" + PercentProgress + "%)"; - debug.strPercent = PercentProgress.ToString() + "%"; - if (BytesRead >= TotalBytes - 1) - updateList(false); - } - - private void UpdateOverallProgress(Int64 BytesRead) - { - // Calculate progress change and add to OverallProgress... - OverallProgress += BytesRead - CurrentProgress; - // Calculate the download progress in percentages - if (TotalSize < 1) - TotalSize = 1; - OverallPercentProgress = Convert.ToInt32((OverallProgress * 100) / TotalSize); - // Make progress on the progress bar - if (OverallPercentProgress > 100) - OverallPercentProgress = 100; - progress_overall.Value = OverallPercentProgress; - if (OverallProgress >= TotalSize) - { - lblProgress.Text = "Done"; - btnCheckFiles.Enabled = true; - } - CurrentProgress = BytesRead; - debug.strCurrent = Convert.ToString(CurrentProgress) + " bytes"; - debug.strOverall = Convert.ToString(OverallProgress) + " bytes"; - debug.strOverallPercentage = Convert.ToString(OverallPercentProgress) + "%"; - debug.strRead = Convert.ToString(BytesRead) + " bytes"; - debug.strTotal = Convert.ToString(TotalSize) + " bytes"; - } - - private void CalculateTotalSize(object startpoint) - { - foreach (DataGridViewRow fileRow in fileList.Rows) - { - if ((fileRow.Cells["optional"].Value.ToString() == "0" || update_optional.Checked) && fileRow.Cells["localmd5"].Value.ToString() != fileRow.Cells["md5"].Value.ToString()) - { - try - { - // Create a request to the file we are downloading - webRequest = (HttpWebRequest)WebRequest.Create("http://update.srb2.org/files_beta/" + fileRow.Cells["filename"].Value.ToString()); - // Set the starting point of the request - webRequest.AddRange(0); - - // Set default authentication for retrieving the file - webRequest.Credentials = CredentialCache.DefaultCredentials; - // Retrieve the response from the server - webResponse = (HttpWebResponse)webRequest.GetResponse(); - // Ask the server for the file size and store it - Int64 fileSize = webResponse.ContentLength; - TotalSize = TotalSize + fileSize; - } - finally - { - // When the above code has ended, close the streams - webResponse.Close(); - } - } - } - doneCalculate = true; - updateList(false); - } - - private void Download(object startpoint) - { - try - { - string filename = Convert.ToString(startpoint); - // Create a request to the file we are downloading - webRequest = (HttpWebRequest)WebRequest.Create("http://update.srb2.org/files_beta/" + downFile); - // Set the starting point of the request - webRequest.AddRange(0); - - // Set default authentication for retrieving the file - webRequest.Credentials = CredentialCache.DefaultCredentials; - // Retrieve the response from the server - webResponse = (HttpWebResponse)webRequest.GetResponse(); - // Ask the server for the file size and store it - Int64 fileSize = webResponse.ContentLength; - - // Open the URL for download - strResponse = webResponse.GetResponseStream(); - - // Create a new file stream where we will be saving the data (local drive) - strLocal = new FileStream(downFile, FileMode.Create, FileAccess.Write, FileShare.None); - // It will store the current number of bytes we retrieved from the server - int bytesSize = 0; - // A buffer for storing and writing the data retrieved from the server - byte[] downBuffer = new byte[2048]; - - // Loop through the buffer until the buffer is empty - while ((bytesSize = strResponse.Read(downBuffer, 0, downBuffer.Length)) > 0) - { - // Write the data from the buffer to the local hard drive - strLocal.Write(downBuffer, 0, bytesSize); - // Invoke the method that updates the form's label and progress bar - this.Invoke(new UpdateProgessCallback(this.UpdateProgress), new object[] { strLocal.Length, fileSize }); - this.Invoke(new OverallProgessCallback(this.UpdateOverallProgress), new object[] { strLocal.Length }); - - if (goPause == true) - { - break; - } - } - } - finally - { - // When the above code has ended, close the streams - strResponse.Close(); - strLocal.Close(); - // And update the row! - downloadStatus = false; - if (downFile == "srb2update.update" && loadedBat != true) - { - MessageBox.Show("The updater will now restart to apply a patch.", "Self Update", MessageBoxButtons.OK); - CreateUpdaterBat(); - startinfo.WindowStyle = ProcessWindowStyle.Hidden; - startinfo.FileName = "srb2update.bat"; - System.Diagnostics.Process.Start(startinfo); - downloadStatus = false; - Environment.Exit(0); - } else - updateList(false); - } - } - - private void CreateUpdaterBat() - { - File.WriteAllText("srb2update.bat", "ping 127.0.0.1\ncopy srb2update.update srb2update.exe\ndel srb2update.update\nsrb2update.exe\nexit"); - } - - - private void update_Load(object sender, EventArgs e) - { - lblProgress.Text = "Getting File List..."; - if (File.Exists("srb2update.bat")) - File.Delete("srb2update.bat"); - TotalSize = 0; - CurrentProgress = 0; - OverallPercentProgress = 0; - OverallProgress = 0; - btnCheckFiles.Enabled = false; - updateList(true); - } - - private void btnOptions_Click(object sender, EventArgs e) - { - new Options(settings).ShowDialog(); - } - - private class ServerInfoListViewAdder : ServerQuerier.ServerInfoReceiveHandler - { - private delegate ListViewItem AddToListCallback(ListViewItem lvi); - private Launcher form1; - private Dictionary dicGametypes = new Dictionary(); - private static Dictionary> dicDefaultFiles = - new Dictionary>(); - - static ServerInfoListViewAdder() - { - dicDefaultFiles.Add( - ServerQuerier.ServerInfoVer.SIV_PREME, - new List( - new string[] { - "srb2.srb", "sonic.plr", "tails.plr", "knux.plr", - "auto.wpn", "bomb.wpn", "home.wpn", "rail.wpn", "infn.wpn", - "drill.dta", "soar.dta", "music.dta" - }) - ); - - dicDefaultFiles.Add( - ServerQuerier.ServerInfoVer.SIV_ME, - new List( - new string[] { - "srb2.wad", "sonic.plr", "tails.plr", "knux.plr", - "rings.wpn", "drill.dta", "soar.dta", "music.dta" - }) - ); - } - - - public ServerInfoListViewAdder(ServerQuerier sq, Launcher form1) - : base(sq) - { - this.form1 = form1; - - // Gametypes. - dicGametypes.Add(0, "Co-op"); - dicGametypes.Add(1, "Match"); - dicGametypes.Add(2, "Race"); - dicGametypes.Add(3, "Tag"); - dicGametypes.Add(4, "CTF"); - dicGametypes.Add(5, "Chaos"); - - // Don't think these are actually used. - dicGametypes.Add(42, "Team Match"); - dicGametypes.Add(43, "Time-Only Race"); - } - - public override void ProcessServerInfo(ServerQuerier.SRB2ServerInfo srb2si) - { - ListView lv = form1.listViewServers; - - // Build a list item. - ListViewItem lvi = new ListViewItem(srb2si.strName); - - // So we can get address and whatever else we might need. - lvi.Tag = srb2si; - - // Gametype string, or number if not recognised. - if (dicGametypes.ContainsKey(srb2si.byGametype)) - lvi.SubItems.Add(dicGametypes[srb2si.byGametype]); - else - lvi.SubItems.Add(Convert.ToString(srb2si.byGametype)); - - lvi.SubItems.Add(Convert.ToString(srb2si.uiTime)); - lvi.SubItems.Add(srb2si.byPlayers + "/" + srb2si.byMaxplayers); - lvi.SubItems.Add(srb2si.strVersion); - - // Make the tooltip. - BuildTooltip(lvi, form1.settings.ShowDefaultWads); - - // Is the game full? - if (srb2si.byPlayers >= srb2si.byMaxplayers) - lvi.ForeColor = Color.DimGray; - // Modified? - else if (srb2si.bModified) - lvi.ForeColor = Color.Red; - - // Thread-safe goodness. - if (lv.InvokeRequired) - { - // Call ourselves in the context of the form's thread. - AddToListCallback addtolistcallback = new AddToListCallback(lv.Items.Add); - lv.Invoke(addtolistcallback, new object[] { lvi }); - } - else - { - // Add it! - lv.Items.Add(lvi); - } - - } - - public override void HandleException(Exception e) - { - - } - - public static void BuildTooltip(ListViewItem lvi, bool bShowDefaultWads) - { - string strWads = String.Empty; - ServerQuerier.SRB2ServerInfo srb2si = (ServerQuerier.SRB2ServerInfo)lvi.Tag; - - foreach (ServerQuerier.AddedWad aw in srb2si.listFiles) - { - List listDefaultFiles = dicDefaultFiles[srb2si.siv]; - - if (bShowDefaultWads || !listDefaultFiles.Contains(aw.strFilename)) - { - strWads += String.Format("\n{0} ({1:f1} KB)", aw.strFilename, Convert.ToSingle(aw.uiSize) / 1024); - if (aw.bImportant) - { - if (aw.downloadtype == ServerQuerier.DownloadTypes.DT_TOOBIG) - strWads += " (too big to download)"; - else if (aw.downloadtype == ServerQuerier.DownloadTypes.DT_DISABLED) - strWads += " (downloading disabled)"; - } - else strWads += " (unimportant)"; - } - } - - lvi.ToolTipText = "Current map: " + srb2si.strMapName + "\n"; - if (strWads != String.Empty) - lvi.ToolTipText += "Wads added:" + strWads; - else lvi.ToolTipText += "No wads added"; - } - } - - private void backgroundWorkerQueryServers_DoWork(object sender, DoWorkEventArgs e) - { - MSClient msclient = new MSClient(); - - try - { - List listServers = msclient.GetServerList(settings.msAddress, Convert.ToUInt16(settings.msPort)); - - - // Query each of the individual servers asynchronously. - foreach (MSServerEntry msse in listServers) - { - sq.Query(msse.strAddress, msse.unPort); - } - } - catch (System.Net.Sockets.SocketException sockexception) - { - MSFail = sockexception.Message; - } - catch (Exception exception) - { - MSFail = exception.Message; - } - } - - private void btnRefresh_Click(object sender, EventArgs e) - { - if (!backgroundWorkerQueryServers.IsBusy) - { - // Clear the server list. - listViewServers.Items.Clear(); - - // Disable the Connect button. - btnConnect.Enabled = false; - - // Query the MS and the individual servers in another thread. - backgroundWorkerQueryServers.RunWorkerAsync(); - } - } - - private void btnConnect_Click(object sender, EventArgs e) - { - if (listViewServers.SelectedItems.Count > 0) - { - ConnectToServerFromListItem(listViewServers.SelectedItems[0]); - } - } - - private void ConnectToServerFromListItem(ListViewItem lvi) - { - ServerQuerier.SRB2ServerInfo srb2si = (ServerQuerier.SRB2ServerInfo)lvi.Tag; - - // Prompt to get a binary if we need one. - if (!settings.HasBinaryForVersion(srb2si.strVersion) && - MessageBox.Show("To join this game, you must register an executable file for version " + srb2si.strVersion + ". Would you like to do so?", Text, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes && - openFileDialog1.ShowDialog() == DialogResult.OK) - { - settings.SetBinary(srb2si.strVersion, openFileDialog1.FileName); - settings.SaveSettings(); - } - - // Go! - ConnectToServer(srb2si.strAddress, srb2si.unPort, srb2si.strVersion); - } - - private void ConnectToServer(string strAddress, ushort unPort, string strVersion) - { - // Make sure we now have a binary. - if (settings.HasBinaryForVersion(strVersion)) - { - try - { - string strBinary = settings.GetBinary(strVersion); - string strDirectory = System.IO.Path.GetDirectoryName(strBinary); - if (strDirectory != String.Empty) - System.IO.Directory.SetCurrentDirectory(strDirectory); - System.Diagnostics.Process.Start(strBinary, System.String.Format("-connect {0}:{1} {2}", strAddress, unPort, settings.Params)).Close(); - if (settings.CloseOnStart) - Environment.Exit(0); - } - catch (Exception exception) - { - MessageBox.Show("Unable to start SRB2: " + exception.Message + ".", "SRB2 MS Launcher", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - } - - private class ListViewSorter : System.Collections.IComparer - { - private int iColumn; - public int Column { get { return iColumn; } } - public SortOrder so; - - public ListViewSorter(int iColumn) - { - this.iColumn = iColumn; - so = SortOrder.Ascending; - } - - public int Compare(object x, object y) - { - ListViewItem lviX = (ListViewItem)x; - ListViewItem lviY = (ListViewItem)y; - - return ((so == SortOrder.Ascending) ? 1 : -1) * String.Compare(lviX.SubItems[iColumn].Text, lviY.SubItems[iColumn].Text); - } - - public void ToggleSortOrder() - { - if (so != SortOrder.Ascending) - so = SortOrder.Ascending; - else - so = SortOrder.Descending; - } - } - - private void listViewServers_ColumnClick(object sender, ColumnClickEventArgs e) - { - if (listViewServers.ListViewItemSorter != null && - ((ListViewSorter)listViewServers.ListViewItemSorter).Column == e.Column) - { - ((ListViewSorter)listViewServers.ListViewItemSorter).ToggleSortOrder(); - listViewServers.Sort(); - } - else - { - listViewServers.ListViewItemSorter = new ListViewSorter(e.Column); - } - } - - private void listViewServers_SelectedIndexChanged(object sender, EventArgs e) - { - btnConnect.Enabled = (listViewServers.SelectedItems.Count > 0); - } - - private void listViewServers_ItemActivate(object sender, EventArgs e) - { - ConnectToServerFromListItem(listViewServers.SelectedItems[0]); - } - - private void Launcher_FormClosed(object sender, FormClosedEventArgs e) - { - Environment.Exit(0); - } - - private Bunny sequence = new Bunny(); - - private void Launcher_KeyUp(object sender, KeyEventArgs e) - { - if (sequence.IsCompletedBy(e.KeyCode)) - { - PlayIt(); - } - debug.strKonami = Convert.ToString(sequence.Position); - } - - private void btnStartSRB2_Click(object sender, EventArgs e) - { - System.Diagnostics.Process.Start("srb2win.exe", System.String.Format("{0}", settings.Params)).Close(); - if(settings.CloseOnStart) - Environment.Exit(0); - } - } -} diff --git a/tools/SRB2Updater/Launcher.resx b/tools/SRB2Updater/Launcher.resx deleted file mode 100644 index 464d72c21..000000000 --- a/tools/SRB2Updater/Launcher.resx +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - True - - - True - - - True - - - True - - - True - - - True - - - True - - - 17, 17 - - - 585, 17 - - - - - AAABAAEAICAAAAEACACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAADg4OAIAAAABQABkAlgAAALkAAABQGQAAcwAlAJYAMQBzJQAAuQA9AJYxAACWAGIAMjIyALk9 - AAD/JSUAPj4+AFZWVgD/SEgAYmJiAABilgBubm4Aenp6AP9rawCAgIAAhoaGAJKSkgD/jo4Anp6eAKSg - oAD/jqsAqqqqAGuP/wC2trYAwMDAAI6r/wDCwsIAa8b/AM7OzgCO1P8A2traAObm5gDy8vIA////AAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQ8PHQAAAAAAAAAAAAAAACMgJSUlJSUZ - AAAAABMNBgoPDw8AAAAAAAAAAAAAACInJycnJycnJyclFgYGBggPDw8PDwAAAAAAAAAAAAAjJycnJycn - JycnGScnFQkGCA8PDw8AAAAAAAAAAAAAISMnJycjIyMjJycnJycVDwYGDw8PDwAAAAAAAAAAAAAQAAEj - HygqKSkkHyMnJwoPDwYJDw8PAAAAAAAAAAAAACkTHxwrKysrKysrGhkMDw8PCwYJDw8AAAAAAAAAACkp - JA0pACkrKysrKyspDw8PDw8PAwYIAAAAAAAAAAAAACsiARwAISsrKysrKysSDw8PDw8PAwYAAAAAAAAA - AAAAKyIAEAAfKysrKysrKxcPDw8PDw8PDwgIABYAABcSCAArKAMPACIrKysrKysrGw8PDw8PDw8PDw8P - Dw8PDw8RACsoBA8EISsrKysrKyseDw8PDw8PDw8PDw8PDw8PDwAAKx8PDw8VKSsrKysrKxcPDw8PDw8P - Dw8PDw8PDw8AACooFQ8PDw8aKCsrKysmDw8PDw8PDw8PDw8PDw8PFQAAAAAKDw8PDw8VIigoIgoPDw8P - Dw8PDw8PDw8PDxEAAAAAAAoPDw8PDw8XFxcXEhIPDwUPDw8PDw8PDw8YAAAAAAAACA8PDw8SFxcXFxcX - FxcPFQ8PDw8PDw8KAAAAAAAAAAAACg8PEhcXFxcXFxcXFxkjBRISEhISGAAAAAAAAAAAIRcXCA8XFxcX - FxcXFxcaJyMFDwoLEQAAAAAAAAAAAAAAFxcSDxIXFxcXFxcSEyAlIwILCwsIAAAAAAAAAAAAABcXEg8A - EhIXFxcXEgoPDBUUBwsLCwsLAAAAAAAAAAAAFxcAAAAAFxIXFxcXFxIKDw8ICwsLDg4LAAAAAAAAAAAA - AAAAAAAAABISFxcXFw8PDw8PDw8PDwAAAAAAAAAAAAAAAAAAAAAAAAASEhcSDw8PDw8PDxIAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAFwoSDw8SFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAP///////////////////3////w//APAf/AAAH/gAAD/wAAA/8AAAP/AAAD/AAAB/4AA - Af+AAABYgAAAAIAAAAGAAAADAAAAA8AAAAfAAAAPwAAAP+AAAH+AAAH/wAAB/4QAAP+eAAB//4AA///g - Af//+A////////////////// - - - \ No newline at end of file diff --git a/tools/SRB2Updater/MSClient.cs b/tools/SRB2Updater/MSClient.cs deleted file mode 100644 index 40cb0d984..000000000 --- a/tools/SRB2Updater/MSClient.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Net.Sockets; -using System.Net; -using System.IO; - -namespace SRB2Updater -{ - class MSClient - { - private Socket socket; - - /// - /// Constructs an MS client object. - /// - public MSClient() - { - socket = new Socket( - AddressFamily.InterNetwork, - SocketType.Stream, - ProtocolType.IP); - } - - /// - /// Gets list of servers reported by the MS. - /// - /// Hostname or IP address of MS. - /// Port of MS. - /// List of running servers. - public List GetServerList(string strAddress, ushort unPort) - { - // Resolve the address if necessary. - IPHostEntry iphe = Dns.GetHostEntry(strAddress); - - int iIPIndex = 0; - while (iIPIndex < iphe.AddressList.Length && - iphe.AddressList[iIPIndex].AddressFamily != socket.AddressFamily) - { - iIPIndex++; - } - - // No addresses from our family? - if (iIPIndex >= iphe.AddressList.Length) - throw new SocketException((int)SocketError.HostNotFound); - - socket.Connect(iphe.AddressList[iIPIndex], unPort); - - // Send a request for the short server list. - byte[] byPacket = new byte[12]; - BinaryWriter bw = new BinaryWriter(new MemoryStream(byPacket)); - bw.Write((uint)0); // Unused - bw.Write((uint)IPAddress.HostToNetworkOrder(205)); // GET_SHORT_SERVER_MSG - bw.Write((uint)0); // Length of tail. - socket.Send(byPacket); - - List listServers = new List(); - - // Don't sit and wait for ever. - socket.ReceiveTimeout = 10000; - - // Keep reading packets. We break if we receive the sentinel end-packet. - byte[] byServer = new byte[12 + 80]; - while (true) - { - int iLen = socket.Receive(byServer); - BinaryReader br = new BinaryReader(new MemoryStream(byServer)); - - // Ignore the first eight bytes. - br.ReadInt64(); - - // Is that the list finished? - int iTailLen = IPAddress.NetworkToHostOrder(br.ReadInt32()); - if (iTailLen == 0) - break; - else if (iTailLen != iLen - 12) - { - // MS is in a bad mood. - //throw new Exception("Bad packet."); - break; - } - - // Otherwise, add the server to the list. - MSServerEntry msse = new MSServerEntry(); - - br.ReadBytes(16); // Skip. - msse.strAddress = Encoding.ASCII.GetString(br.ReadBytes(16)); - - string str = Encoding.ASCII.GetString(br.ReadBytes(8)); - int iPos = str.IndexOf("\0"); - if (iPos >= 0) - str = str.Remove(iPos); - msse.unPort = Convert.ToUInt16(str); - - msse.strName = Encoding.ASCII.GetString(br.ReadBytes(32)); - iPos = msse.strName.IndexOf("\0"); - if (iPos >= 0) - msse.strName = msse.strName.Remove(iPos); - - msse.strVersion = Encoding.ASCII.GetString(br.ReadBytes(8)); - iPos = msse.strVersion.IndexOf("\0"); - if (iPos >= 0) - msse.strVersion = msse.strVersion.Remove(iPos); - - listServers.Add(msse); - } - - return listServers; - } - } - - public struct MSServerEntry - { - public string strAddress; - public ushort unPort; - public string strName; - public string strVersion; - public bool bPermanent; - } - -} diff --git a/tools/SRB2Updater/Options.Designer.cs b/tools/SRB2Updater/Options.Designer.cs deleted file mode 100644 index 01234549d..000000000 --- a/tools/SRB2Updater/Options.Designer.cs +++ /dev/null @@ -1,628 +0,0 @@ -namespace SRB2Updater -{ - partial class Options - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Options)); - this.groupDisplay = new System.Windows.Forms.GroupBox(); - this.label2 = new System.Windows.Forms.Label(); - this.txtHeight = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); - this.txtWidth = new System.Windows.Forms.TextBox(); - this.chkCustomResolution = new System.Windows.Forms.CheckBox(); - this.chkDisplayWindowed = new System.Windows.Forms.CheckBox(); - this.panel1 = new System.Windows.Forms.Panel(); - this.btnCancel = new System.Windows.Forms.Button(); - this.btnSave = new System.Windows.Forms.Button(); - this.panel2 = new System.Windows.Forms.Panel(); - this.groupMS = new System.Windows.Forms.GroupBox(); - this.label4 = new System.Windows.Forms.Label(); - this.txtMSPort = new System.Windows.Forms.TextBox(); - this.label3 = new System.Windows.Forms.Label(); - this.txtMSAddress = new System.Windows.Forms.TextBox(); - this.panel3 = new System.Windows.Forms.Panel(); - this.panel7 = new System.Windows.Forms.Panel(); - this.groupBox3 = new System.Windows.Forms.GroupBox(); - this.txtParams = new System.Windows.Forms.TextBox(); - this.label9 = new System.Windows.Forms.Label(); - this.panel4 = new System.Windows.Forms.Panel(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.listviewBinaries = new System.Windows.Forms.ListView(); - this.colhdrVersion = new System.Windows.Forms.ColumnHeader(); - this.colhdrBinary = new System.Windows.Forms.ColumnHeader(); - this.textboxBinary = new System.Windows.Forms.TextBox(); - this.btnAdd = new System.Windows.Forms.Button(); - this.btnDel = new System.Windows.Forms.Button(); - this.label5 = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.btnBrowse = new System.Windows.Forms.Button(); - this.textboxVersion = new System.Windows.Forms.TextBox(); - this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); - this.tabControl1 = new System.Windows.Forms.TabControl(); - this.tabPage1 = new System.Windows.Forms.TabPage(); - this.tabPage2 = new System.Windows.Forms.TabPage(); - this.panel5 = new System.Windows.Forms.Panel(); - this.panel6 = new System.Windows.Forms.Panel(); - this.groupBox2 = new System.Windows.Forms.GroupBox(); - this.chkShowDefaultWads = new System.Windows.Forms.CheckBox(); - this.chkCloseOnStart = new System.Windows.Forms.CheckBox(); - this.groupDisplay.SuspendLayout(); - this.panel1.SuspendLayout(); - this.panel2.SuspendLayout(); - this.groupMS.SuspendLayout(); - this.panel3.SuspendLayout(); - this.panel7.SuspendLayout(); - this.groupBox3.SuspendLayout(); - this.panel4.SuspendLayout(); - this.groupBox1.SuspendLayout(); - this.tabControl1.SuspendLayout(); - this.tabPage1.SuspendLayout(); - this.tabPage2.SuspendLayout(); - this.panel5.SuspendLayout(); - this.panel6.SuspendLayout(); - this.groupBox2.SuspendLayout(); - this.SuspendLayout(); - // - // groupDisplay - // - this.groupDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupDisplay.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.groupDisplay.Controls.Add(this.label2); - this.groupDisplay.Controls.Add(this.txtHeight); - this.groupDisplay.Controls.Add(this.label1); - this.groupDisplay.Controls.Add(this.txtWidth); - this.groupDisplay.Controls.Add(this.chkCustomResolution); - this.groupDisplay.Controls.Add(this.chkDisplayWindowed); - this.groupDisplay.Location = new System.Drawing.Point(8, 8); - this.groupDisplay.Name = "groupDisplay"; - this.groupDisplay.Size = new System.Drawing.Size(268, 102); - this.groupDisplay.TabIndex = 1; - this.groupDisplay.TabStop = false; - this.groupDisplay.Text = "Display Settings"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(128, 74); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(46, 15); - this.label2.TabIndex = 5; - this.label2.Text = "Height:"; - // - // txtHeight - // - this.txtHeight.Location = new System.Drawing.Point(175, 71); - this.txtHeight.MaxLength = 4; - this.txtHeight.Name = "txtHeight"; - this.txtHeight.Size = new System.Drawing.Size(46, 21); - this.txtHeight.TabIndex = 4; - this.txtHeight.Text = "768"; - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(19, 74); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(41, 15); - this.label1.TabIndex = 3; - this.label1.Text = "Width:"; - // - // txtWidth - // - this.txtWidth.Location = new System.Drawing.Point(66, 71); - this.txtWidth.MaxLength = 4; - this.txtWidth.Name = "txtWidth"; - this.txtWidth.Size = new System.Drawing.Size(46, 21); - this.txtWidth.TabIndex = 2; - this.txtWidth.Text = "1024"; - // - // chkCustomResolution - // - this.chkCustomResolution.AutoSize = true; - this.chkCustomResolution.Location = new System.Drawing.Point(6, 46); - this.chkCustomResolution.Name = "chkCustomResolution"; - this.chkCustomResolution.Size = new System.Drawing.Size(159, 19); - this.chkCustomResolution.TabIndex = 1; - this.chkCustomResolution.Text = "Use Custom Resolution"; - this.chkCustomResolution.UseVisualStyleBackColor = true; - this.chkCustomResolution.CheckedChanged += new System.EventHandler(this.chkCustomResolution_CheckedChanged); - // - // chkDisplayWindowed - // - this.chkDisplayWindowed.AutoSize = true; - this.chkDisplayWindowed.Location = new System.Drawing.Point(6, 20); - this.chkDisplayWindowed.Name = "chkDisplayWindowed"; - this.chkDisplayWindowed.Size = new System.Drawing.Size(117, 19); - this.chkDisplayWindowed.TabIndex = 0; - this.chkDisplayWindowed.Text = "Windowed Mode"; - this.chkDisplayWindowed.UseVisualStyleBackColor = true; - // - // panel1 - // - this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel1.Controls.Add(this.groupDisplay); - this.panel1.Location = new System.Drawing.Point(14, 13); - this.panel1.Name = "panel1"; - this.panel1.Padding = new System.Windows.Forms.Padding(5); - this.panel1.Size = new System.Drawing.Size(284, 118); - this.panel1.TabIndex = 2; - // - // btnCancel - // - this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnCancel.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnCancel.Location = new System.Drawing.Point(260, 525); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Size = new System.Drawing.Size(75, 23); - this.btnCancel.TabIndex = 3; - this.btnCancel.Text = "Cancel"; - this.btnCancel.UseVisualStyleBackColor = true; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); - // - // btnSave - // - this.btnSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.btnSave.Font = new System.Drawing.Font("Arial Rounded MT Bold", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.btnSave.Location = new System.Drawing.Point(174, 525); - this.btnSave.Name = "btnSave"; - this.btnSave.Size = new System.Drawing.Size(75, 23); - this.btnSave.TabIndex = 4; - this.btnSave.Text = "Ok"; - this.btnSave.UseVisualStyleBackColor = true; - this.btnSave.Click += new System.EventHandler(this.btnSave_Click); - // - // panel2 - // - this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel2.Controls.Add(this.groupMS); - this.panel2.Location = new System.Drawing.Point(13, 13); - this.panel2.Name = "panel2"; - this.panel2.Padding = new System.Windows.Forms.Padding(5); - this.panel2.Size = new System.Drawing.Size(286, 95); - this.panel2.TabIndex = 5; - // - // groupMS - // - this.groupMS.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupMS.Controls.Add(this.label4); - this.groupMS.Controls.Add(this.txtMSPort); - this.groupMS.Controls.Add(this.label3); - this.groupMS.Controls.Add(this.txtMSAddress); - this.groupMS.Location = new System.Drawing.Point(9, 8); - this.groupMS.Name = "groupMS"; - this.groupMS.Size = new System.Drawing.Size(269, 79); - this.groupMS.TabIndex = 0; - this.groupMS.TabStop = false; - this.groupMS.Text = "Connection"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(41, 51); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(32, 15); - this.label4.TabIndex = 3; - this.label4.Text = "Port:"; - // - // txtMSPort - // - this.txtMSPort.Location = new System.Drawing.Point(79, 48); - this.txtMSPort.Name = "txtMSPort"; - this.txtMSPort.Size = new System.Drawing.Size(86, 21); - this.txtMSPort.TabIndex = 2; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(17, 23); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(56, 15); - this.label3.TabIndex = 1; - this.label3.Text = "Address:"; - // - // txtMSAddress - // - this.txtMSAddress.Location = new System.Drawing.Point(79, 20); - this.txtMSAddress.Name = "txtMSAddress"; - this.txtMSAddress.Size = new System.Drawing.Size(184, 21); - this.txtMSAddress.TabIndex = 0; - // - // panel3 - // - this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.panel3.Controls.Add(this.panel7); - this.panel3.Controls.Add(this.panel4); - this.panel3.Controls.Add(this.panel1); - this.panel3.Location = new System.Drawing.Point(6, 6); - this.panel3.Name = "panel3"; - this.panel3.Padding = new System.Windows.Forms.Padding(10); - this.panel3.Size = new System.Drawing.Size(312, 467); - this.panel3.TabIndex = 6; - // - // panel7 - // - this.panel7.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel7.Controls.Add(this.groupBox3); - this.panel7.Location = new System.Drawing.Point(15, 350); - this.panel7.Name = "panel7"; - this.panel7.Padding = new System.Windows.Forms.Padding(5); - this.panel7.Size = new System.Drawing.Size(283, 106); - this.panel7.TabIndex = 7; - // - // groupBox3 - // - this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox3.Controls.Add(this.chkCloseOnStart); - this.groupBox3.Controls.Add(this.txtParams); - this.groupBox3.Controls.Add(this.label9); - this.groupBox3.Location = new System.Drawing.Point(13, 8); - this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(258, 83); - this.groupBox3.TabIndex = 12; - this.groupBox3.TabStop = false; - this.groupBox3.Text = "Command Line"; - // - // txtParams - // - this.txtParams.Location = new System.Drawing.Point(83, 20); - this.txtParams.Name = "txtParams"; - this.txtParams.Size = new System.Drawing.Size(167, 21); - this.txtParams.TabIndex = 6; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(5, 23); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(75, 15); - this.label9.TabIndex = 7; - this.label9.Text = "Parameters:"; - // - // panel4 - // - this.panel4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel4.Controls.Add(this.groupBox1); - this.panel4.Location = new System.Drawing.Point(15, 137); - this.panel4.Name = "panel4"; - this.panel4.Padding = new System.Windows.Forms.Padding(5); - this.panel4.Size = new System.Drawing.Size(284, 207); - this.panel4.TabIndex = 6; - // - // groupBox1 - // - this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox1.Controls.Add(this.listviewBinaries); - this.groupBox1.Controls.Add(this.textboxBinary); - this.groupBox1.Controls.Add(this.btnAdd); - this.groupBox1.Controls.Add(this.btnDel); - this.groupBox1.Controls.Add(this.label5); - this.groupBox1.Controls.Add(this.label7); - this.groupBox1.Controls.Add(this.btnBrowse); - this.groupBox1.Controls.Add(this.textboxVersion); - this.groupBox1.Location = new System.Drawing.Point(13, 8); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(259, 191); - this.groupBox1.TabIndex = 12; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Executables"; - // - // listviewBinaries - // - this.listviewBinaries.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.listviewBinaries.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.colhdrVersion, - this.colhdrBinary}); - this.listviewBinaries.FullRowSelect = true; - this.listviewBinaries.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; - this.listviewBinaries.HideSelection = false; - this.listviewBinaries.Location = new System.Drawing.Point(6, 19); - this.listviewBinaries.Name = "listviewBinaries"; - this.listviewBinaries.Size = new System.Drawing.Size(245, 83); - this.listviewBinaries.TabIndex = 0; - this.listviewBinaries.UseCompatibleStateImageBehavior = false; - this.listviewBinaries.View = System.Windows.Forms.View.Details; - this.listviewBinaries.SelectedIndexChanged += new System.EventHandler(this.listviewBinaries_SelectedIndexChanged); - // - // colhdrVersion - // - this.colhdrVersion.Text = "Version"; - // - // colhdrBinary - // - this.colhdrBinary.Text = "Binary"; - this.colhdrBinary.Width = 198; - // - // textboxBinary - // - this.textboxBinary.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textboxBinary.Enabled = false; - this.textboxBinary.Location = new System.Drawing.Point(84, 161); - this.textboxBinary.Name = "textboxBinary"; - this.textboxBinary.Size = new System.Drawing.Size(93, 21); - this.textboxBinary.TabIndex = 4; - this.textboxBinary.TextChanged += new System.EventHandler(this.textboxBinary_TextChanged); - // - // btnAdd - // - this.btnAdd.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.btnAdd.Location = new System.Drawing.Point(51, 104); - this.btnAdd.Name = "btnAdd"; - this.btnAdd.Size = new System.Drawing.Size(98, 25); - this.btnAdd.TabIndex = 1; - this.btnAdd.Text = "&Add"; - this.btnAdd.UseVisualStyleBackColor = true; - this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click); - // - // btnDel - // - this.btnDel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.btnDel.Enabled = false; - this.btnDel.Location = new System.Drawing.Point(155, 104); - this.btnDel.Name = "btnDel"; - this.btnDel.Size = new System.Drawing.Size(98, 25); - this.btnDel.TabIndex = 2; - this.btnDel.Text = "&Delete"; - this.btnDel.UseVisualStyleBackColor = true; - this.btnDel.Click += new System.EventHandler(this.btnDel_Click); - // - // label5 - // - this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(6, 138); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(51, 15); - this.label5.TabIndex = 2; - this.label5.Text = "Version:"; - // - // label7 - // - this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(6, 164); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(44, 15); - this.label7.TabIndex = 3; - this.label7.Text = "Binary:"; - // - // btnBrowse - // - this.btnBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.btnBrowse.Enabled = false; - this.btnBrowse.Location = new System.Drawing.Point(183, 161); - this.btnBrowse.Name = "btnBrowse"; - this.btnBrowse.Size = new System.Drawing.Size(68, 21); - this.btnBrowse.TabIndex = 5; - this.btnBrowse.Text = "&Browse..."; - this.btnBrowse.UseVisualStyleBackColor = true; - this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); - // - // textboxVersion - // - this.textboxVersion.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textboxVersion.Enabled = false; - this.textboxVersion.Location = new System.Drawing.Point(84, 135); - this.textboxVersion.Name = "textboxVersion"; - this.textboxVersion.Size = new System.Drawing.Size(167, 21); - this.textboxVersion.TabIndex = 3; - this.textboxVersion.TextChanged += new System.EventHandler(this.textboxVersion_TextChanged); - // - // openFileDialog1 - // - this.openFileDialog1.DefaultExt = "exe"; - this.openFileDialog1.Filter = "Executable files|*.exe|All files|*.*"; - // - // tabControl1 - // - this.tabControl1.Controls.Add(this.tabPage1); - this.tabControl1.Controls.Add(this.tabPage2); - this.tabControl1.Location = new System.Drawing.Point(12, 12); - this.tabControl1.Name = "tabControl1"; - this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(332, 507); - this.tabControl1.TabIndex = 7; - // - // tabPage1 - // - this.tabPage1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.tabPage1.Controls.Add(this.panel3); - this.tabPage1.Location = new System.Drawing.Point(4, 24); - this.tabPage1.Name = "tabPage1"; - this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(324, 479); - this.tabPage1.TabIndex = 0; - this.tabPage1.Text = "SRB2"; - // - // tabPage2 - // - this.tabPage2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.tabPage2.Controls.Add(this.panel5); - this.tabPage2.Location = new System.Drawing.Point(4, 24); - this.tabPage2.Name = "tabPage2"; - this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(324, 479); - this.tabPage2.TabIndex = 1; - this.tabPage2.Text = "Master Server"; - // - // panel5 - // - this.panel5.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(212)))), ((int)(((byte)(204)))), ((int)(((byte)(187))))); - this.panel5.Controls.Add(this.panel6); - this.panel5.Controls.Add(this.panel2); - this.panel5.Location = new System.Drawing.Point(6, 6); - this.panel5.Name = "panel5"; - this.panel5.Padding = new System.Windows.Forms.Padding(10); - this.panel5.Size = new System.Drawing.Size(312, 507); - this.panel5.TabIndex = 7; - // - // panel6 - // - this.panel6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.panel6.Controls.Add(this.groupBox2); - this.panel6.Location = new System.Drawing.Point(13, 114); - this.panel6.Name = "panel6"; - this.panel6.Padding = new System.Windows.Forms.Padding(5); - this.panel6.Size = new System.Drawing.Size(286, 61); - this.panel6.TabIndex = 6; - // - // groupBox2 - // - this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.groupBox2.Controls.Add(this.chkShowDefaultWads); - this.groupBox2.Location = new System.Drawing.Point(9, 8); - this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(269, 45); - this.groupBox2.TabIndex = 0; - this.groupBox2.TabStop = false; - this.groupBox2.Text = "List Settings"; - // - // chkShowDefaultWads - // - this.chkShowDefaultWads.AutoSize = true; - this.chkShowDefaultWads.Location = new System.Drawing.Point(6, 20); - this.chkShowDefaultWads.Name = "chkShowDefaultWads"; - this.chkShowDefaultWads.Size = new System.Drawing.Size(201, 19); - this.chkShowDefaultWads.TabIndex = 8; - this.chkShowDefaultWads.Text = "Show default files in list of wads"; - this.chkShowDefaultWads.UseVisualStyleBackColor = true; - // - // chkCloseOnStart - // - this.chkCloseOnStart.AutoSize = true; - this.chkCloseOnStart.Location = new System.Drawing.Point(9, 47); - this.chkCloseOnStart.Name = "chkCloseOnStart"; - this.chkCloseOnStart.Size = new System.Drawing.Size(216, 19); - this.chkCloseOnStart.TabIndex = 9; - this.chkCloseOnStart.Text = "Close Launcher when SRB2 starts"; - this.chkCloseOnStart.UseVisualStyleBackColor = true; - // - // Options - // - this.AcceptButton = this.btnSave; - this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(235)))), ((int)(((byte)(230)))), ((int)(((byte)(217))))); - this.ClientSize = new System.Drawing.Size(356, 560); - this.Controls.Add(this.tabControl1); - this.Controls.Add(this.btnSave); - this.Controls.Add(this.btnCancel); - this.Font = new System.Drawing.Font("Arial", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.Name = "Options"; - this.Text = "Options"; - this.groupDisplay.ResumeLayout(false); - this.groupDisplay.PerformLayout(); - this.panel1.ResumeLayout(false); - this.panel2.ResumeLayout(false); - this.groupMS.ResumeLayout(false); - this.groupMS.PerformLayout(); - this.panel3.ResumeLayout(false); - this.panel7.ResumeLayout(false); - this.groupBox3.ResumeLayout(false); - this.groupBox3.PerformLayout(); - this.panel4.ResumeLayout(false); - this.groupBox1.ResumeLayout(false); - this.groupBox1.PerformLayout(); - this.tabControl1.ResumeLayout(false); - this.tabPage1.ResumeLayout(false); - this.tabPage2.ResumeLayout(false); - this.panel5.ResumeLayout(false); - this.panel6.ResumeLayout(false); - this.groupBox2.ResumeLayout(false); - this.groupBox2.PerformLayout(); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.GroupBox groupDisplay; - private System.Windows.Forms.Panel panel1; - private System.Windows.Forms.CheckBox chkDisplayWindowed; - private System.Windows.Forms.Label label1; - private System.Windows.Forms.TextBox txtWidth; - private System.Windows.Forms.CheckBox chkCustomResolution; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.TextBox txtHeight; - private System.Windows.Forms.Button btnCancel; - private System.Windows.Forms.Button btnSave; - private System.Windows.Forms.Panel panel2; - private System.Windows.Forms.GroupBox groupMS; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.TextBox txtMSAddress; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.TextBox txtMSPort; - private System.Windows.Forms.Panel panel3; - private System.Windows.Forms.OpenFileDialog openFileDialog1; - private System.Windows.Forms.Panel panel4; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.ListView listviewBinaries; - private System.Windows.Forms.ColumnHeader colhdrVersion; - private System.Windows.Forms.ColumnHeader colhdrBinary; - private System.Windows.Forms.TextBox textboxBinary; - private System.Windows.Forms.Button btnAdd; - private System.Windows.Forms.Button btnDel; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Button btnBrowse; - private System.Windows.Forms.TextBox textboxVersion; - private System.Windows.Forms.TabControl tabControl1; - private System.Windows.Forms.TabPage tabPage1; - private System.Windows.Forms.TabPage tabPage2; - private System.Windows.Forms.Panel panel5; - private System.Windows.Forms.Panel panel6; - private System.Windows.Forms.GroupBox groupBox2; - private System.Windows.Forms.CheckBox chkShowDefaultWads; - private System.Windows.Forms.Panel panel7; - private System.Windows.Forms.GroupBox groupBox3; - private System.Windows.Forms.TextBox txtParams; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.CheckBox chkCloseOnStart; - } -} \ No newline at end of file diff --git a/tools/SRB2Updater/Options.cs b/tools/SRB2Updater/Options.cs deleted file mode 100644 index a45cb13af..000000000 --- a/tools/SRB2Updater/Options.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; -using System.Windows.Forms; -using System.IO; - -namespace SRB2Updater -{ - public partial class Options : Form - { - private Settings settings; - public Options(Settings settings) - { - InitializeComponent(); - this.settings = settings; - SetOptions(); - } - - private void SetOptions() - { - chkDisplayWindowed.Checked = settings.displayWindowed; - chkCustomResolution.Checked = settings.displayCustom; - txtHeight.Text = settings.displayHeight.ToString(); - txtWidth.Text = settings.displayWidth.ToString(); - txtMSPort.Text = settings.msPort.ToString(); - settings.AddBinariesToListView(listviewBinaries); - txtMSAddress.Text = settings.msAddress.ToString(); - txtParams.Text = settings.Params.ToString(); - chkCloseOnStart.Checked = settings.CloseOnStart; - chkShowDefaultWads.Checked = settings.ShowDefaultWads; - if (settings.displayCustom) - { - txtHeight.Enabled = true; - txtWidth.Enabled = true; - } - else - { - txtHeight.Enabled = false; - txtWidth.Enabled = false; - } - } - - private void chkCustomResolution_CheckedChanged(object sender, EventArgs e) - { - if (chkCustomResolution.Checked) - { - txtHeight.Enabled = true; - txtWidth.Enabled = true; - } - else - { - txtHeight.Enabled = false; - txtWidth.Enabled = false; - } - } - - private void btnSave_Click(object sender, EventArgs e) - { - settings.displayCustom = chkCustomResolution.Checked; - settings.displayHeight = Convert.ToInt32(txtHeight.Text); - settings.displayWidth = Convert.ToInt32(txtWidth.Text); - settings.displayWindowed = chkDisplayWindowed.Checked; - settings.msAddress = txtMSAddress.Text; - settings.ShowDefaultWads = chkShowDefaultWads.Checked; - settings.Params = txtParams.Text; - settings.msPort = Convert.ToInt32(txtMSPort.Text); - settings.CloseOnStart = chkCloseOnStart.Checked; - settings.SaveSettings(); - settings.SetBinariesFromListView(listviewBinaries); - Close(); - } - - private void btnCancel_Click(object sender, EventArgs e) - { - Close(); - } - - private void btnAdd_Click(object sender, EventArgs e) - { - listviewBinaries.Items.Add(new ListViewItem(new string[] { "[New Version]", "" })); - } - - private void btnDel_Click(object sender, EventArgs e) - { - if (listviewBinaries.SelectedItems.Count > 0) - listviewBinaries.Items.Remove(listviewBinaries.SelectedItems[0]); - } - - private void btnBrowse_Click(object sender, EventArgs e) - { - if (listviewBinaries.SelectedItems.Count > 0 && - openFileDialog1.ShowDialog() == DialogResult.OK) - textboxBinary.Text = openFileDialog1.FileName; - } - - private void textboxVersion_TextChanged(object sender, EventArgs e) - { - if (listviewBinaries.SelectedItems.Count > 0) - listviewBinaries.SelectedItems[0].Text = textboxVersion.Text; - } - - private void textboxBinary_TextChanged(object sender, EventArgs e) - { - if (listviewBinaries.SelectedItems.Count > 0) - listviewBinaries.SelectedItems[0].SubItems[1].Text = textboxBinary.Text; - } - - private void listviewBinaries_SelectedIndexChanged(object sender, EventArgs e) - { - if (listviewBinaries.SelectedItems.Count > 0) - { - btnDel.Enabled = true; - btnBrowse.Enabled = true; - textboxVersion.Text = listviewBinaries.SelectedItems[0].Text; - textboxBinary.Text = listviewBinaries.SelectedItems[0].SubItems[1].Text; - textboxVersion.Enabled = true; - textboxBinary.Enabled = true; - } - else - { - btnDel.Enabled = false; - btnBrowse.Enabled = false; - textboxVersion.Text = ""; - textboxBinary.Text = ""; - textboxVersion.Enabled = false; - textboxBinary.Enabled = false; - } - } - } -} diff --git a/tools/SRB2Updater/Options.resx b/tools/SRB2Updater/Options.resx deleted file mode 100644 index ee0d50c3f..000000000 --- a/tools/SRB2Updater/Options.resx +++ /dev/null @@ -1,166 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - 17, 17 - - - - - AAABAAEAICAAAAEACACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAADg4OAIAAAABQABkAlgAAALkAAABQGQAAcwAlAJYAMQBzJQAAuQA9AJYxAACWAGIAMjIyALk9 - AAD/JSUAPj4+AFZWVgD/SEgAYmJiAABilgBubm4Aenp6AP9rawCAgIAAhoaGAJKSkgD/jo4Anp6eAKSg - oAD/jqsAqqqqAGuP/wC2trYAwMDAAI6r/wDCwsIAa8b/AM7OzgCO1P8A2traAObm5gDy8vIA////AAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQ8PHQAAAAAAAAAAAAAAACMgJSUlJSUZ - AAAAABMNBgoPDw8AAAAAAAAAAAAAACInJycnJycnJyclFgYGBggPDw8PDwAAAAAAAAAAAAAjJycnJycn - JycnGScnFQkGCA8PDw8AAAAAAAAAAAAAISMnJycjIyMjJycnJycVDwYGDw8PDwAAAAAAAAAAAAAQAAEj - HygqKSkkHyMnJwoPDwYJDw8PAAAAAAAAAAAAACkTHxwrKysrKysrGhkMDw8PCwYJDw8AAAAAAAAAACkp - JA0pACkrKysrKyspDw8PDw8PAwYIAAAAAAAAAAAAACsiARwAISsrKysrKysSDw8PDw8PAwYAAAAAAAAA - AAAAKyIAEAAfKysrKysrKxcPDw8PDw8PDwgIABYAABcSCAArKAMPACIrKysrKysrGw8PDw8PDw8PDw8P - Dw8PDw8RACsoBA8EISsrKysrKyseDw8PDw8PDw8PDw8PDw8PDwAAKx8PDw8VKSsrKysrKxcPDw8PDw8P - Dw8PDw8PDw8AACooFQ8PDw8aKCsrKysmDw8PDw8PDw8PDw8PDw8PFQAAAAAKDw8PDw8VIigoIgoPDw8P - Dw8PDw8PDw8PDxEAAAAAAAoPDw8PDw8XFxcXEhIPDwUPDw8PDw8PDw8YAAAAAAAACA8PDw8SFxcXFxcX - FxcPFQ8PDw8PDw8KAAAAAAAAAAAACg8PEhcXFxcXFxcXFxkjBRISEhISGAAAAAAAAAAAIRcXCA8XFxcX - FxcXFxcaJyMFDwoLEQAAAAAAAAAAAAAAFxcSDxIXFxcXFxcSEyAlIwILCwsIAAAAAAAAAAAAABcXEg8A - EhIXFxcXEgoPDBUUBwsLCwsLAAAAAAAAAAAAFxcAAAAAFxIXFxcXFxIKDw8ICwsLDg4LAAAAAAAAAAAA - AAAAAAAAABISFxcXFw8PDw8PDw8PDwAAAAAAAAAAAAAAAAAAAAAAAAASEhcSDw8PDw8PDxIAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAFwoSDw8SFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAP///////////////////3////w//APAf/AAAH/gAAD/wAAA/8AAAP/AAAD/AAAB/4AA - Af+AAABYgAAAAIAAAAGAAAADAAAAA8AAAAfAAAAPwAAAP+AAAH+AAAH/wAAB/4QAAP+eAAB//4AA///g - Af//+A////////////////// - - - \ No newline at end of file diff --git a/tools/SRB2Updater/Program.cs b/tools/SRB2Updater/Program.cs deleted file mode 100644 index 51c0be56e..000000000 --- a/tools/SRB2Updater/Program.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Windows.Forms; - -namespace SRB2Updater -{ - static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main(string[] args) - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new Launcher(args)); - } - } -} diff --git a/tools/SRB2Updater/Properties/AssemblyInfo.cs b/tools/SRB2Updater/Properties/AssemblyInfo.cs deleted file mode 100644 index abc46e8cd..000000000 --- a/tools/SRB2Updater/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Resources; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SRB2 Automatic Updater")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Sonic Team Junior")] -[assembly: AssemblyProduct("Sonic Robo Blast 2")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("94c164ce-02a9-4966-948f-004d35760ba1")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: NeutralResourcesLanguageAttribute("en-US")] diff --git a/tools/SRB2Updater/Properties/Resources.Designer.cs b/tools/SRB2Updater/Properties/Resources.Designer.cs deleted file mode 100644 index 246c91e52..000000000 --- a/tools/SRB2Updater/Properties/Resources.Designer.cs +++ /dev/null @@ -1,132 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.4927 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SRB2Updater.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SRB2Updater.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static System.Drawing.Bitmap Banner { - get { - object obj = ResourceManager.GetObject("Banner", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap Banner2 { - get { - object obj = ResourceManager.GetObject("Banner2", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap Banner3 { - get { - object obj = ResourceManager.GetObject("Banner3", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap Banner4 { - get { - object obj = ResourceManager.GetObject("Banner4", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap CONSBACK { - get { - object obj = ResourceManager.GetObject("CONSBACK", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.IO.UnmanagedMemoryStream Kotaku { - get { - return ResourceManager.GetStream("Kotaku", resourceCulture); - } - } - - internal static System.Drawing.Bitmap Sonic { - get { - object obj = ResourceManager.GetObject("Sonic", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap sonic_bottom { - get { - object obj = ResourceManager.GetObject("sonic_bottom", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap sonic_top { - get { - object obj = ResourceManager.GetObject("sonic_top", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - internal static System.Drawing.Bitmap updaterbanner { - get { - object obj = ResourceManager.GetObject("updaterbanner", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - } -} diff --git a/tools/SRB2Updater/Properties/Resources.resx b/tools/SRB2Updater/Properties/Resources.resx deleted file mode 100644 index b5c93d021..000000000 --- a/tools/SRB2Updater/Properties/Resources.resx +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - ..\Resources\CONSBACK.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Sonic.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Banner.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\sonic_bottom.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\sonic_top.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\updaterbanner.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Banner2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Banner3.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Banner4.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\Kotaku.wav;System.IO.MemoryStream, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/tools/SRB2Updater/Properties/Settings.Designer.cs b/tools/SRB2Updater/Properties/Settings.Designer.cs deleted file mode 100644 index 4e8aea28c..000000000 --- a/tools/SRB2Updater/Properties/Settings.Designer.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:2.0.50727.3506 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SRB2Updater.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/tools/SRB2Updater/Properties/Settings.settings b/tools/SRB2Updater/Properties/Settings.settings deleted file mode 100644 index abf36c5d3..000000000 --- a/tools/SRB2Updater/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/tools/SRB2Updater/Resources/Banner.png b/tools/SRB2Updater/Resources/Banner.png deleted file mode 100644 index 7d8d55602..000000000 Binary files a/tools/SRB2Updater/Resources/Banner.png and /dev/null differ diff --git a/tools/SRB2Updater/Resources/Banner.psd b/tools/SRB2Updater/Resources/Banner.psd deleted file mode 100644 index eb29b8b6f..000000000 Binary files a/tools/SRB2Updater/Resources/Banner.psd and /dev/null differ diff --git a/tools/SRB2Updater/Resources/Banner2.png b/tools/SRB2Updater/Resources/Banner2.png deleted file mode 100644 index f3d3d3e6d..000000000 Binary files a/tools/SRB2Updater/Resources/Banner2.png and /dev/null differ diff --git a/tools/SRB2Updater/Resources/Banner3.png b/tools/SRB2Updater/Resources/Banner3.png deleted file mode 100644 index 04713070a..000000000 Binary files a/tools/SRB2Updater/Resources/Banner3.png and /dev/null differ diff --git a/tools/SRB2Updater/Resources/Banner4.png b/tools/SRB2Updater/Resources/Banner4.png deleted file mode 100644 index 8b2627b8d..000000000 Binary files a/tools/SRB2Updater/Resources/Banner4.png and /dev/null differ diff --git a/tools/SRB2Updater/Resources/CONSBACK.bmp b/tools/SRB2Updater/Resources/CONSBACK.bmp deleted file mode 100644 index 3c1298f08..000000000 Binary files a/tools/SRB2Updater/Resources/CONSBACK.bmp and /dev/null differ diff --git a/tools/SRB2Updater/Resources/Kotaku.wav b/tools/SRB2Updater/Resources/Kotaku.wav deleted file mode 100644 index 49e7f613a..000000000 Binary files a/tools/SRB2Updater/Resources/Kotaku.wav and /dev/null differ diff --git a/tools/SRB2Updater/Resources/Sonic.png b/tools/SRB2Updater/Resources/Sonic.png deleted file mode 100644 index a19cf225d..000000000 Binary files a/tools/SRB2Updater/Resources/Sonic.png and /dev/null differ diff --git a/tools/SRB2Updater/Resources/Srb2win.ico b/tools/SRB2Updater/Resources/Srb2win.ico deleted file mode 100644 index 0036a827a..000000000 Binary files a/tools/SRB2Updater/Resources/Srb2win.ico and /dev/null differ diff --git a/tools/SRB2Updater/Resources/sonic_bottom.png b/tools/SRB2Updater/Resources/sonic_bottom.png deleted file mode 100644 index 42c17c785..000000000 Binary files a/tools/SRB2Updater/Resources/sonic_bottom.png and /dev/null differ diff --git a/tools/SRB2Updater/Resources/sonic_top.png b/tools/SRB2Updater/Resources/sonic_top.png deleted file mode 100644 index 66d6fccaa..000000000 Binary files a/tools/SRB2Updater/Resources/sonic_top.png and /dev/null differ diff --git a/tools/SRB2Updater/Resources/updaterbanner.png b/tools/SRB2Updater/Resources/updaterbanner.png deleted file mode 100644 index 9a2f6fa38..000000000 Binary files a/tools/SRB2Updater/Resources/updaterbanner.png and /dev/null differ diff --git a/tools/SRB2Updater/SRB2Updater.csproj b/tools/SRB2Updater/SRB2Updater.csproj deleted file mode 100644 index 6e8647312..000000000 --- a/tools/SRB2Updater/SRB2Updater.csproj +++ /dev/null @@ -1,173 +0,0 @@ - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {2E2F67C6-8492-4034-A142-50872504D86D} - WinExe - Properties - SRB2Updater - srb2update - - - - - 2.0 - v2.0 - - - false - Srb2win.ico - SRB2Updater.Program - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - Form - - - Debug.cs - - - Form - - - Launcher.cs - - - - Form - - - Options.cs - - - - - Debug.cs - Designer - - - Launcher.cs - Designer - - - Options.cs - Designer - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - False - .NET Framework Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/SRB2Updater/SRB2Updater.sln b/tools/SRB2Updater/SRB2Updater.sln deleted file mode 100644 index f4e88dc64..000000000 --- a/tools/SRB2Updater/SRB2Updater.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SRB2Updater", "SRB2Updater.csproj", "{2E2F67C6-8492-4034-A142-50872504D86D}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2E2F67C6-8492-4034-A142-50872504D86D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E2F67C6-8492-4034-A142-50872504D86D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E2F67C6-8492-4034-A142-50872504D86D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E2F67C6-8492-4034-A142-50872504D86D}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/tools/SRB2Updater/ServerQuerier.cs b/tools/SRB2Updater/ServerQuerier.cs deleted file mode 100644 index 51b6940f6..000000000 --- a/tools/SRB2Updater/ServerQuerier.cs +++ /dev/null @@ -1,362 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Net; -using System.Net.Sockets; -using System.IO; - -namespace SRB2Updater -{ - class ServerQuerier - { - private UdpClient udpclient; - private IPEndPoint ipepMS; - - private const int MS_HOLEPUNCH_SIZE = 0; - private const int PT_ASKINFO_SIZE = 16; - private const byte PT_ASKINFO = 12; - private const byte PT_SERVERINFO = 13; - private const int MAXSERVERNAME = 32; - private const int MAX_WADPATH = 128; - - /// - /// Constructs a ServerQuerier object. - /// - public ServerQuerier() - { - udpclient = new UdpClient(0, AddressFamily.InterNetwork); - - // Fix for WSAECONNRESET. Only affects Win2k and up. If I send a - // packet to a host which replies with an ICMP Port Unreachable, - // subsequent socket operations go doo-lally. So, we enable the - // older behaviour of ignoring these ICMP messages, since we don't - // care about them anyway. - if (Environment.OSVersion.Platform == PlatformID.Win32NT && - Environment.OSVersion.Version.Major >= 5) - { - const uint IOC_IN = 0x80000000; - const uint IOC_VENDOR = 0x18000000; - const uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; - - udpclient.Client.IOControl(unchecked((int)SIO_UDP_CONNRESET), new byte[] { Convert.ToByte(false) }, null); - } - } - - public void StartListening(ServerInfoReceiveHandler sirh) - { - // Start listening. - udpclient.BeginReceive(new AsyncCallback(ServerInfoReceiveHandler.Receive), sirh); - } - - - /// - /// Sets the master server address. Necessary before querying via the MS. - /// - /// IP address of hostname of MS. - /// Port of MS. - public void SetMasterServer(string strAddress, ushort unPort) - { - IPAddress address = Dns.GetHostEntry(strAddress).AddressList[0]; - ipepMS = new IPEndPoint(address, unPort); - } - - public void Query(string strAddress, ushort unPort) - { - // Build the packet. - byte[] byPacket = new byte[PT_ASKINFO_SIZE]; - BinaryWriter bw = new BinaryWriter(new MemoryStream(byPacket)); - - bw.Seek(4, SeekOrigin.Begin); // Skip the checksum. - bw.Write((byte)0); // ack - bw.Write((byte)0); // ackreturn - bw.Write((byte)PT_ASKINFO); // Packet type. - bw.Write((byte)0); // Reserved. - bw.Write((byte)0); // Version. This is actually unnecessary -- the client will reply anyway. -MattW_CFI - bw.Write((byte)0); // Reserved. - bw.Write((byte)0); // Reserved. - bw.Write((byte)0); // Reserved. - // Time for ping calculation. - bw.Write(unchecked((uint)(DateTime.Now.Ticks / 10000))); - - // Calculate the checksum. - bw.Seek(0, SeekOrigin.Begin); - bw.Write(SRB2Checksum(byPacket)); - - // Send the packet. - udpclient.Send(byPacket, byPacket.Length, strAddress, unPort); - } - - /// - /// Calculates the checksum of an SRB2 packet. - /// - /// Packet. - /// Checksum. - private static uint SRB2Checksum(byte[] byPacket) - { - uint c = 0x1234567; - int i; - - for (i = 4; i < byPacket.Length; i++) - unchecked - { - c += (uint)byPacket[i] * (uint)(i - 3); - } - - return c; - } - - private static string ReadFixedLengthStr(BinaryReader br, int iLen) - { - String str = Encoding.ASCII.GetString(br.ReadBytes(iLen)); - int iPos = str.IndexOf("\0"); - if (iPos >= 0) - str = str.Remove(iPos); - - return str; - } - - public abstract class ServerInfoReceiveHandler - { - UdpClient udpclient; - IPEndPoint ipepRemote; - - /// - /// Called after a server info packet is received. - /// - /// Server info. - public abstract void ProcessServerInfo(SRB2ServerInfo srb2si); - public abstract void HandleException(Exception e); - - public ServerInfoReceiveHandler(ServerQuerier sq) - { - ipepRemote = new IPEndPoint(IPAddress.Any, 0); - - udpclient = sq.udpclient; - } - - public static void Receive(IAsyncResult ar) - { - ServerInfoReceiveHandler sirh = (ServerInfoReceiveHandler)ar.AsyncState; - - byte[] byPacket = sirh.udpclient.EndReceive(ar, ref sirh.ipepRemote); - - // Analyse the packet. - BinaryReader br = new BinaryReader(new MemoryStream(byPacket)); - - // Get the checksum. - uint uiChecksum = br.ReadUInt32(); - - // Skip ack and ackreturn and get packet type. - br.ReadBytes(2); - byte byPacketType = br.ReadByte(); - - // Only interested in valid PT_SERVERINFO packets. - if (byPacketType == PT_SERVERINFO && uiChecksum == SRB2Checksum(byPacket)) - { - bool bMalformed = true; - - // Skip padding. - br.ReadByte(); - - // Remember where we are. - long iPacketStart = br.BaseStream.Position; - - // Try to interpret the packet in each recognised format. - foreach (ServerInfoVer siv in Enum.GetValues(typeof(ServerInfoVer))) - { - SRB2ServerInfo srb2si; - byte byNumWads = 0; - - srb2si.siv = siv; - - br.BaseStream.Position = iPacketStart; - - // Get address from socket. - srb2si.strAddress = sirh.ipepRemote.Address.ToString(); - srb2si.unPort = unchecked((ushort)sirh.ipepRemote.Port); - - // Get version. - byte byVersion = br.ReadByte(); - - if (siv == ServerInfoVer.SIV_PREME) - { - br.ReadBytes(3); - - uint uiSubVersion = br.ReadUInt32(); - - // Format version. - // MattW_CFI: I hope you don't mind this exception, Oogaland, but 0.01.6 looks odd >_> - if (byVersion == 1 && uiSubVersion == 6) - srb2si.strVersion = "X.01.6"; - else - srb2si.strVersion = byVersion.ToString(); - //srb2si.strVersion = String.Format("{0}.{1:00}.{2}", byVersion / 100, byVersion % 100, uiSubVersion); - } - else - { - byte bySubVersion = br.ReadByte(); - - // Format version. - //srb2si.strVersion = String.Format("{0}.{1:00}.{2}", byVersion / 100, byVersion % 100, bySubVersion); - srb2si.strVersion = byVersion.ToString(); - } - - srb2si.byPlayers = br.ReadByte(); - srb2si.byMaxplayers = br.ReadByte(); - srb2si.byGametype = br.ReadByte(); - srb2si.bModified = (br.ReadByte() != 0); - - if (siv == ServerInfoVer.SIV_ME) - byNumWads = br.ReadByte(); - - srb2si.sbyAdminplayer = br.ReadSByte(); - - if (siv == ServerInfoVer.SIV_PREME) - br.ReadBytes(3); - - // Calculate ping. - srb2si.uiTime = unchecked((uint)((long)(DateTime.Now.Ticks / 10000 - br.ReadUInt32()) % ((long)UInt32.MaxValue + 1))); - - if (siv == ServerInfoVer.SIV_PREME) - br.ReadUInt32(); - - // Get and tidy map name. - if (siv == ServerInfoVer.SIV_PREME) - { - srb2si.strMapName = ReadFixedLengthStr(br, 8); - srb2si.strName = ReadFixedLengthStr(br, MAXSERVERNAME); - } - else - { - srb2si.strName = ReadFixedLengthStr(br, MAXSERVERNAME); - srb2si.strMapName = ReadFixedLengthStr(br, 8); - } - - if (siv == ServerInfoVer.SIV_PREME) - byNumWads = br.ReadByte(); - - // Create new list of strings of initial size equal to number of wads. - srb2si.listFiles = new List(byNumWads); - - // Get the files info. - byte[] byFiles = br.ReadBytes(siv == ServerInfoVer.SIV_PREME ? 4096 : 936); - BinaryReader brFiles = new BinaryReader(new MemoryStream(byFiles)); - - // Extract the filenames. - try - { - for (int i = 0; i < byNumWads; i++) - { - bool bFullString = false; - AddedWad aw = new AddedWad(); - - if (siv == ServerInfoVer.SIV_PREME) - { - aw.bImportant = brFiles.ReadByte() != 0; - aw.downloadtype = (DownloadTypes)brFiles.ReadByte(); - } - else - { - byte byFileStatus = brFiles.ReadByte(); - aw.bImportant = (byFileStatus & 0xF) != 0; - aw.downloadtype = (DownloadTypes)(byFileStatus >> 4); - } - - aw.uiSize = brFiles.ReadUInt32(); - - // Work out how long the string is. - int iStringPos = (int)brFiles.BaseStream.Position; - while (iStringPos < byFiles.Length && byFiles[iStringPos] != 0) iStringPos++; - - // Make sure it's not longer than the max name length. - if (iStringPos - (int)brFiles.BaseStream.Position > MAX_WADPATH) - { - bFullString = true; - iStringPos = MAX_WADPATH + (int)brFiles.BaseStream.Position; - } - - // Get the info and add it, if possible. - if (iStringPos > (int)brFiles.BaseStream.Position) - { - aw.strFilename = Encoding.ASCII.GetString(brFiles.ReadBytes(iStringPos - (int)brFiles.BaseStream.Position)); - srb2si.listFiles.Add(aw); - } - - // Skip nul. - if (!bFullString) brFiles.ReadByte(); - - // Skip the md5sum. - brFiles.ReadBytes(16); - } - - // Okay, done! Do something useful with the server info. - sirh.ProcessServerInfo(srb2si); - - // If we got this far without an exception, leave the foreach loop. - bMalformed = false; - break; - } - catch (EndOfStreamException) - { - // Packet doesn't match supposed type, so we swallow the exception - // and try remaining types. - } - catch (Exception e) - { - sirh.HandleException(e); - break; - } - } - - if (bMalformed) - sirh.HandleException(new Exception("Received invalid PT_SERVERINFO packet from " + sirh.ipepRemote.Address + ":" + sirh.ipepRemote.Port + ".")); - } - - // Resume listening. - sirh.ipepRemote = new IPEndPoint(IPAddress.Any, 0); - sirh.udpclient.BeginReceive(new AsyncCallback(Receive), sirh); - } - } - - public enum DownloadTypes - { - DT_TOOBIG = 0, - DT_OK = 1, - DT_DISABLED = 2 - } - - public struct AddedWad - { - public string strFilename; - public bool bImportant; - public uint uiSize; - public DownloadTypes downloadtype; - } - - public enum ServerInfoVer - { - SIV_PREME, - SIV_ME - }; - - public struct SRB2ServerInfo - { - public string strAddress; - public ushort unPort; - - public ServerInfoVer siv; - - public string strVersion; - public byte byPlayers; - public byte byMaxplayers; - public byte byGametype; - public bool bModified; - public sbyte sbyAdminplayer; - public uint uiTime; - public string strMapName; - public string strName; - - public List listFiles; - } - } -} diff --git a/tools/SRB2Updater/Settings.cs b/tools/SRB2Updater/Settings.cs deleted file mode 100644 index d72aeee51..000000000 --- a/tools/SRB2Updater/Settings.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections; -using System.Text; -using System.Data; -using Microsoft.Win32; -using System.Windows.Forms; -using System.IO; - -namespace SRB2Updater -{ - public class Settings - { - // Global Settings - public bool boolDisplayWindowed; - public bool boolDisplayCustomResolution; - public bool boolCloseOnStart; - public int intDisplayWidth; - public int intDisplayHeight; - public string strMSAddress; - public int intMSPort; - public Array arrWadList; - public string strParams; - - public string Params - { - get { return strParams; } - set { strParams = value; } - } - - public Array wadList - { - get { return arrWadList; } - set { arrWadList = value; } - } - - public bool CloseOnStart - { - get { return boolCloseOnStart; } - set { boolCloseOnStart = value; } - } - - public string msAddress - { - get { return strMSAddress; } - set { strMSAddress = value; } - } - - public int msPort - { - get { return intMSPort; } - set { intMSPort = value; } - } - - public bool displayWindowed - { - get { return boolDisplayWindowed; } - set { boolDisplayWindowed = value; } - } - - public bool displayCustom - { - get { return boolDisplayCustomResolution; } - set { boolDisplayCustomResolution = value; } - } - - public int displayWidth - { - get { return intDisplayWidth; } - set { intDisplayWidth = value; } - } - - public int displayHeight - { - get { return intDisplayHeight; } - set { intDisplayHeight = value; } - } - - bool boolShowDefaultWads; - public bool ShowDefaultWads - { - get { return boolShowDefaultWads; } - set { boolShowDefaultWads = value; } - } - - public void GetSettings() - { - RegistryKey rk = Registry.CurrentUser.CreateSubKey(@"Software\SonicTeamJunior\Launcher"); - RegistryKey rkDisplay = Registry.CurrentUser.CreateSubKey(@"Software\SonicTeamJunior\Launcher\Display"); - RegistryKey rkMS = Registry.CurrentUser.CreateSubKey(@"Software\SonicTeamJunior\Launcher\MasterServer"); - RegistryKey rkBinaries = rk.CreateSubKey("Binaries"); - rkBinaries.SetValue("2.0.4", Directory.GetCurrentDirectory() + "\\srb2win.exe"); - - try { boolDisplayCustomResolution = Convert.ToInt32(rkDisplay.GetValue("CustomResolution", 0)) != 0; } - catch { boolDisplayCustomResolution = false; } - try { boolDisplayWindowed = Convert.ToInt32(rkDisplay.GetValue("Windowed", 0)) != 0; } - catch { boolDisplayWindowed = false; } - try { boolShowDefaultWads = Convert.ToInt32(rkDisplay.GetValue("ShowDefaultWads", 0)) != 0; } - catch { boolShowDefaultWads = false; } - try { boolCloseOnStart = Convert.ToInt32(rkDisplay.GetValue("CloseOnStart", 0)) != 0; } - catch { boolCloseOnStart = false; } - intDisplayHeight = Convert.ToInt32(rkDisplay.GetValue("Height", "480")); - intDisplayWidth = Convert.ToInt32(rkDisplay.GetValue("Width", "640")); - intMSPort = Convert.ToInt32(rkMS.GetValue("Port", "28900")); - strMSAddress = Convert.ToString(rkMS.GetValue("Address", "ms.srb2.org")); - strParams = Convert.ToString(rk.GetValue("Params")); - - dicBinaries.Clear(); - foreach (string strName in rkBinaries.GetValueNames()) - dicBinaries[strName] = (string)rkBinaries.GetValue(strName); - - - rk.Close(); - rkDisplay.Close(); - rkMS.Close(); - rkBinaries.Close(); - } - - public void SaveSettings() - { - RegistryKey rk = Registry.CurrentUser.CreateSubKey(@"Software\SonicTeamJunior\Launcher"); - RegistryKey rkDisplay = rk.CreateSubKey("Display"); - RegistryKey rkMS = rk.CreateSubKey("MasterServer"); - rkDisplay.SetValue("CustomResolution", boolDisplayCustomResolution); - rkDisplay.SetValue("Windowed", boolDisplayWindowed); - rkDisplay.SetValue("Height", intDisplayHeight); - rkDisplay.SetValue("Width", intDisplayWidth); - rkMS.SetValue("Port", intMSPort); - rkMS.SetValue("Address", strMSAddress); - rkMS.SetValue("ShowDefaultWads", boolShowDefaultWads); - rk.SetValue("Params", strParams); - rk.SetValue("CloseOnStart", boolCloseOnStart); - - rk.DeleteSubKey("Binaries", false); - RegistryKey rkBinaries = rk.CreateSubKey("Binaries"); - rkBinaries.SetValue("2.0.4", Directory.GetCurrentDirectory() + "\\srb2win.exe"); - foreach (string strName in dicBinaries.Keys) - rkBinaries.SetValue(strName, dicBinaries[strName]); - - rk.Close(); - } - -/* public void WriteToRegistry() - { - RegistryKey rk = Registry.CurrentUser.CreateSubKey(@"Software\SRB2MSLauncher"); - - rk.SetValue("Params", strParams); - rk.SetValue("Masterserver", strMSAddress); - rk.SetValue("MSPort", unMSPort, RegistryValueKind.DWord); - rk.SetValue("ShowDefaultWads", Convert.ToInt32(bShowDefaultWads), RegistryValueKind.DWord); - - rk.DeleteSubKey("Binaries", false); - RegistryKey rkBinaries = rk.CreateSubKey("Binaries"); - foreach (string strName in dicBinaries.Keys) - rkBinaries.SetValue(strName, dicBinaries[strName]); - - rkBinaries.Close(); - rk.Close(); - } - - public void LoadFromRegistry() - { - RegistryKey rk = Registry.CurrentUser.CreateSubKey(@"Software\SRB2MSLauncher"); - RegistryKey rkBinaries = rk.CreateSubKey("Binaries"); - - strParams = (string)rk.GetValue("Params", ""); - strMSAddress = (string)rk.GetValue("Masterserver", "ms.srb2.org"); - - try { unMSPort = Convert.ToUInt16(rk.GetValue("MSPort", MS_DEFAULT_PORT)); } - catch { unMSPort = MS_DEFAULT_PORT; } - - try { bShowDefaultWads = Convert.ToInt32(rk.GetValue("ShowDefaultWads", 0)) != 0; } - catch { bShowDefaultWads = true; } - - dicBinaries.Clear(); - foreach (string strName in rkBinaries.GetValueNames()) - dicBinaries[strName] = (string)rkBinaries.GetValue(strName); - - rkBinaries.Close(); - rk.Close(); - }*/ - - - public List VersionStrings - { - get { return new List(dicBinaries.Keys); } - } - - public bool HasBinaryForVersion(string strVersion) - { - return dicBinaries.ContainsKey(strVersion) && dicBinaries[strVersion] != ""; - } - - public void AddBinariesToListView(ListView lv) - { - foreach (string strName in dicBinaries.Keys) - lv.Items.Add(new ListViewItem(new string[] { strName, dicBinaries[strName] })); - } - - public void SetBinariesFromListView(ListView lv) - { - dicBinaries.Clear(); - foreach (ListViewItem lvi in lv.Items) - dicBinaries[lvi.Text] = lvi.SubItems[1].Text; - } - - Dictionary dicBinaries = new Dictionary(); - - public void SetBinary(string strVersion, string strBinary) - { - dicBinaries[strVersion] = strBinary; - } - - public string GetBinary(string strVersion) - { - return dicBinaries[strVersion]; - } - } -} \ No newline at end of file diff --git a/tools/SRB2Updater/app.config b/tools/SRB2Updater/app.config deleted file mode 100644 index b7db28170..000000000 --- a/tools/SRB2Updater/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tools/djgpp/all313.dif b/tools/djgpp/all313.dif deleted file mode 100644 index cdecf7d84..000000000 --- a/tools/djgpp/all313.dif +++ /dev/null @@ -1,812 +0,0 @@ -diff -ruN allegro.312/demo/alld/tmp.txt allegro.313/demo/alld/tmp.txt ---- allegro.312/demo/alld/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/demo/alld/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/demo/alleg/tmp.txt allegro.313/demo/alleg/tmp.txt ---- allegro.312/demo/alleg/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/demo/alleg/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/demo/allp/tmp.txt allegro.313/demo/allp/tmp.txt ---- allegro.312/demo/allp/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/demo/allp/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/examples/alld/tmp.txt allegro.313/examples/alld/tmp.txt ---- allegro.312/examples/alld/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/examples/alld/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/examples/alleg/tmp.txt allegro.313/examples/alleg/tmp.txt ---- allegro.312/examples/alleg/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/examples/alleg/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/examples/allp/tmp.txt allegro.313/examples/allp/tmp.txt ---- allegro.312/examples/allp/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/examples/allp/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/makefile allegro.313/makefile ---- allegro.312/makefile Sun Feb 21 00:31:48 1999 -+++ allegro.313/makefile Mon Jun 20 23:45:18 2005 -@@ -7,8 +7,10 @@ - # # - ################################################# - --# replace this definition if you are using PGCC --# PGCC=1 -+# remline this definition if need Allegro for 486 -+PGCC=1 -+ -+GCC=gcc-2 - - .PHONY: baddjgpp baddjdev badgcc badbnu badmake badtxi badpath badalleg - -@@ -22,23 +24,25 @@ - # check that the djdev package is installed - ifeq ($(wildcard $(DJDIR)/bin/djasm.exe),) - baddjdev: -- @echo Missing djgpp package! You need to install djdev201.zip (or whatever the -+ @echo Missing djgpp package! You need to install djdev203.zip (or whatever the - @echo latest version is). Download this from wherever you got djgpp, and unzip - @echo it into the root of your djgpp directory. - endif - - # check that the gcc package is installed --ifeq ($(wildcard $(DJDIR)/bin/gcc.exe),) -+ifeq ($(wildcard $(DJDIR)/bin/$(GCC).exe),) - badgcc: -- @echo Missing djgpp package! You need to install gcc2721b.zip (or whatever the -- @echo latest version is). Download this from wherever you got djgpp, and unzip -- @echo it into the root of your djgpp directory. -+ @echo Missing djgpp package! You need to install gcc2953b.zip. Download this -+ @echo from wherever you got djgpp, and unzip bin\gcc.exe , rename it as -+ @echo $(GCC).exe into the of your bin directory. - endif - -+GCC := @$(GCC) -+ - # check that the binutils package is installed - ifeq ($(wildcard $(DJDIR)/bin/ld.exe),) - badbnu: -- @echo Missing djgpp package! You need to install bnu27b.zip (or whatever the -+ @echo Missing djgpp package! You need to install bnu216b.zip (or whatever the - @echo latest version is). Download this from wherever you got djgpp, and unzip - @echo it into the root of your djgpp directory. - endif -@@ -46,7 +50,7 @@ - # check that the make package is installed - ifeq ($(wildcard $(DJDIR)/bin/make.exe),) - badmake: -- @echo Missing djgpp package! You need to install mak3761b.zip (or whatever the -+ @echo Missing djgpp package! You need to install mak3791b.zip (or whatever the - @echo latest version is). Download this from wherever you got djgpp, and unzip - @echo it into the root of your djgpp directory. - endif -@@ -54,7 +58,7 @@ - # check that the texinfo package is installed - ifeq ($(wildcard $(DJDIR)/bin/makeinfo.exe),) - badtxi: -- @echo Missing djgpp package! You need to install txi390b.zip (or whatever the -+ @echo Missing djgpp package! You need to install txi48b.zip (or whatever the - @echo latest version is). Download this from wherever you got djgpp, and unzip - @echo it into the root of your djgpp directory. If you do not need the Info - @echo documentation, run make all to ignore this error. -@@ -83,11 +87,32 @@ - endif - endif - -+# -------- check environment to see what type of library to build -------- -+ -+ifdef DEBUGMODE -+ -+# -------- build a debugging library -------- -+VERSION = alld -+ -+else -+ifdef PROFILEMODE -+ -+# -------- build a profiling library -------- -+VERSION = allp -+ -+else -+ -+# -------- build a release library -------- -+VERSION = alleg -+ -+endif -+endif -+ -+ - # set some useful paths --OBJ = obj/djgpp --DOBJ = obj\djgpp --LIB = lib/djgpp/liballeg.a --LIBDEST = $(DJDIR)/lib/liballeg.a -+LIB = lib$(VERSION).a -+OBJ = obj/djgpp/$(VERSION) -+LIBDEST = $(DJDIR)/lib/$(LIB) - INCDEST = $(DJDIR)/include/allegro.h - DOCDEST = $(DJDIR)/info/allegro.inf - INTERNAL_H = src/internal.h src/djgpp/interndj.h -@@ -113,19 +138,22 @@ - else - ifdef PROFILEMODE - # build with profiling information -+OFLAGS = -pg -O3 -ffast-math - ifdef PGCC --OFLAGS = -pg -mpentium -O6 -ffast-math -+OFLAGS := $(OFLAGS) -mcpu=pentium - else --OFLAGS = -pg -m486 -O3 -ffast-math -+OFLAGS := $(OFLAGS) -mcpu=i486 - endif - LFLAGS = -pg - -+ - else - # build a normal optimised version -+OFLAGS = -O3 -ffast-math -fomit-frame-pointer - ifdef PGCC --OFLAGS = -mpentium -O6 -ffast-math -fomit-frame-pointer -+OFLAGS := $(OFLAGS) -mcpu=pentium - else --OFLAGS = -m486 -O3 -ffast-math -fomit-frame-pointer -+OFLAGS := $(OFLAGS) -mcpu=i486 - endif - - ifdef SYMBOLMODE -@@ -179,9 +207,18 @@ - - .PHONY: all msg lib install uninstall docs clean veryclean mmxtest $(PROGRAMS) - --all: msg $(LIB) $(PROGRAMS) docs install -+all: msg lib/djgpp/$(LIB) $(PROGRAMS) docs - @echo All done. -- @echo To use Allegro, #include allegro.h and link with liballeg.a -+ifdef DEBUGMODE -+ @echo To install this version of Allegro, run make install DEBUGMODE=1 -+else -+ifdef PROFILEMODE -+ @echo To install this version of Allegro, run make install PROFILEMODE=1 -+else -+ @echo To install this version of Allegro, run make install -+endif -+endif -+ @echo To use Allegro, #include allegro.h and link with $(LIB) - @echo Example command line: gcc foobar.c -o foobar.exe -lalleg - @echo Run make compress to run DJP or UPX on the executable files - @echo Enjoy! -@@ -189,36 +226,36 @@ - msg: - @echo Compiling Allegro. Please wait... - --lib: $(LIB) -+lib: lib/djgpp/$(LIB) - - install: $(LIBDEST) $(INCDEST) $(DOCDEST) - - docs: $(DOCS) - --$(LIBDEST): $(LIB) -- copy lib\djgpp\liballeg.a $(subst /,\,$(LIBDEST)) -+$(LIBDEST): lib/djgpp/$(LIB) -+ cp lib/djgpp/$(LIB) $(LIBDEST) - - $(INCDEST): allegro.h -- copy allegro.h $(subst /,\,$(INCDEST)) -+ cp allegro.h $(INCDEST) - - $(DOCDEST): docs/allegro.inf - ifneq ($(wildcard $(DJDIR)/bin/makeinfo.exe),) -- copy docs\allegro.inf $(subst /,\,$(DOCDEST)) -+ cp docs\allegro.inf $(DOCDEST) - else - @echo makeinfo not installed: skipping copy of allegro.inf - endif - - $(OBJ)/%.o: %.c allegro.h -- gcc $(CFLAGS) -o $@ -c $< -+ $(GCC) $(CFLAGS) -o $@ -c $< - - $(OBJ)/%.o: %.S asmdefs.inc $(OBJ)/asmdef.inc -- gcc $(SFLAGS) -o $@ -c $< -+ $(GCC) $(SFLAGS) -o $@ -c $< - - $(OBJ)/%.o: %.s asmdefs.inc $(OBJ)/asmdef.inc -- gcc -x assembler-with-cpp $(SFLAGS) -o $@ -c $< -+ $(GCC) -x assembler-with-cpp $(SFLAGS) -o $@ -c $< - --*/%.exe: $(OBJ)/%.o $(LIB) -- gcc $(LFLAGS) -o $@ $< $(LIB) -+*/$(VERSION)/%.exe: $(OBJ)/%.o lib/djgpp/$(LIB) -+ $(GCC) $(LFLAGS) -o $@ $< lib/djgpp/$(LIB) - - docs/%.inf: docs/%.txi - ifneq ($(wildcard $(DJDIR)/bin/makeinfo.exe),) -@@ -252,38 +289,38 @@ - $(OBJ)/makedoc.exe -part -ascii THANKS docs/thanks._tx - - $(OBJ)/makedoc.exe: docs/makedoc.c -- gcc $(CFLAGS) $(LFLAGS) -o $@ docs/makedoc.c -+ $(GCC) $(CFLAGS) $(LFLAGS) -o $@ docs/makedoc.c - - $(OBJ)/asmdef.inc: $(OBJ)/asmdef.exe - $(OBJ)/asmdef.exe $(OBJ)/asmdef.inc - - $(OBJ)/asmdef.exe: src/asmdef.c allegro.h $(INTERNAL_H) -- gcc $(CFLAGS) $(LFLAGS) -o $@ src/asmdef.c -+ $(GCC) $(CFLAGS) $(LFLAGS) -o $@ src/asmdef.c - - mmxtest: -- @echo // no MMX > $(DOBJ)\mmx.h -- @echo .text > $(DOBJ)\mmxtest.s -- @echo emms >> $(DOBJ)\mmxtest.s -- @gcc -c $(OBJ)/mmxtest.s -o $(OBJ)/mmxtest.o -- @echo #define ALLEGRO_MMX > $(DOBJ)\mmx.h -+ @echo // no MMX > $(subst /,\,$(OBJ))\mmx.h -+ @echo .text > $(subst /,\,$(OBJ))\mmxtest.s -+ @echo emms >> $(subst /,\,$(OBJ))\mmxtest.s -+ @$(GCC) -c $(OBJ)/mmxtest.s -o $(OBJ)/mmxtest.o -+ @echo #define ALLEGRO_MMX > $(subst /,\,$(OBJ))\mmx.h - @echo Your assembler supports MMX instructions! - - $(OBJ)/mmx.h: - @echo Testing for MMX assembler support... - -$(MAKE) mmxtest - --$(OBJ)/setupdat.s $(OBJ)/setupdat.h: setup/setup.dat tools/dat2s.exe -- tools/dat2s.exe setup/setup.dat -o $(OBJ)/setupdat.s -h $(OBJ)/setupdat.h -+$(OBJ)/setupdat.s $(OBJ)/setupdat.h: setup/setup.dat tools/$(VERSION)/dat2s.exe -+ tools/$(VERSION)/dat2s.exe setup/setup.dat -o $(OBJ)/setupdat.s -h $(OBJ)/setupdat.h - - $(OBJ)/setupdat.o: $(OBJ)/setupdat.s -- gcc $(SFLAGS) -o $(OBJ)/setupdat.o -c $(OBJ)/setupdat.s -+ $(GCC) $(SFLAGS) -o $(OBJ)/setupdat.o -c $(OBJ)/setupdat.s - --setup/setup.exe: $(OBJ)/setup.o $(OBJ)/setupdat.o $(LIB) -- gcc $(LFLAGS) -o setup/setup.exe $(OBJ)/setup.o $(OBJ)/setupdat.o $(LIB) -+setup/$(VERSION)/setup.exe: $(OBJ)/setup.o $(OBJ)/setupdat.o lib/djgpp/$(LIB) -+ $(GCC) $(LFLAGS) -o setup/$(VERSION)/setup.exe $(OBJ)/setup.o $(OBJ)/setupdat.o lib/djgpp/$(LIB) - ifndef DEBUGMODE - ifndef SYMBOLMODE - ifneq ($(DJP),) -- $(DJP) setup/setup.exe -+ $(DJP) setup/$(VERSION)/setup.exe - endif - endif - endif -@@ -301,79 +338,79 @@ - endif - - $(OBJ)/plugins.h: $(wildcard tools/plugins/*.inc) -- copy tools\plugins\*.inc $(DOBJ)\plugins.h -+ cat tools/plugins/*.inc > $(OBJ)/plugins.h - --tools/dat.exe: $(OBJ)/dat.o $(DATEDIT_DEPS) $(LIB) -- gcc $(LFLAGS) -o tools/dat.exe $(OBJ)/dat.o $(DATEDIT_LINK) $(LIB) -+tools/$(VERSION)/dat.exe: $(OBJ)/dat.o $(DATEDIT_DEPS) lib/djgpp/$(LIB) -+ $(GCC) $(LFLAGS) -o tools/$(VERSION)/dat.exe $(OBJ)/dat.o $(DATEDIT_LINK) lib/djgpp/$(LIB) - --tools/dat2s.exe: $(OBJ)/dat2s.o $(DATEDIT_DEPS) $(LIB) -- gcc $(LFLAGS) -o tools/dat2s.exe $(OBJ)/dat2s.o $(DATEDIT_LINK) $(LIB) -+tools/$(VERSION)/dat2s.exe: $(OBJ)/dat2s.o $(DATEDIT_DEPS) lib/djgpp/$(LIB) -+ $(GCC) $(LFLAGS) -o tools/$(VERSION)/dat2s.exe $(OBJ)/dat2s.o $(DATEDIT_LINK) lib/djgpp/$(LIB) - --tools/grabber.exe: $(OBJ)/grabber.o $(DATEDIT_DEPS) $(LIB) -- gcc $(LFLAGS) -o tools/grabber.exe $(OBJ)/grabber.o $(DATEDIT_LINK) $(LIB) -+tools/$(VERSION)/grabber.exe: $(OBJ)/grabber.o $(DATEDIT_DEPS) lib/djgpp/$(LIB) -+ $(GCC) $(LFLAGS) -o tools/$(VERSION)/grabber.exe $(OBJ)/grabber.o $(DATEDIT_LINK) lib/djgpp/$(LIB) - --tools/pat2dat.exe: $(OBJ)/pat2dat.o $(DATEDIT_DEPS) $(LIB) -- gcc $(LFLAGS) -o tools/pat2dat.exe $(OBJ)/pat2dat.o $(DATEDIT_LINK) $(LIB) -+tools/$(VERSION)/pat2dat.exe: $(OBJ)/pat2dat.o $(DATEDIT_DEPS) lib/djgpp/$(LIB) -+ $(GCC) $(LFLAGS) -o tools/$(VERSION)/pat2dat.exe $(OBJ)/pat2dat.o $(DATEDIT_LINK) lib/djgpp/$(LIB) - --$(LIB): $(LIB_OBJS) -- ar rs $(LIB) $(LIB_OBJS) -+lib/djgpp/$(LIB): $(LIB_OBJS) -+ ar rs lib/djgpp/$(LIB) $(LIB_OBJS) - - compress: $(PROGRAMS) - ifneq ($(DJP),) -- $(DJP) demo/*.exe examples/*.exe tests/*.exe tools/*.exe setup/keyconf.exe obj/djgpp/*.exe -+ $(DJP) demo/$(VERSION)/*.exe examples/$(VERSION)/*.exe tests/$(VERSION)/*.exe tools/$(VERSION)/*.exe setup/$(VERSION)/keyconf.exe $(OBJ)*.exe - else - @echo No executable compressor found! This target requires either the - @echo DJP or UPX utilities to be installed in your djgpp bin directory. - endif - - clean: -- -rm -v obj/djgpp/*.* lib/djgpp/*.* docs/*.$(HTML) docs/*.txi docs/*.inf docs/*.rtf -+ -rm -f -v $(OBJ)/*.* lib/djgpp/*.* docs/*.$(HTML) docs/*.txi docs/*.inf docs/*.rtf - - veryclean: clean -- -rm -v allegro.txt AUTHORS CHANGES faq.txt help.txt NEWS THANKS \ -- demo/*.exe examples/*.exe setup/*.exe tests/*.exe tools/*.exe -+ -rm -f -v allegro.txt AUTHORS CHANGES faq.txt help.txt NEWS THANKS \ -+ demo/$(VERSION)/*.exe examples/$(VERSION)/*.exe setup/$(VERSION)/*.exe tests/$(VERSION)/*.exe tools/$(VERSION)/*.exe - - uninstall: -- -rm $(LIBDEST) -- -rm $(INCDEST) -- -rm $(DOCDEST) -+ -rm -f $(LIBDEST) -+ -rm -f $(INCDEST) -+ -rm -f $(DOCDEST) - @echo All gone! (sulk) - --demo: demo/demo.exe --keyconf: setup/keyconf.exe --setup: setup/setup.exe --afinfo: tests/afinfo.exe --akaitest: tests/akaitest.exe --digitest: tests/digitest.exe --mathtest: tests/mathtest.exe --miditest: tests/miditest.exe --play: tests/play.exe --playfli: tests/playfli.exe --test: tests/test.exe --vesainfo: tests/vesainfo.exe --colormap: tools/colormap.exe --dat: tools/dat.exe --dat2s: tools/dat2s.exe --exedat: tools/exedat.exe --grabber: tools/grabber.exe --pack: tools/pack.exe --pat2dat: tools/pat2dat.exe --rgbmap: tools/rgbmap.exe -- --examples: examples/ex1.exe examples/ex2.exe examples/ex3.exe \ -- examples/ex4.exe examples/ex5.exe examples/ex6.exe \ -- examples/ex7.exe examples/ex8.exe examples/ex9.exe \ -- examples/ex10.exe examples/ex11.exe examples/ex12.exe \ -- examples/ex13.exe examples/ex14.exe examples/ex15.exe \ -- examples/ex16.exe examples/ex17.exe examples/ex18.exe \ -- examples/ex19.exe examples/ex20.exe examples/ex21.exe \ -- examples/ex22.exe examples/ex23.exe examples/ex24.exe \ -- examples/ex25.exe examples/ex26.exe examples/ex27.exe \ -- examples/ex28.exe examples/ex29.exe examples/ex30.exe \ -- examples/ex31.exe examples/ex32.exe examples/ex33.exe \ -- examples/ex34.exe examples/ex35.exe examples/ex36.exe \ -- examples/ex37.exe examples/ex38.exe examples/ex39.exe \ -- examples/ex40.exe -+demo: demo/$(VERSION)/demo.exe -+keyconf: setup/$(VERSION)/keyconf.exe -+setup: setup/$(VERSION)/setup.exe -+afinfo: tests/$(VERSION)/afinfo.exe -+akaitest: tests/$(VERSION)/akaitest.exe -+digitest: tests/$(VERSION)/digitest.exe -+mathtest: tests/$(VERSION)/mathtest.exe -+miditest: tests/$(VERSION)/miditest.exe -+play: tests/$(VERSION)/play.exe -+playfli: tests/$(VERSION)/playfli.exe -+test: tests/$(VERSION)/test.exe -+vesainfo: tests/$(VERSION)/vesainfo.exe -+colormap: tools/$(VERSION)/colormap.exe -+dat: tools/$(VERSION)/dat.exe -+dat2s: tools/$(VERSION)/dat2s.exe -+exedat: tools/$(VERSION)/exedat.exe -+grabber: tools/$(VERSION)/grabber.exe -+pack: tools/$(VERSION)/pack.exe -+pat2dat: tools/$(VERSION)/pat2dat.exe -+rgbmap: tools/$(VERSION)/rgbmap.exe -+ -+examples: examples/$(VERSION)/ex1.exe examples/$(VERSION)/ex2.exe examples/$(VERSION)/ex3.exe \ -+ examples/$(VERSION)/ex4.exe examples/$(VERSION)/ex5.exe examples/$(VERSION)/ex6.exe \ -+ examples/$(VERSION)/ex7.exe examples/$(VERSION)/ex8.exe examples/$(VERSION)/ex9.exe \ -+ examples/$(VERSION)/ex10.exe examples/$(VERSION)/ex11.exe examples/$(VERSION)/ex12.exe \ -+ examples/$(VERSION)/ex13.exe examples/$(VERSION)/ex14.exe examples/$(VERSION)/ex15.exe \ -+ examples/$(VERSION)/ex16.exe examples/$(VERSION)/ex17.exe examples/$(VERSION)/ex18.exe \ -+ examples/$(VERSION)/ex19.exe examples/$(VERSION)/ex20.exe examples/$(VERSION)/ex21.exe \ -+ examples/$(VERSION)/ex22.exe examples/$(VERSION)/ex23.exe examples/$(VERSION)/ex24.exe \ -+ examples/$(VERSION)/ex25.exe examples/$(VERSION)/ex26.exe examples/$(VERSION)/ex27.exe \ -+ examples/$(VERSION)/ex28.exe examples/$(VERSION)/ex29.exe examples/$(VERSION)/ex30.exe \ -+ examples/$(VERSION)/ex31.exe examples/$(VERSION)/ex32.exe examples/$(VERSION)/ex33.exe \ -+ examples/$(VERSION)/ex34.exe examples/$(VERSION)/ex35.exe examples/$(VERSION)/ex36.exe \ -+ examples/$(VERSION)/ex37.exe examples/$(VERSION)/ex38.exe examples/$(VERSION)/ex39.exe \ -+ examples/$(VERSION)/ex40.exe - - $(OBJ)/demo.o: demo.h - $(OBJ)/adlib.o: fm_instr.h -diff -ruN allegro.312/obj/djgpp/alld/tmp.txt allegro.313/obj/djgpp/alld/tmp.txt ---- allegro.312/obj/djgpp/alld/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/obj/djgpp/alld/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/obj/djgpp/alleg/tmp.txt allegro.313/obj/djgpp/alleg/tmp.txt ---- allegro.312/obj/djgpp/alleg/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/obj/djgpp/alleg/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/obj/djgpp/allp/tmp.txt allegro.313/obj/djgpp/allp/tmp.txt ---- allegro.312/obj/djgpp/allp/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/obj/djgpp/allp/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/obj/djgpp/tmp.txt allegro.313/obj/djgpp/tmp.txt ---- allegro.312/obj/djgpp/tmp.txt Sat Feb 27 21:25:34 1999 -+++ allegro.313/obj/djgpp/tmp.txt Thu Jan 1 00:00:00 1970 -@@ -1 +0,0 @@ --This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/setup/alld/tmp.txt allegro.313/setup/alld/tmp.txt ---- allegro.312/setup/alld/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/setup/alld/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/setup/alleg/tmp.txt allegro.313/setup/alleg/tmp.txt ---- allegro.312/setup/alleg/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/setup/alleg/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/setup/allp/tmp.txt allegro.313/setup/allp/tmp.txt ---- allegro.312/setup/allp/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/setup/allp/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/src/asmdefs.inc allegro.313/src/asmdefs.inc ---- allegro.312/src/asmdefs.inc Sat Feb 20 20:51:22 1999 -+++ allegro.313/src/asmdefs.inc Sun Jun 19 04:18:44 2005 -@@ -41,8 +41,8 @@ - * %eax. Registers will be unchanged, except %eax will return a pointer - * to the start of the selected scanline. - */ --#define WRITE_BANK() call BMP_WBANK(%edx) --#define READ_BANK() call BMP_RBANK(%edx) -+#define WRITE_BANK() call *BMP_WBANK(%edx) -+#define READ_BANK() call *BMP_RBANK(%edx) - - - /* Helper macro for looking up a position in the pattern bitmap. Passed -diff -ruN allegro.312/src/djgpp/gpro.c allegro.313/src/djgpp/gpro.c ---- allegro.312/src/djgpp/gpro.c Sat Feb 20 22:01:28 1999 -+++ allegro.313/src/djgpp/gpro.c Mon Jun 20 21:23:42 2005 -@@ -53,135 +53,79 @@ - */ - static int read_gpp(int pad_num) - { -- char samples[60]; -- char clock_mask, data_mask; -- int ret; -- -- asm ( -- " cmpb $0, %0 ; " -- " jne 14f ; " -- " movb $0x10, %b2 ; " -- " movb $0x20, %b3 ; " -- " jmp 15f ; " -- " 14: " -- " movb $0x40, %b2 ; " -- " movb $0x80, %b3 ; " -- -- " 15: " -- " xorl %%ebx, %%ebx ; " -- " xorl %%edi, %%edi ; " -- " movw $0x201, %%dx ; " -- -- " cli ; " -- " inb %%dx, %%al ; " -- " movb %%al, %%ah ; " -- -- " 4: " -- " xorl %%ecx, %%ecx ; " -- " 0: " -- " inb %%dx, %%al ; " -- " cmpb %%ah, %%al ; " -- " jne 1f ; " -- " incl %%ecx ; " -- " cmpl $255, %%ecx ; " -- " jl 0b ; " -- -- " 1: " -- " cmpl $255, %%ecx ; " -- " je 16f ; " -- -- " testb %%ah, %b2 ; " -- " jz 2f ; " -- " testb %%al, %b2 ; " -- " jnz 2f ; " -- -- " addl %4, %%edi ; " -- " testb %%al, %b3 ; " -- " jz 3f ; " -- " movb $1, (%%edi) ; " -- " jmp 12f ; " -- " 3: " -- " movb $0, (%%edi) ; " -- " 12: " -- " subl %4, %%edi ; " -- " incl %%edi ; " -- -- " 2: " -- " movb %%al, %%ah ; " -- " cmpl $200, %%ebx ; " -- " je 13f ; " -- " incl %%ebx ; " -- " cmpl $50, %%edi ; " -- " jl 4b ; " -- -- " 13: " -- " sti ; " -- " xorl %%ecx, %%ecx ; " -- " movl $1, %%esi ; " -- " 7: " -- " addl %4, %%esi ; " -- " movb (%%esi), %%dl ; " -- " subl %4, %%esi ; " -- " cmpb $1, %%dl ; " -- " jg 16f ; " -- " jne 6f ; " -- " incl %%ecx ; " -- " jmp 5f ; " -- " 6: " -- " xorl %%ecx, %%ecx ; " -- -- " 5: " -- " cmpl $5, %%ecx ; " -- " je 8f ; " -- " cmpl %%edi, %%esi ; " -- " je 8f ; " -- " incl %%esi ; " -- " jmp 7b ; " -- -- " 8: " -- " cmpl $5, %%ecx ; " -- " jne 16f ; " -- " addl $2, %%esi ; " -- " xorl %%eax, %%eax ; " -- " xorl %%ebx, %%ebx ; " -- " xorl %%ecx, %%ecx ; " -- " xorl %%edx, %%edx ; " -- -- " 10: " -- " incl %%ecx ; " -- " cmpl $5, %%ecx ; " -- " jne 11f ; " -- " movl $1, %%ecx ; " -- " incl %%esi ; " -- " 11: " -- " addl %4, %%esi ; " -- " movb (%%esi), %%dl ; " -- " subl %4, %%esi ; " -- " orl %%edx, %%eax ; " -- " shll $1, %%eax ; " -- " cmpl $13, %%ebx ; " -- " je 9f ; " -- " incl %%ebx ; " -- " incl %%esi ; " -- " jmp 10b ; " -- -- " 16: " -- " movl $1, %%eax ; " -- -- " 9: " -- " sti ; " -- -- : "=a" (ret) -- -- : "0" (pad_num), -- "m" (clock_mask), -- "m" (data_mask), -- "m" (samples) -+ int samples[50]; -+ int clock_mask, data_mask, data, old_data; -+ int num_samples, timeout1, timeout2, sample_pos, c; -+ -+ if (pad_num == 0) { -+ clock_mask = 0x10; -+ data_mask = 0x20; -+ } -+ else { -+ clock_mask = 0x40; -+ data_mask = 0x80; -+ } -+ -+ num_samples = 0; -+ timeout1 = 0; -+ -+ asm volatile ("cli"); -+ -+ old_data = inportb(0x201); -+ data = 0; -+ -+ while (num_samples<50) { -+ for (timeout2=0; timeout2<255; timeout2++) { -+ data = inportb(0x201); -+ if (data != old_data) -+ break; -+ } -+ -+ if (timeout2 == 255) { -+ asm volatile ("sti"); -+ return 1; -+ } -+ -+ if ((old_data & clock_mask) && (!(data & clock_mask))) { -+ samples[num_samples] = (data & data_mask) ? 1 : 0; -+ num_samples++; -+ } -+ -+ old_data = data; -+ -+ if (timeout1++ == 200) -+ break; -+ } -+ -+ asm volatile ("sti"); -+ -+ c = 0; -+ -+ for (sample_pos=1; sample_posgs), - "=m" (sregs->ss) - -- : /* no inputs */ -- -- : "%eax" /* clobbers %eax */ - ); - } - -diff -ruN allegro.312/src/gfx15.s allegro.313/src/gfx15.s ---- allegro.312/src/gfx15.s Sat Feb 20 20:50:30 1999 -+++ allegro.313/src/gfx15.s Mon Jun 20 22:46:02 2005 -@@ -367,9 +367,9 @@ - movl BMP_CT(%edx), %esi /* clip y1 */ - - vline_y1_ok: -- cmpw BMP_CB(%edx), %ecx /* test y2, bmp->cb */ -+ cmpw BMP_CB(%edx), %cx /* test y2, bmp->cb */ - jl vline_noclip -- cmpw BMP_CB(%edx), %esi /* test y1, bmp->cb */ -+ cmpw BMP_CB(%edx), %si /* test y1, bmp->cb */ - jge vline_done - movl BMP_CB(%edx), %ecx /* clip y2 */ - decl %ecx -diff -ruN allegro.312/src/gfx16.s allegro.313/src/gfx16.s ---- allegro.312/src/gfx16.s Sat Feb 20 20:50:42 1999 -+++ allegro.313/src/gfx16.s Mon Jun 20 22:47:28 2005 -@@ -417,9 +417,9 @@ - movl BMP_CT(%edx), %esi /* clip y1 */ - - vline_y1_ok: -- cmpw BMP_CB(%edx), %ecx /* test y2, bmp->cb */ -+ cmpw BMP_CB(%edx), %cx /* test y2, bmp->cb */ - jl vline_noclip -- cmpw BMP_CB(%edx), %esi /* test y1, bmp->cb */ -+ cmpw BMP_CB(%edx), %si /* test y1, bmp->cb */ - jge vline_done - movl BMP_CB(%edx), %ecx /* clip y2 */ - decl %ecx -diff -ruN allegro.312/src/gfx24.s allegro.313/src/gfx24.s ---- allegro.312/src/gfx24.s Sat Feb 20 20:46:30 1999 -+++ allegro.313/src/gfx24.s Mon Jun 20 22:48:22 2005 -@@ -265,7 +265,7 @@ - movl %eax, ARG2 /* ARG2 == 12(%ebp) */ - movl %eax, 15(%ebp) /* overwrite ARG2, ARG3, ARG4 */ - movl %eax, 18(%ebp) -- movw %eax, 21(%ebp) -+ movw %ax, 21(%ebp) - shrl $16, %eax - movb %al, 23(%ebp) - cmpl $4, %ecx -@@ -503,9 +503,9 @@ - movl BMP_CT(%edx), %esi /* clip y1 */ - - vline_y1_ok: -- cmpw BMP_CB(%edx), %ecx /* test y2, bmp->cb */ -+ cmpw BMP_CB(%edx), %cx /* test y2, bmp->cb */ - jl vline_noclip -- cmpw BMP_CB(%edx), %esi /* test y1, bmp->cb */ -+ cmpw BMP_CB(%edx), %si /* test y1, bmp->cb */ - jge vline_done - movl BMP_CB(%edx), %ecx /* clip y2 */ - decl %ecx -diff -ruN allegro.312/src/gfx32.s allegro.313/src/gfx32.s ---- allegro.312/src/gfx32.s Sat Feb 20 20:50:40 1999 -+++ allegro.313/src/gfx32.s Mon Jun 20 22:48:44 2005 -@@ -398,9 +398,9 @@ - movl BMP_CT(%edx), %esi /* clip y1 */ - - vline_y1_ok: -- cmpw BMP_CB(%edx), %ecx /* test y2, bmp->cb */ -+ cmpw BMP_CB(%edx), %cx /* test y2, bmp->cb */ - jl vline_noclip -- cmpw BMP_CB(%edx), %esi /* test y1, bmp->cb */ -+ cmpw BMP_CB(%edx), %si /* test y1, bmp->cb */ - jge vline_done - movl BMP_CB(%edx), %ecx /* clip y2 */ - decl %ecx -diff -ruN allegro.312/src/gfx8.s allegro.313/src/gfx8.s ---- allegro.312/src/gfx8.s Sat Feb 20 20:50:54 1999 -+++ allegro.313/src/gfx8.s Mon Jun 20 22:49:02 2005 -@@ -455,9 +455,9 @@ - movl BMP_CT(%edx), %esi /* clip y1 */ - - vline_y1_ok: -- cmpw BMP_CB(%edx), %ecx /* test y2, bmp->cb */ -+ cmpw BMP_CB(%edx), %cx /* test y2, bmp->cb */ - jl vline_noclip -- cmpw BMP_CB(%edx), %esi /* test y1, bmp->cb */ -+ cmpw BMP_CB(%edx), %si /* test y1, bmp->cb */ - jge vline_done - movl BMP_CB(%edx), %ecx /* clip y2 */ - decl %ecx -diff -ruN allegro.312/tests/alld/tmp.txt allegro.313/tests/alld/tmp.txt ---- allegro.312/tests/alld/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/tests/alld/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/tests/alleg/tmp.txt allegro.313/tests/alleg/tmp.txt ---- allegro.312/tests/alleg/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/tests/alleg/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/tests/allp/tmp.txt allegro.313/tests/allp/tmp.txt ---- allegro.312/tests/allp/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/tests/allp/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/tools/alld/tmp.txt allegro.313/tools/alld/tmp.txt ---- allegro.312/tools/alld/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/tools/alld/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/tools/alleg/tmp.txt allegro.313/tools/alleg/tmp.txt ---- allegro.312/tools/alleg/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/tools/alleg/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. -diff -ruN allegro.312/tools/allp/tmp.txt allegro.313/tools/allp/tmp.txt ---- allegro.312/tools/allp/tmp.txt Thu Jan 1 00:00:00 1970 -+++ allegro.313/tools/allp/tmp.txt Sat Feb 27 21:25:34 1999 -@@ -0,0 +1 @@ -+This file is needed because some unzip programs skip empty directories. diff --git a/tools/fmoddyn.h b/tools/fmoddyn.h deleted file mode 100644 index d1e7c43f8..000000000 --- a/tools/fmoddyn.h +++ /dev/null @@ -1,582 +0,0 @@ -/* =========================================================================================== */ -/* FMOD Dynamic DLL loading header. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004. */ -/* =========================================================================================== */ - -#ifndef _FMODDYN_H_ -#define _FMODDYN_H_ - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) - #include -#else - #include - #include -#endif -#include - -typedef struct -{ - void *module; - - signed char (F_API *FSOUND_SetOutput)(int outputtype); - signed char (F_API *FSOUND_SetDriver)(int driver); - signed char (F_API *FSOUND_SetMixer)(int mixer); - signed char (F_API *FSOUND_SetBufferSize)(int len_ms); - signed char (F_API *FSOUND_SetHWND)(void *hwnd); - signed char (F_API *FSOUND_SetMinHardwareChannels)(int min); - signed char (F_API *FSOUND_SetMaxHardwareChannels)(int max); - signed char (F_API *FSOUND_SetMemorySystem)(void *pool, int poollen, FSOUND_ALLOCCALLBACK useralloc, FSOUND_REALLOCCALLBACK userrealloc, FSOUND_FREECALLBACK userfree); - signed char (F_API *FSOUND_Init)(int mixrate, int maxsoftwarechannels, unsigned int flags); - void (F_API *FSOUND_Close)(); - void (F_API *FSOUND_Update)(); /* you must call this once a frame */ - void (F_API *FSOUND_SetSpeakerMode)(unsigned int speakermode); - void (F_API *FSOUND_SetSFXMasterVolume)(int volume); - void (F_API *FSOUND_SetPanSeperation)(float pansep); - void (F_API *FSOUND_File_SetCallbacks)(FSOUND_OPENCALLBACK useropen, FSOUND_CLOSECALLBACK userclose, FSOUND_READCALLBACK userread, FSOUND_SEEKCALLBACK userseek, FSOUND_TELLCALLBACK usertell); - int (F_API *FSOUND_GetError)(); - float (F_API *FSOUND_GetVersion)(); - int (F_API *FSOUND_GetOutput)(); - void * (F_API *FSOUND_GetOutputHandle)(); - int (F_API *FSOUND_GetDriver)(); - int (F_API *FSOUND_GetMixer)(); - int (F_API *FSOUND_GetNumDrivers)(); - const char * (F_API *FSOUND_GetDriverName)(int id); - signed char (F_API *FSOUND_GetDriverCaps)(int id, unsigned int *caps); - int (F_API *FSOUND_GetOutputRate)(); - int (F_API *FSOUND_GetMaxChannels)(); - int (F_API *FSOUND_GetMaxSamples)(); - unsigned int (F_API *FSOUND_GetSpeakerMode)(); - int (F_API *FSOUND_GetSFXMasterVolume)(); - signed char (F_API *FSOUND_GetNumHWChannels)(int *num2d, int *num3d, int *total); - int (F_API *FSOUND_GetChannelsPlaying)(); - float (F_API *FSOUND_GetCPUUsage)(); - void (F_API *FSOUND_GetMemoryStats)(unsigned int *currentalloced, unsigned int *maxalloced); - FSOUND_SAMPLE * (F_API *FSOUND_Sample_Load)(int index, const char *name_or_data, unsigned int mode, int offset, int length); - FSOUND_SAMPLE * (F_API *FSOUND_Sample_Alloc)(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri); - void (F_API *FSOUND_Sample_Free)(FSOUND_SAMPLE *sptr); - signed char (F_API *FSOUND_Sample_Upload)(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode); - signed char (F_API *FSOUND_Sample_Lock)(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2); - signed char (F_API *FSOUND_Sample_Unlock)(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2); - signed char (F_API *FSOUND_Sample_SetMode)(FSOUND_SAMPLE *sptr, unsigned int mode); - signed char (F_API *FSOUND_Sample_SetLoopPoints)(FSOUND_SAMPLE *sptr, int loopstart, int loopend); - signed char (F_API *FSOUND_Sample_SetDefaults)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri); - signed char (F_API *FSOUND_Sample_SetDefaultsEx)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri, int varfreq, int varvol, int varpan); - signed char (F_API *FSOUND_Sample_SetMinMaxDistance)(FSOUND_SAMPLE *sptr, float min, float max); - signed char (F_API *FSOUND_Sample_SetMaxPlaybacks)(FSOUND_SAMPLE *sptr, int max); - FSOUND_SAMPLE * (F_API *FSOUND_Sample_Get)(int sampno); - const char * (F_API *FSOUND_Sample_GetName)(FSOUND_SAMPLE *sptr); - unsigned int (F_API *FSOUND_Sample_GetLength)(FSOUND_SAMPLE *sptr); - signed char (F_API *FSOUND_Sample_GetLoopPoints)(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend); - signed char (F_API *FSOUND_Sample_GetDefaults)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri); - signed char (F_API *FSOUND_Sample_GetDefaultsEx)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri, int *varfreq, int *varvol, int *varpan); - unsigned int (F_API *FSOUND_Sample_GetMode)(FSOUND_SAMPLE *sptr); - signed char (F_API *FSOUND_Sample_GetMinMaxDistance)(FSOUND_SAMPLE *sptr, float *min, float *max); - int (F_API *FSOUND_PlaySound)(int channel, FSOUND_SAMPLE *sptr); - int (F_API *FSOUND_PlaySoundEx)(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused); - signed char (F_API *FSOUND_StopSound)(int channel); - signed char (F_API *FSOUND_SetFrequency)(int channel, int freq); - signed char (F_API *FSOUND_SetVolume)(int channel, int vol); - signed char (F_API *FSOUND_SetVolumeAbsolute)(int channel, int vol); - signed char (F_API *FSOUND_SetPan)(int channel, int pan); - signed char (F_API *FSOUND_SetSurround)(int channel, signed char surround); - signed char (F_API *FSOUND_SetMute)(int channel, signed char mute); - signed char (F_API *FSOUND_SetPriority)(int channel, int priority); - signed char (F_API *FSOUND_SetReserved)(int channel, signed char reserved); - signed char (F_API *FSOUND_SetPaused)(int channel, signed char paused); - signed char (F_API *FSOUND_SetLoopMode)(int channel, unsigned int loopmode); - signed char (F_API *FSOUND_SetCurrentPosition)(int channel, unsigned int offset); - signed char (F_API *FSOUND_3D_SetAttributes)(int channel, const float *pos, const float *vel); - signed char (F_API *FSOUND_3D_SetMinMaxDistance)(int channel, float min, float max); - signed char (F_API *FSOUND_IsPlaying)(int channel); - int (F_API *FSOUND_GetFrequency)(int channel); - int (F_API *FSOUND_GetVolume)(int channel); - int (F_API *FSOUND_GetAmplitude)(int channel); - int (F_API *FSOUND_GetPan)(int channel); - signed char (F_API *FSOUND_GetSurround)(int channel); - signed char (F_API *FSOUND_GetMute)(int channel); - int (F_API *FSOUND_GetPriority)(int channel); - signed char (F_API *FSOUND_GetReserved)(int channel); - signed char (F_API *FSOUND_GetPaused)(int channel); - unsigned int (F_API *FSOUND_GetLoopMode)(int channel); - unsigned int (F_API *FSOUND_GetCurrentPosition)(int channel); - FSOUND_SAMPLE * (F_API *FSOUND_GetCurrentSample)(int channel); - signed char (F_API *FSOUND_GetCurrentLevels)(int channel, float *l, float *r); - int (F_API *FSOUND_GetNumSubChannels)(int channel); - int (F_API *FSOUND_GetSubChannel)(int channel, int subchannel); - signed char (F_API *FSOUND_3D_GetAttributes)(int channel, float *pos, float *vel); - signed char (F_API *FSOUND_3D_GetMinMaxDistance)(int channel, float *min, float *max); - void (F_API *FSOUND_3D_SetDopplerFactor)(float scale); - void (F_API *FSOUND_3D_SetDistanceFactor)(float scale); - void (F_API *FSOUND_3D_SetRolloffFactor)(float scale); - void (F_API *FSOUND_3D_Listener_SetCurrent)(int current, int numlisteners); /* use this if you use multiple listeners / splitscreen */ - void (F_API *FSOUND_3D_Listener_SetAttributes)(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz); - void (F_API *FSOUND_3D_Listener_GetAttributes)(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz); - int (F_API *FSOUND_FX_Enable)(int channel, unsigned int fx); /* See FSOUND_FX_MODES */ - signed char (F_API *FSOUND_FX_Disable)(int channel); - signed char (F_API *FSOUND_FX_SetChorus)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); - signed char (F_API *FSOUND_FX_SetCompressor)(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay); - signed char (F_API *FSOUND_FX_SetDistortion)(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff); - signed char (F_API *FSOUND_FX_SetEcho)(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay); - signed char (F_API *FSOUND_FX_SetFlanger)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase); - signed char (F_API *FSOUND_FX_SetGargle)(int fxid, int RateHz, int WaveShape); - signed char (F_API *FSOUND_FX_SetI3DL2Reverb)(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference); - signed char (F_API *FSOUND_FX_SetParamEQ)(int fxid, float Center, float Bandwidth, float Gain); - signed char (F_API *FSOUND_FX_SetWavesReverb)(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio); - signed char (F_API *FSOUND_Stream_SetBufferSize)(int ms); /* call this before opening streams, not after */ - FSOUND_STREAM * (F_API *FSOUND_Stream_Open)(const char *name_or_data, unsigned int mode, int offset, int length); - FSOUND_STREAM * (F_API *FSOUND_Stream_Create)(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, void *userdata); - signed char (F_API *FSOUND_Stream_Close)(FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_Play)(int channel, FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_PlayEx)(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused); - signed char (F_API *FSOUND_Stream_Stop)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetPosition)(FSOUND_STREAM *stream, unsigned int position); - unsigned int (F_API *FSOUND_Stream_GetPosition)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetTime)(FSOUND_STREAM *stream, int ms); - int (F_API *FSOUND_Stream_GetTime)(FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_GetLength)(FSOUND_STREAM *stream); - int (F_API *FSOUND_Stream_GetLengthMs)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetMode)(FSOUND_STREAM *stream, unsigned int mode); - unsigned int (F_API *FSOUND_Stream_GetMode)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetLoopPoints)(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm); - signed char (F_API *FSOUND_Stream_SetLoopCount)(FSOUND_STREAM *stream, int count); - int (F_API *FSOUND_Stream_GetOpenState)(FSOUND_STREAM *stream); - FSOUND_SAMPLE * (F_API *FSOUND_Stream_GetSample)(FSOUND_STREAM *stream); /* every stream contains a sample to playback on */ - FSOUND_DSPUNIT * (F_API *FSOUND_Stream_CreateDSP)(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, void *userdata); - signed char (F_API *FSOUND_Stream_SetEndCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata); - signed char (F_API *FSOUND_Stream_SetSyncCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata); - FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_AddSyncPoint)(FSOUND_STREAM *stream, unsigned int pcmoffset, const char *name); - signed char (F_API *FSOUND_Stream_DeleteSyncPoint)(FSOUND_SYNCPOINT *point); - int (F_API *FSOUND_Stream_GetNumSyncPoints)(FSOUND_STREAM *stream); - FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_GetSyncPoint)(FSOUND_STREAM *stream, int index); - char * (F_API *FSOUND_Stream_GetSyncPointInfo)(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset); - signed char (F_API *FSOUND_Stream_SetSubStream)(FSOUND_STREAM *stream, int index); - int (F_API *FSOUND_Stream_GetNumSubStreams)(FSOUND_STREAM *stream); - signed char (F_API *FSOUND_Stream_SetSubStreamSentence)(FSOUND_STREAM *stream, const int *sentencelist, int numitems); - signed char (F_API *FSOUND_Stream_GetNumTagFields)(FSOUND_STREAM *stream, int *num); - signed char (F_API *FSOUND_Stream_GetTagField)(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length); - signed char (F_API *FSOUND_Stream_FindTagField)(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length); - signed char (F_API *FSOUND_Stream_Net_SetProxy)(const char *proxy); - signed char (F_API *FSOUND_Stream_Net_SetTimeout)(int timeout); - char * (F_API *FSOUND_Stream_Net_GetLastServerStatus)(); - signed char (F_API *FSOUND_Stream_Net_SetBufferProperties)(int buffersize, int prebuffer_percent, int rebuffer_percent); - signed char (F_API *FSOUND_Stream_Net_GetBufferProperties)(int *buffersize, int *prebuffer_percent, int *rebuffer_percent); - signed char (F_API *FSOUND_Stream_Net_SetMetadataCallback)(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, void *userdata); - signed char (F_API *FSOUND_Stream_Net_GetStatus)(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags); - signed char (F_API *FSOUND_CD_Play)(char drive, int track); - void (F_API *FSOUND_CD_SetPlayMode)(char drive, signed char mode); - signed char (F_API *FSOUND_CD_Stop)(char drive); - signed char (F_API *FSOUND_CD_SetPaused)(char drive, signed char paused); - signed char (F_API *FSOUND_CD_SetVolume)(char drive, int volume); - signed char (F_API *FSOUND_CD_SetTrackTime)(char drive, unsigned int ms); - signed char (F_API *FSOUND_CD_OpenTray)(char drive, signed char open); - signed char (F_API *FSOUND_CD_GetPaused)(char drive); - int (F_API *FSOUND_CD_GetTrack)(char drive); - int (F_API *FSOUND_CD_GetNumTracks)(char drive); - int (F_API *FSOUND_CD_GetVolume)(char drive); - int (F_API *FSOUND_CD_GetTrackLength)(char drive, int track); - int (F_API *FSOUND_CD_GetTrackTime)(char drive); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_Create)(FSOUND_DSPCALLBACK callback, int priority, void *userdata); - void (F_API *FSOUND_DSP_Free)(FSOUND_DSPUNIT *unit); - void (F_API *FSOUND_DSP_SetPriority)(FSOUND_DSPUNIT *unit, int priority); - int (F_API *FSOUND_DSP_GetPriority)(FSOUND_DSPUNIT *unit); - void (F_API *FSOUND_DSP_SetActive)(FSOUND_DSPUNIT *unit, signed char active); - signed char (F_API *FSOUND_DSP_GetActive)(FSOUND_DSPUNIT *unit); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClearUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetSFXUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetMusicUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetFFTUnit)(); - FSOUND_DSPUNIT * (F_API *FSOUND_DSP_GetClipAndCopyUnit)(); - signed char (F_API *FSOUND_DSP_MixBuffers)(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode); - void (F_API *FSOUND_DSP_ClearMixBuffer)(); - int (F_API *FSOUND_DSP_GetBufferLength)(); /* Length of each DSP update */ - int (F_API *FSOUND_DSP_GetBufferLengthTotal)(); /* Total buffer length due to FSOUND_SetBufferSize */ - float * (F_API *FSOUND_DSP_GetSpectrum)(); /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */ - signed char (F_API *FSOUND_Reverb_SetProperties)(const FSOUND_REVERB_PROPERTIES *prop); - signed char (F_API *FSOUND_Reverb_GetProperties)(FSOUND_REVERB_PROPERTIES *prop); - signed char (F_API *FSOUND_Reverb_SetChannelProperties)(int channel, const FSOUND_REVERB_CHANNELPROPERTIES *prop); - signed char (F_API *FSOUND_Reverb_GetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop); - signed char (F_API *FSOUND_Record_SetDriver)(int outputtype); - int (F_API *FSOUND_Record_GetNumDrivers)(); - const char * (F_API *FSOUND_Record_GetDriverName)(int id); - int (F_API *FSOUND_Record_GetDriver)(); - signed char (F_API *FSOUND_Record_StartSample)(FSOUND_SAMPLE *sptr, signed char loop); - signed char (F_API *FSOUND_Record_Stop)(); - int (F_API *FSOUND_Record_GetPosition)(); - FMUSIC_MODULE * (F_API *FMUSIC_LoadSong)(const char *name); - FMUSIC_MODULE * (F_API *FMUSIC_LoadSongEx)(const char *name_or_data, int offset, int length, unsigned int mode, const int *samplelist, int samplelistnum); - int (F_API *FMUSIC_GetOpenState)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_FreeSong)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_PlaySong)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_StopSong)(FMUSIC_MODULE *mod); - void (F_API *FMUSIC_StopAllSongs)(); - signed char (F_API *FMUSIC_SetZxxCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback); - signed char (F_API *FMUSIC_SetRowCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep); - signed char (F_API *FMUSIC_SetOrderCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep); - signed char (F_API *FMUSIC_SetInstCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument); - signed char (F_API *FMUSIC_SetSample)(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr); - signed char (F_API *FMUSIC_SetUserData)(FMUSIC_MODULE *mod, void *userdata); - signed char (F_API *FMUSIC_OptimizeChannels)(FMUSIC_MODULE *mod, int maxchannels, int minvolume); - signed char (F_API *FMUSIC_SetReverb)(signed char reverb); /* MIDI only */ - signed char (F_API *FMUSIC_SetLooping)(FMUSIC_MODULE *mod, signed char looping); - signed char (F_API *FMUSIC_SetOrder)(FMUSIC_MODULE *mod, int order); - signed char (F_API *FMUSIC_SetPaused)(FMUSIC_MODULE *mod, signed char pause); - signed char (F_API *FMUSIC_SetMasterVolume)(FMUSIC_MODULE *mod, int volume); - signed char (F_API *FMUSIC_SetMasterSpeed)(FMUSIC_MODULE *mode, float speed); - signed char (F_API *FMUSIC_SetPanSeperation)(FMUSIC_MODULE *mod, float pansep); - const char * (F_API *FMUSIC_GetName)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetType)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumOrders)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumPatterns)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumInstruments)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumSamples)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetNumChannels)(FMUSIC_MODULE *mod); - FSOUND_SAMPLE * (F_API *FMUSIC_GetSample)(FMUSIC_MODULE *mod, int sampno); - int (F_API *FMUSIC_GetPatternLength)(FMUSIC_MODULE *mod, int orderno); - signed char (F_API *FMUSIC_IsFinished)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_IsPlaying)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetMasterVolume)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetGlobalVolume)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetOrder)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetPattern)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetSpeed)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetBPM)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetRow)(FMUSIC_MODULE *mod); - signed char (F_API *FMUSIC_GetPaused)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetTime)(FMUSIC_MODULE *mod); - int (F_API *FMUSIC_GetRealChannel)(FMUSIC_MODULE *mod, int modchannel); - unsigned int (F_API *FMUSIC_GetUserData)(FMUSIC_MODULE *mod); -} FMOD_INSTANCE; - - -static FMOD_INSTANCE *FMOD_CreateInstance(char *dllName) -{ - FMOD_INSTANCE *instance; - - instance = (FMOD_INSTANCE *)calloc(sizeof(FMOD_INSTANCE), 1); - if (!instance) - { - return NULL; - } - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) - instance->module = LoadLibrary(dllName); -#else - instance->module = dlopen(dllName, RTLD_LAZY); -#endif - if (!instance->module) - { - free(instance); - return NULL; - } - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) -#ifdef __MINGW64__ - #define F_GETPROC(_x, _y) \ - { \ - char tmp[] = _y; \ - *(strchr(tmp, '@')) = 0; \ - instance->_x = (LPVOID)GetProcAddress((HMODULE)instance->module, &tmp[1]); \ - if (!instance->_x) \ - { \ - FreeLibrary((HMODULE)instance->module); \ - free(instance); \ - return NULL; \ - } \ - } -#elif defined(__MINGW32__) - #define F_GETPROC(_x, _y) \ - { \ - instance->_x = (LPVOID)GetProcAddress((HMODULE)instance->module, _y); \ - if (!instance->_x) \ - { \ - FreeLibrary((HMODULE)instance->module); \ - free(instance); \ - return NULL; \ - } \ - } -#elif defined (_X86_) - #define F_GETPROC(_x, _y) \ - { \ - instance->_x = (LPVOID)(size_t)GetProcAddress((HMODULE)instance->module, _y); \ - if (!instance->_x) \ - { \ - FreeLibrary((HMODULE)instance->module); \ - free(instance); \ - return NULL; \ - } \ - } -#else - #define F_GETPROC(_x, _y) \ - { \ - char tmp[] = _y; \ - *(strchr(tmp, '@')) = 0; \ - instance->_x = (LPVOID)(size_t)GetProcAddress((HMODULE)instance->module, &tmp[1]); \ - if (!instance->_x) \ - { \ - FreeLibrary((HMODULE)instance->module); \ - free(instance); \ - return NULL; \ - } \ - } -#endif -#else - #define F_GETPROC(_x, _y) \ - { \ - char tmp[] = _y; \ - *(strchr(tmp, '@')) = 0; \ - instance->_x = (void *)dlsym(instance->module, &tmp[1]); \ - if (!instance->_x) \ - { \ - dlclose(instance->module); \ - free(instance); \ - return NULL; \ - } \ - } -#endif - - F_GETPROC(FSOUND_SetOutput, "_FSOUND_SetOutput@4"); - F_GETPROC(FSOUND_SetDriver, "_FSOUND_SetDriver@4"); - F_GETPROC(FSOUND_SetMixer, "_FSOUND_SetMixer@4"); - F_GETPROC(FSOUND_SetBufferSize, "_FSOUND_SetBufferSize@4"); - F_GETPROC(FSOUND_SetHWND, "_FSOUND_SetHWND@4"); - F_GETPROC(FSOUND_SetMinHardwareChannels, "_FSOUND_SetMinHardwareChannels@4"); - F_GETPROC(FSOUND_SetMaxHardwareChannels, "_FSOUND_SetMaxHardwareChannels@4"); - F_GETPROC(FSOUND_SetMemorySystem, "_FSOUND_SetMemorySystem@20"); - F_GETPROC(FSOUND_Init, "_FSOUND_Init@12"); - F_GETPROC(FSOUND_Close, "_FSOUND_Close@0"); - F_GETPROC(FSOUND_Update, "_FSOUND_Update@0"); - F_GETPROC(FSOUND_SetSFXMasterVolume, "_FSOUND_SetSFXMasterVolume@4"); - F_GETPROC(FSOUND_SetPanSeperation, "_FSOUND_SetPanSeperation@4"); - F_GETPROC(FSOUND_SetSpeakerMode, "_FSOUND_SetSpeakerMode@4"); - F_GETPROC(FSOUND_GetError, "_FSOUND_GetError@0"); - F_GETPROC(FSOUND_GetVersion, "_FSOUND_GetVersion@0"); - F_GETPROC(FSOUND_GetOutput, "_FSOUND_GetOutput@0"); - F_GETPROC(FSOUND_GetOutputHandle, "_FSOUND_GetOutputHandle@0"); - F_GETPROC(FSOUND_GetDriver, "_FSOUND_GetDriver@0"); - F_GETPROC(FSOUND_GetMixer, "_FSOUND_GetMixer@0"); - F_GETPROC(FSOUND_GetNumDrivers, "_FSOUND_GetNumDrivers@0"); - F_GETPROC(FSOUND_GetDriverName, "_FSOUND_GetDriverName@4"); - F_GETPROC(FSOUND_GetDriverCaps, "_FSOUND_GetDriverCaps@8"); - F_GETPROC(FSOUND_GetOutputRate, "_FSOUND_GetOutputRate@0"); - F_GETPROC(FSOUND_GetMaxChannels, "_FSOUND_GetMaxChannels@0"); - F_GETPROC(FSOUND_GetMaxSamples, "_FSOUND_GetMaxSamples@0"); - F_GETPROC(FSOUND_GetSpeakerMode, "_FSOUND_GetSpeakerMode@0"); - F_GETPROC(FSOUND_GetSFXMasterVolume, "_FSOUND_GetSFXMasterVolume@0"); - F_GETPROC(FSOUND_GetNumHWChannels, "_FSOUND_GetNumHWChannels@12"); - F_GETPROC(FSOUND_GetChannelsPlaying, "_FSOUND_GetChannelsPlaying@0"); - F_GETPROC(FSOUND_GetCPUUsage, "_FSOUND_GetCPUUsage@0"); - F_GETPROC(FSOUND_GetMemoryStats, "_FSOUND_GetMemoryStats@8"); - F_GETPROC(FSOUND_Sample_Load, "_FSOUND_Sample_Load@20"); - F_GETPROC(FSOUND_Sample_Alloc, "_FSOUND_Sample_Alloc@28"); - F_GETPROC(FSOUND_Sample_Free, "_FSOUND_Sample_Free@4"); - F_GETPROC(FSOUND_Sample_Upload, "_FSOUND_Sample_Upload@12"); - F_GETPROC(FSOUND_Sample_Lock, "_FSOUND_Sample_Lock@28"); - F_GETPROC(FSOUND_Sample_Unlock, "_FSOUND_Sample_Unlock@20"); - F_GETPROC(FSOUND_Sample_SetMode, "_FSOUND_Sample_SetMode@8"); - F_GETPROC(FSOUND_Sample_SetLoopPoints, "_FSOUND_Sample_SetLoopPoints@12"); - F_GETPROC(FSOUND_Sample_SetDefaults, "_FSOUND_Sample_SetDefaults@20"); - F_GETPROC(FSOUND_Sample_SetDefaultsEx, "_FSOUND_Sample_SetDefaultsEx@32"); - F_GETPROC(FSOUND_Sample_SetMinMaxDistance, "_FSOUND_Sample_SetMinMaxDistance@12"); - F_GETPROC(FSOUND_Sample_SetMaxPlaybacks, "_FSOUND_Sample_SetMaxPlaybacks@8"); - F_GETPROC(FSOUND_Sample_Get, "_FSOUND_Sample_Get@4"); - F_GETPROC(FSOUND_Sample_GetName, "_FSOUND_Sample_GetName@4"); - F_GETPROC(FSOUND_Sample_GetLength, "_FSOUND_Sample_GetLength@4"); - F_GETPROC(FSOUND_Sample_GetLoopPoints, "_FSOUND_Sample_GetLoopPoints@12"); - F_GETPROC(FSOUND_Sample_GetDefaults, "_FSOUND_Sample_GetDefaults@20"); - F_GETPROC(FSOUND_Sample_GetDefaultsEx, "_FSOUND_Sample_GetDefaultsEx@32"); - F_GETPROC(FSOUND_Sample_GetMode, "_FSOUND_Sample_GetMode@4"); - F_GETPROC(FSOUND_Sample_GetMinMaxDistance, "_FSOUND_Sample_GetMinMaxDistance@12"); - F_GETPROC(FSOUND_PlaySound, "_FSOUND_PlaySound@8"); - F_GETPROC(FSOUND_PlaySoundEx, "_FSOUND_PlaySoundEx@16"); - F_GETPROC(FSOUND_StopSound, "_FSOUND_StopSound@4"); - F_GETPROC(FSOUND_SetFrequency, "_FSOUND_SetFrequency@8"); - F_GETPROC(FSOUND_SetVolume, "_FSOUND_SetVolume@8"); - F_GETPROC(FSOUND_SetVolumeAbsolute, "_FSOUND_SetVolumeAbsolute@8"); - F_GETPROC(FSOUND_SetPan, "_FSOUND_SetPan@8"); - F_GETPROC(FSOUND_SetSurround, "_FSOUND_SetSurround@8"); - F_GETPROC(FSOUND_SetMute, "_FSOUND_SetMute@8"); - F_GETPROC(FSOUND_SetPriority, "_FSOUND_SetPriority@8"); - F_GETPROC(FSOUND_SetReserved, "_FSOUND_SetReserved@8"); - F_GETPROC(FSOUND_SetPaused, "_FSOUND_SetPaused@8"); - F_GETPROC(FSOUND_SetLoopMode, "_FSOUND_SetLoopMode@8"); - F_GETPROC(FSOUND_SetCurrentPosition, "_FSOUND_SetCurrentPosition@8"); - F_GETPROC(FSOUND_3D_SetAttributes, "_FSOUND_3D_SetAttributes@12"); - F_GETPROC(FSOUND_3D_SetMinMaxDistance, "_FSOUND_3D_SetMinMaxDistance@12"); - F_GETPROC(FSOUND_IsPlaying, "_FSOUND_IsPlaying@4"); - F_GETPROC(FSOUND_GetFrequency, "_FSOUND_GetFrequency@4"); - F_GETPROC(FSOUND_GetVolume, "_FSOUND_GetVolume@4"); - F_GETPROC(FSOUND_GetAmplitude, "_FSOUND_GetAmplitude@4"); - F_GETPROC(FSOUND_GetPan, "_FSOUND_GetPan@4"); - F_GETPROC(FSOUND_GetSurround, "_FSOUND_GetSurround@4"); - F_GETPROC(FSOUND_GetMute, "_FSOUND_GetMute@4"); - F_GETPROC(FSOUND_GetPriority, "_FSOUND_GetPriority@4"); - F_GETPROC(FSOUND_GetReserved, "_FSOUND_GetReserved@4"); - F_GETPROC(FSOUND_GetPaused, "_FSOUND_GetPaused@4"); - F_GETPROC(FSOUND_GetLoopMode, "_FSOUND_GetLoopMode@4"); - F_GETPROC(FSOUND_GetCurrentPosition, "_FSOUND_GetCurrentPosition@4"); - F_GETPROC(FSOUND_GetCurrentSample, "_FSOUND_GetCurrentSample@4"); - F_GETPROC(FSOUND_GetCurrentLevels, "_FSOUND_GetCurrentLevels@12"); - F_GETPROC(FSOUND_GetNumSubChannels, "_FSOUND_GetNumSubChannels@4"); - F_GETPROC(FSOUND_GetSubChannel, "_FSOUND_GetSubChannel@8"); - F_GETPROC(FSOUND_3D_GetAttributes, "_FSOUND_3D_GetAttributes@12"); - F_GETPROC(FSOUND_3D_GetMinMaxDistance, "_FSOUND_3D_GetMinMaxDistance@12"); - F_GETPROC(FSOUND_3D_Listener_SetCurrent, "_FSOUND_3D_Listener_SetCurrent@8"); - F_GETPROC(FSOUND_3D_Listener_SetAttributes, "_FSOUND_3D_Listener_SetAttributes@32"); - F_GETPROC(FSOUND_3D_Listener_GetAttributes, "_FSOUND_3D_Listener_GetAttributes@32"); - F_GETPROC(FSOUND_3D_SetDopplerFactor, "_FSOUND_3D_SetDopplerFactor@4"); - F_GETPROC(FSOUND_3D_SetDistanceFactor, "_FSOUND_3D_SetDistanceFactor@4"); - F_GETPROC(FSOUND_3D_SetRolloffFactor, "_FSOUND_3D_SetRolloffFactor@4"); - F_GETPROC(FSOUND_FX_Enable, "_FSOUND_FX_Enable@8"); - F_GETPROC(FSOUND_FX_Disable, "_FSOUND_FX_Disable@4"); - F_GETPROC(FSOUND_FX_SetChorus, "_FSOUND_FX_SetChorus@32"); - F_GETPROC(FSOUND_FX_SetCompressor, "_FSOUND_FX_SetCompressor@28"); - F_GETPROC(FSOUND_FX_SetDistortion, "_FSOUND_FX_SetDistortion@24"); - F_GETPROC(FSOUND_FX_SetEcho, "_FSOUND_FX_SetEcho@24"); - F_GETPROC(FSOUND_FX_SetFlanger, "_FSOUND_FX_SetFlanger@32"); - F_GETPROC(FSOUND_FX_SetGargle, "_FSOUND_FX_SetGargle@12"); - F_GETPROC(FSOUND_FX_SetI3DL2Reverb, "_FSOUND_FX_SetI3DL2Reverb@52"); - F_GETPROC(FSOUND_FX_SetParamEQ, "_FSOUND_FX_SetParamEQ@16"); - F_GETPROC(FSOUND_FX_SetWavesReverb, "_FSOUND_FX_SetWavesReverb@20"); - F_GETPROC(FSOUND_Stream_Open, "_FSOUND_Stream_Open@16"); - F_GETPROC(FSOUND_Stream_Create, "_FSOUND_Stream_Create@20"); - F_GETPROC(FSOUND_Stream_Play, "_FSOUND_Stream_Play@8"); - F_GETPROC(FSOUND_Stream_PlayEx, "_FSOUND_Stream_PlayEx@16"); - F_GETPROC(FSOUND_Stream_Stop, "_FSOUND_Stream_Stop@4"); - F_GETPROC(FSOUND_Stream_Close, "_FSOUND_Stream_Close@4"); - F_GETPROC(FSOUND_Stream_SetEndCallback, "_FSOUND_Stream_SetEndCallback@12"); - F_GETPROC(FSOUND_Stream_SetSyncCallback, "_FSOUND_Stream_SetSyncCallback@12"); - F_GETPROC(FSOUND_Stream_GetSample, "_FSOUND_Stream_GetSample@4"); - F_GETPROC(FSOUND_Stream_CreateDSP, "_FSOUND_Stream_CreateDSP@16"); - F_GETPROC(FSOUND_Stream_SetBufferSize, "_FSOUND_Stream_SetBufferSize@4"); - F_GETPROC(FSOUND_Stream_SetPosition, "_FSOUND_Stream_SetPosition@8"); - F_GETPROC(FSOUND_Stream_GetPosition, "_FSOUND_Stream_GetPosition@4"); - F_GETPROC(FSOUND_Stream_SetTime, "_FSOUND_Stream_SetTime@8"); - F_GETPROC(FSOUND_Stream_GetTime, "_FSOUND_Stream_GetTime@4"); - F_GETPROC(FSOUND_Stream_GetLength, "_FSOUND_Stream_GetLength@4"); - F_GETPROC(FSOUND_Stream_GetLengthMs, "_FSOUND_Stream_GetLengthMs@4"); - F_GETPROC(FSOUND_Stream_SetMode, "_FSOUND_Stream_SetMode@8"); - F_GETPROC(FSOUND_Stream_GetMode, "_FSOUND_Stream_GetMode@4"); - F_GETPROC(FSOUND_Stream_SetSubStream, "_FSOUND_Stream_SetSubStream@8"); - F_GETPROC(FSOUND_Stream_GetNumSubStreams, "_FSOUND_Stream_GetNumSubStreams@4"); - F_GETPROC(FSOUND_Stream_SetSubStreamSentence, "_FSOUND_Stream_SetSubStreamSentence@12"); - F_GETPROC(FSOUND_Stream_SetLoopPoints, "_FSOUND_Stream_SetLoopPoints@12"); - F_GETPROC(FSOUND_Stream_SetLoopCount, "_FSOUND_Stream_SetLoopCount@8"); - F_GETPROC(FSOUND_Stream_AddSyncPoint, "_FSOUND_Stream_AddSyncPoint@12"); - F_GETPROC(FSOUND_Stream_DeleteSyncPoint, "_FSOUND_Stream_DeleteSyncPoint@4"); - F_GETPROC(FSOUND_Stream_GetNumSyncPoints, "_FSOUND_Stream_GetNumSyncPoints@4"); - F_GETPROC(FSOUND_Stream_GetSyncPoint, "_FSOUND_Stream_GetSyncPoint@8"); - F_GETPROC(FSOUND_Stream_GetSyncPointInfo, "_FSOUND_Stream_GetSyncPointInfo@8"); - F_GETPROC(FSOUND_Stream_GetOpenState, "_FSOUND_Stream_GetOpenState@4"); - F_GETPROC(FSOUND_Stream_GetNumTagFields, "_FSOUND_Stream_GetNumTagFields@8"); - F_GETPROC(FSOUND_Stream_GetTagField, "_FSOUND_Stream_GetTagField@24"); - F_GETPROC(FSOUND_Stream_FindTagField, "_FSOUND_Stream_FindTagField@20"); - F_GETPROC(FSOUND_Stream_Net_SetProxy, "_FSOUND_Stream_Net_SetProxy@4"); - F_GETPROC(FSOUND_Stream_Net_GetLastServerStatus, "_FSOUND_Stream_Net_GetLastServerStatus@0"); - F_GETPROC(FSOUND_Stream_Net_SetBufferProperties, "_FSOUND_Stream_Net_SetBufferProperties@12"); - F_GETPROC(FSOUND_Stream_Net_GetBufferProperties, "_FSOUND_Stream_Net_GetBufferProperties@12"); - F_GETPROC(FSOUND_Stream_Net_SetMetadataCallback, "_FSOUND_Stream_Net_SetMetadataCallback@12"); - F_GETPROC(FSOUND_Stream_Net_GetStatus, "_FSOUND_Stream_Net_GetStatus@20"); - F_GETPROC(FSOUND_CD_Play, "_FSOUND_CD_Play@8"); - F_GETPROC(FSOUND_CD_SetPlayMode, "_FSOUND_CD_SetPlayMode@8"); - F_GETPROC(FSOUND_CD_Stop, "_FSOUND_CD_Stop@4"); - F_GETPROC(FSOUND_CD_SetPaused, "_FSOUND_CD_SetPaused@8"); - F_GETPROC(FSOUND_CD_SetVolume, "_FSOUND_CD_SetVolume@8"); - F_GETPROC(FSOUND_CD_SetTrackTime, "_FSOUND_CD_SetTrackTime@8"); - F_GETPROC(FSOUND_CD_OpenTray, "_FSOUND_CD_OpenTray@8"); - F_GETPROC(FSOUND_CD_GetPaused, "_FSOUND_CD_GetPaused@4"); - F_GETPROC(FSOUND_CD_GetTrack, "_FSOUND_CD_GetTrack@4"); - F_GETPROC(FSOUND_CD_GetNumTracks, "_FSOUND_CD_GetNumTracks@4"); - F_GETPROC(FSOUND_CD_GetVolume, "_FSOUND_CD_GetVolume@4"); - F_GETPROC(FSOUND_CD_GetTrackLength, "_FSOUND_CD_GetTrackLength@8"); - F_GETPROC(FSOUND_CD_GetTrackTime, "_FSOUND_CD_GetTrackTime@4"); - F_GETPROC(FSOUND_DSP_Create, "_FSOUND_DSP_Create@12"); - F_GETPROC(FSOUND_DSP_Free, "_FSOUND_DSP_Free@4"); - F_GETPROC(FSOUND_DSP_SetPriority, "_FSOUND_DSP_SetPriority@8"); - F_GETPROC(FSOUND_DSP_GetPriority, "_FSOUND_DSP_GetPriority@4"); - F_GETPROC(FSOUND_DSP_SetActive, "_FSOUND_DSP_SetActive@8"); - F_GETPROC(FSOUND_DSP_GetActive, "_FSOUND_DSP_GetActive@4"); - F_GETPROC(FSOUND_DSP_GetClearUnit, "_FSOUND_DSP_GetClearUnit@0"); - F_GETPROC(FSOUND_DSP_GetSFXUnit, "_FSOUND_DSP_GetSFXUnit@0"); - F_GETPROC(FSOUND_DSP_GetMusicUnit, "_FSOUND_DSP_GetMusicUnit@0"); - F_GETPROC(FSOUND_DSP_GetClipAndCopyUnit, "_FSOUND_DSP_GetClipAndCopyUnit@0"); - F_GETPROC(FSOUND_DSP_GetFFTUnit, "_FSOUND_DSP_GetFFTUnit@0"); - F_GETPROC(FSOUND_DSP_MixBuffers, "_FSOUND_DSP_MixBuffers@28"); - F_GETPROC(FSOUND_DSP_ClearMixBuffer, "_FSOUND_DSP_ClearMixBuffer@0"); - F_GETPROC(FSOUND_DSP_GetBufferLength, "_FSOUND_DSP_GetBufferLength@0"); - F_GETPROC(FSOUND_DSP_GetBufferLengthTotal, "_FSOUND_DSP_GetBufferLengthTotal@0"); - F_GETPROC(FSOUND_DSP_GetSpectrum, "_FSOUND_DSP_GetSpectrum@0"); - F_GETPROC(FSOUND_Reverb_SetProperties, "_FSOUND_Reverb_SetProperties@4"); - F_GETPROC(FSOUND_Reverb_GetProperties, "_FSOUND_Reverb_GetProperties@4"); - F_GETPROC(FSOUND_Reverb_SetChannelProperties, "_FSOUND_Reverb_SetChannelProperties@8"); - F_GETPROC(FSOUND_Reverb_GetChannelProperties, "_FSOUND_Reverb_GetChannelProperties@8"); - F_GETPROC(FSOUND_Record_SetDriver, "_FSOUND_Record_SetDriver@4"); - F_GETPROC(FSOUND_Record_GetNumDrivers, "_FSOUND_Record_GetNumDrivers@0"); - F_GETPROC(FSOUND_Record_GetDriverName, "_FSOUND_Record_GetDriverName@4"); - F_GETPROC(FSOUND_Record_GetDriver, "_FSOUND_Record_GetDriver@0"); - F_GETPROC(FSOUND_Record_StartSample, "_FSOUND_Record_StartSample@8"); - F_GETPROC(FSOUND_Record_Stop, "_FSOUND_Record_Stop@0"); - F_GETPROC(FSOUND_Record_GetPosition, "_FSOUND_Record_GetPosition@0"); - F_GETPROC(FSOUND_File_SetCallbacks, "_FSOUND_File_SetCallbacks@20"); - F_GETPROC(FMUSIC_LoadSong, "_FMUSIC_LoadSong@4"); - F_GETPROC(FMUSIC_LoadSongEx, "_FMUSIC_LoadSongEx@24"); - F_GETPROC(FMUSIC_GetOpenState, "_FMUSIC_GetOpenState@4"); - F_GETPROC(FMUSIC_FreeSong, "_FMUSIC_FreeSong@4"); - F_GETPROC(FMUSIC_PlaySong, "_FMUSIC_PlaySong@4"); - F_GETPROC(FMUSIC_StopSong, "_FMUSIC_StopSong@4"); - F_GETPROC(FMUSIC_StopAllSongs, "_FMUSIC_StopAllSongs@0"); - F_GETPROC(FMUSIC_SetZxxCallback, "_FMUSIC_SetZxxCallback@8"); - F_GETPROC(FMUSIC_SetRowCallback, "_FMUSIC_SetRowCallback@12"); - F_GETPROC(FMUSIC_SetOrderCallback, "_FMUSIC_SetOrderCallback@12"); - F_GETPROC(FMUSIC_SetInstCallback, "_FMUSIC_SetInstCallback@12"); - F_GETPROC(FMUSIC_SetSample, "_FMUSIC_SetSample@12"); - F_GETPROC(FMUSIC_SetUserData, "_FMUSIC_SetUserData@8"); - F_GETPROC(FMUSIC_OptimizeChannels, "_FMUSIC_OptimizeChannels@12"); - F_GETPROC(FMUSIC_SetReverb, "_FMUSIC_SetReverb@4"); - F_GETPROC(FMUSIC_SetLooping, "_FMUSIC_SetLooping@8"); - F_GETPROC(FMUSIC_SetOrder, "_FMUSIC_SetOrder@8"); - F_GETPROC(FMUSIC_SetPaused, "_FMUSIC_SetPaused@8"); - F_GETPROC(FMUSIC_SetMasterVolume, "_FMUSIC_SetMasterVolume@8"); - F_GETPROC(FMUSIC_SetMasterSpeed, "_FMUSIC_SetMasterSpeed@8"); - F_GETPROC(FMUSIC_SetPanSeperation, "_FMUSIC_SetPanSeperation@8"); - F_GETPROC(FMUSIC_GetName, "_FMUSIC_GetName@4"); - F_GETPROC(FMUSIC_GetType, "_FMUSIC_GetType@4"); - F_GETPROC(FMUSIC_GetNumOrders, "_FMUSIC_GetNumOrders@4"); - F_GETPROC(FMUSIC_GetNumPatterns, "_FMUSIC_GetNumPatterns@4"); - F_GETPROC(FMUSIC_GetNumInstruments, "_FMUSIC_GetNumInstruments@4"); - F_GETPROC(FMUSIC_GetNumSamples, "_FMUSIC_GetNumSamples@4"); - F_GETPROC(FMUSIC_GetNumChannels, "_FMUSIC_GetNumChannels@4"); - F_GETPROC(FMUSIC_GetSample, "_FMUSIC_GetSample@8"); - F_GETPROC(FMUSIC_GetPatternLength, "_FMUSIC_GetPatternLength@8"); - F_GETPROC(FMUSIC_IsFinished, "_FMUSIC_IsFinished@4"); - F_GETPROC(FMUSIC_IsPlaying, "_FMUSIC_IsPlaying@4"); - F_GETPROC(FMUSIC_GetMasterVolume, "_FMUSIC_GetMasterVolume@4"); - F_GETPROC(FMUSIC_GetGlobalVolume, "_FMUSIC_GetGlobalVolume@4"); - F_GETPROC(FMUSIC_GetOrder, "_FMUSIC_GetOrder@4"); - F_GETPROC(FMUSIC_GetPattern, "_FMUSIC_GetPattern@4"); - F_GETPROC(FMUSIC_GetSpeed, "_FMUSIC_GetSpeed@4"); - F_GETPROC(FMUSIC_GetBPM, "_FMUSIC_GetBPM@4"); - F_GETPROC(FMUSIC_GetRow, "_FMUSIC_GetRow@4"); - F_GETPROC(FMUSIC_GetPaused, "_FMUSIC_GetPaused@4"); - F_GETPROC(FMUSIC_GetTime, "_FMUSIC_GetTime@4"); - F_GETPROC(FMUSIC_GetRealChannel, "_FMUSIC_GetRealChannel@8"); - F_GETPROC(FMUSIC_GetUserData, "_FMUSIC_GetUserData@4"); - - return instance; -} - -static void FMOD_FreeInstance(FMOD_INSTANCE *instance) -{ - if (instance) - { - if (instance->module) - { -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) - FreeLibrary((HMODULE)instance->module); -#else - dlclose(instance->module); -#endif - } - free(instance); - } -} - -#endif diff --git a/tools/gdbst03/Makefile b/tools/gdbst03/Makefile deleted file mode 100644 index 5279e5b55..000000000 --- a/tools/gdbst03/Makefile +++ /dev/null @@ -1,83 +0,0 @@ -# -# Makefile for GDB Stub for DJGPP/Mingw 0.3 source distribution -# -# Copyright 2000 by Jonathan Brogdon -# - -include Makefile.cfg - -default: - @$(ECHO) Welcome to GDB Stub for DJGPP & Mingw 0.3 source distribution! - @$(ECHO) To make the GDB stub type: - @$(ECHO) make all - Make library and demo programs - @$(ECHO) make library - Make only library - @$(ECHO) make demo - Make demo program - @$(ECHO) make install - Install library and header files - @$(ECHO) make uninstall - Uninstall library and header files - @$(ECHO) make clean - Remove .o files - @$(ECHO) make distclean - Remove ready binaries and .o files - @$(ECHO) make dep - Make dependences - -# Inform make of phony targets -.PHONY: library demo clean blankdep dep distclean install - -all: dep library demo - @$(ECHO) Library and demo program created - -./lib/libgdbst.a: - @mkdir -p lib - @make -s -C ./src/library all - -library: ./lib/libgdbst.a - @$(ECHO) Library created - -demo: ./lib/libgdbst.a - @mkdir -p demo - @make -s -C ./src/demo all - @$(ECHO) Demo program created - -clean: - @make -s -C ./src/library clean - @make -s -C ./src/demo clean - @$(ECHO) Clean complete - -blankdep: -# Create blank depend.dep files to avoid errors - @$(ECHOBLANK) > ./src/library/depend.dep - @$(ECHOBLANK) > ./src/demo/depend.dep - -# Now carry on as usual -dep: blankdep - @make -s -C ./src/library dep - @make -s -C ./src/demo dep - @$(ECHO) Created dependency files - -# Blank all the dependencies too -distclean: blankdep - @make -s -C ./src/library distclean - @make -s -C ./src/demo distclean - @$(RM) -r ./demo/ - @$(RM) -r ./lib/ - @$(ECHO) Cleaned up files - -install: library -ifdef DJGPP - @cp lib/*.a $(DJDIR)/lib - @ginstall -d $(DJDIR)/include - @cp include/*.h $(DJDIR)/include - @$(ECHO) GDB Stub Library for DJGPP installed -endif - -uninstall: -ifdef DJGPP - @$(RM) $(DJDIR)/lib/libgdb.a - @$(RM) $(DJDIR)/include/i386-stub.h - @$(ECHO) GDB Stub Library for DJGPP uninstalled -ifdef DJGPP - - - - - - - diff --git a/tools/gdbst03/announce b/tools/gdbst03/announce deleted file mode 100644 index ac976b644..000000000 --- a/tools/gdbst03/announce +++ /dev/null @@ -1,27 +0,0 @@ -GDB Stub for DJGPP 0.1 Announcement -=================================== - -GDB Stub for DJGPP Copyright 2000 by Jonathan Brogdon - -Hello. - - I'd like to announce the GDB Stub for DJGPP for DJGPP, the latest version of -a GDB stub for DJGPP targets. The GDB Stub for DJGPP conforms to the GNU GDB stub -interface as specified in the GDB User's Manual. It allows for debugging of a -DJGPP target remotely over a serial link with GDB. - - It comes with an example program for demonstrating remote debugging of -DJGPP targets, and documentation (man and HTML pages). - - The GDB Stub for DJGPP is distributed under the GNU Library General Public License -(LGPL). - - If you have any questions relating to libsocket, please mail me and I'll -be happy to help. - - Thanks, - - Jonathan Brogdon - - - June 29th 2000 diff --git a/tools/gdbst03/include/i386-stub.h b/tools/gdbst03/include/i386-stub.h deleted file mode 100644 index 092a3dfc6..000000000 --- a/tools/gdbst03/include/i386-stub.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - * - * i386-stub.h - * - * Description: Data definitions and constants for low level - * GDB server support. - * - * Terms of use: This software is provided for use under the terms - * and conditions of the GNU General Public License. - * You should have received a copy of the GNU General - * Public License along with this program; if not, write - * to the Free Software Foundation, Inc., 59 Temple Place - * Suite 330, Boston, MA 02111-1307, USA. - * - * Credits: Created by Jonathan Brogdon - * - * History - * Engineer: Date: Notes: - * --------- ----- ------ - * Jonathan Brogdon 20000617 Genesis - * Gordon Schumacher 20020212 Updated for modularity - * - ****************************************************************************/ -#ifndef _GDBSTUB_H_ -#define _GDBSTUB_H_ - - -#ifdef __cplusplus -extern "C" { -#endif -extern int gdb_serial_init(unsigned int port, unsigned int speed); -extern void gdb_target_init(void); -extern void gdb_target_close(void); - -extern void set_debug_traps(void); -extern void restore_traps(void); -extern void breakpoint(void); -#ifdef __cplusplus -} -#endif - - -#endif /* _GDBSTUB_H_ */ diff --git a/tools/gdbst03/install b/tools/gdbst03/install deleted file mode 100644 index b92c39c04..000000000 --- a/tools/gdbst03/install +++ /dev/null @@ -1,20 +0,0 @@ -The makefile contains the information about the target products -available. - -Note: Makefile.cfg contains macros for various tools used during -the build process. Of particular note: some folks use the echo.exe -that is available from the DJGPP (or other) site(s). Others may not -have installed this, and therefore calls to echo during the build -will use the built-in DOS echo command. When attempting to echo a -blank line, the arguments to these two echo commands are different. -Therefore, makefile.cfg contains the macro ECHOBLANK. Please set -this macro according to the needs of your environment. If you change -this in makefile.cfg, it will be picked up by all other project -makefiles. - -Type 'make' to see a list of targets. When the 'install' -target is made, the libgdb.a will be copied into your $(DJDIR)/lib -directory. In addition, the i386-stub.h file will be copied into -your $(DJDIR)/include directory. The uninstall target will remove -these files. - diff --git a/tools/gdbst03/license b/tools/gdbst03/license deleted file mode 100644 index 4356f26ed..000000000 --- a/tools/gdbst03/license +++ /dev/null @@ -1,454 +0,0 @@ - -GNU LIBRARY GENERAL PUBLIC LICENSE -********************************** - - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - [This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - -Preamble -======== - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it in -new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License, which was designed for utility -programs. This license, the GNU Library General Public License, -applies to certain designated libraries. This license is quite -different from the ordinary one; be sure to read it in full, and don't -assume that anything in it is the same as in the ordinary license. - - The reason we have a separate public license for some libraries is -that they blur the distinction we usually make between modifying or -adding to a program and simply using it. Linking a program with a -library, without changing the library, is in some sense simply using -the library, and is analogous to running a utility program or -application program. However, in a textual and legal sense, the linked -executable is a combined work, a derivative of the original library, -and the ordinary General Public License treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended -to permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to -achieve this as regards changes in header files, but we have achieved -it as regards changes in the actual functions of the Library.) The -hope is that this will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which - contains a notice placed by the copyright holder or other - authorized party saying it may be distributed under the terms of - this Library General Public License (also called "this License"). - Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data - prepared so as to be conveniently linked with application programs - (which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work - which has been distributed under these terms. A "work based on the - Library" means either the Library or any derivative work under - copyright law: that is to say, a work containing the Library or a - portion of it, either verbatim or with modifications and/or - translated straightforwardly into another language. (Hereinafter, - translation is included without limitation in the term - "modification".) - - "Source code" for a work means the preferred form of the work for - making modifications to it. For a library, complete source code - means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to - control compilation and installation of the library. - - Activities other than copying, distribution and modification are - not covered by this License; they are outside its scope. The act - of running a program using the Library is not restricted, and - output from such a program is covered only if its contents - constitute a work based on the Library (independent of the use of - the Library in a tool for writing it). Whether that is true - depends on what the Library does and what the program that uses - the Library does. - - 1. You may copy and distribute verbatim copies of the Library's - complete source code as you receive it, in any medium, provided - that you conspicuously and appropriately publish on each copy an - appropriate copyright notice and disclaimer of warranty; keep - intact all the notices that refer to this License and to the - absence of any warranty; and distribute a copy of this License - along with the Library. - - You may charge a fee for the physical act of transferring a copy, - and you may at your option offer warranty protection in exchange - for a fee. - - 2. You may modify your copy or copies of the Library or any portion - of it, thus forming a work based on the Library, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a. The modified work must itself be a software library. - - b. You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c. You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d. If a facility in the modified Library refers to a function or - a table of data to be supplied by an application program that - uses the facility, other than as an argument passed when the - facility is invoked, then you must make a good faith effort - to ensure that, in the event an application does not supply - such function or table, the facility still operates, and - performs whatever part of its purpose remains meaningful. - - (For example, a function in a library to compute square roots - has a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function - must be optional: if the application does not supply it, the - square root function must still compute square roots.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the - Library, and can be reasonably considered independent and separate - works in themselves, then this License, and its terms, do not - apply to those sections when you distribute them as separate - works. But when you distribute the same sections as part of a - whole which is a work based on the Library, the distribution of - the whole must be on the terms of this License, whose permissions - for other licensees extend to the entire whole, and thus to each - and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or - contest your rights to work written entirely by you; rather, the - intent is to exercise the right to control the distribution of - derivative or collective works based on the Library. - - In addition, mere aggregation of another work not based on the - Library with the Library (or with a work based on the Library) on - a volume of a storage or distribution medium does not bring the - other work under the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public - License instead of this License to a given copy of the Library. - To do this, you must alter all the notices that refer to this - License, so that they refer to the ordinary GNU General Public - License, version 2, instead of to this License. (If a newer - version than version 2 of the ordinary GNU General Public License - has appeared, then you can specify that version instead if you - wish.) Do not make any other change in these notices. - - Once this change is made in a given copy, it is irreversible for - that copy, so the ordinary GNU General Public License applies to - all subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of - the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or - derivative of it, under Section 2) in object code or executable - form under the terms of Sections 1 and 2 above provided that you - accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software - interchange. - - If distribution of object code is made by offering access to copy - from a designated place, then offering equivalent access to copy - the source code from the same place satisfies the requirement to - distribute the source code, even though third parties are not - compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the - Library, but is designed to work with the Library by being - compiled or linked with it, is called a "work that uses the - Library". Such a work, in isolation, is not a derivative work of - the Library, and therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library - creates an executable that is a derivative of the Library (because - it contains portions of the Library), rather than a "work that - uses the library". The executable is therefore covered by this - License. Section 6 states terms for distribution of such - executables. - - When a "work that uses the Library" uses material from a header - file that is part of the Library, the object code for the work may - be a derivative work of the Library even though the source code is - not. Whether this is true is especially significant if the work - can be linked without the Library, or if the work is itself a - library. The threshold for this to be true is not precisely - defined by law. - - If such an object file uses only numerical parameters, data - structure layouts and accessors, and small macros and small inline - functions (ten lines or less in length), then the use of the object - file is unrestricted, regardless of whether it is legally a - derivative work. (Executables containing this object code plus - portions of the Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may - distribute the object code for the work under the terms of Section - 6. Any executables containing that work also fall under Section 6, - whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or - link a "work that uses the Library" with the Library to produce a - work containing portions of the Library, and distribute that work - under terms of your choice, provided that the terms permit - modification of the work for the customer's own use and reverse - engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the - Library is used in it and that the Library and its use are covered - by this License. You must supply a copy of this License. If the - work during execution displays copyright notices, you must include - the copyright notice for the Library among them, as well as a - reference directing the user to the copy of this License. Also, - you must do one of these things: - - a. Accompany the work with the complete corresponding - machine-readable source code for the Library including - whatever changes were used in the work (which must be - distributed under Sections 1 and 2 above); and, if the work - is an executable linked with the Library, with the complete - machine-readable "work that uses the Library", as object code - and/or source code, so that the user can modify the Library - and then relink to produce a modified executable containing - the modified Library. (It is understood that the user who - changes the contents of definitions files in the Library will - not necessarily be able to recompile the application to use - the modified definitions.) - - b. Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - c. If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the - above specified materials from the same place. - - d. Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the - Library" must include any data and utility programs needed for - reproducing the executable from it. However, as a special - exception, the source code distributed need not include anything - that is normally distributed (in either source or binary form) - with the major components (compiler, kernel, and so on) of the - operating system on which the executable runs, unless that - component itself accompanies the executable. - - It may happen that this requirement contradicts the license - restrictions of other proprietary libraries that do not normally - accompany the operating system. Such a contradiction means you - cannot use both them and the Library together in an executable - that you distribute. - - 7. You may place library facilities that are a work based on the - Library side-by-side in a single library together with other - library facilities not covered by this License, and distribute - such a combined library, provided that the separate distribution - of the work based on the Library and of the other library - facilities is otherwise permitted, and provided that you do these - two things: - - a. Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b. Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same - work. - - 8. You may not copy, modify, sublicense, link with, or distribute the - Library except as expressly provided under this License. Any - attempt otherwise to copy, modify, sublicense, link with, or - distribute the Library is void, and will automatically terminate - your rights under this License. However, parties who have - received copies, or rights, from you under this License will not - have their licenses terminated so long as such parties remain in - full compliance. - - 9. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify - or distribute the Library or its derivative works. These actions - are prohibited by law if you do not accept this License. - Therefore, by modifying or distributing the Library (or any work - based on the Library), you indicate your acceptance of this - License to do so, and all its terms and conditions for copying, - distributing or modifying the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the - Library), the recipient automatically receives a license from the - original licensor to copy, distribute, link with or modify the - Library subject to these terms and conditions. You may not impose - any further restrictions on the recipients' exercise of the rights - granted herein. You are not responsible for enforcing compliance - by third parties to this License. - - 11. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent - issues), conditions are imposed on you (whether by court order, - agreement or otherwise) that contradict the conditions of this - License, they do not excuse you from the conditions of this - License. If you cannot distribute so as to satisfy simultaneously - your obligations under this License and any other pertinent - obligations, then as a consequence you may not distribute the - Library at all. For example, if a patent license would not permit - royalty-free redistribution of the Library by all those who - receive copies directly or indirectly through you, then the only - way you could satisfy both it and this License would be to refrain - entirely from distribution of the Library. - - If any portion of this section is held invalid or unenforceable - under any particular circumstance, the balance of the section is - intended to apply, and the section as a whole is intended to apply - in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of - any such claims; this section has the sole purpose of protecting - the integrity of the free software distribution system which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is - willing to distribute software through any other system and a - licensee cannot impose that choice. - - This section is intended to make thoroughly clear what is believed - to be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in - certain countries either by patents or by copyrighted interfaces, - the original copyright holder who places the Library under this - License may add an explicit geographical distribution limitation - excluding those countries, so that distribution is permitted only - in or among countries not thus excluded. In such case, this - License incorporates the limitation as if written in the body of - this License. - - 13. The Free Software Foundation may publish revised and/or new - versions of the Library General Public License from time to time. - Such new versions will be similar in spirit to the present version, - but may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the - Library specifies a version number of this License which applies - to it and "any later version", you have the option of following - the terms and conditions either of that version or of any later - version published by the Free Software Foundation. If the Library - does not specify a license version number, you may choose any - version ever published by the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free - programs whose distribution conditions are incompatible with these, - write to the author to ask for permission. For software which is - copyrighted by the Free Software Foundation, write to the Free - Software Foundation; we sometimes make exceptions for this. Our - decision will be guided by the two goals of preserving the free - status of all derivatives of our free software and of promoting - the sharing and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO - WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE - LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT - HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT - WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT - NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE - QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE - LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY - SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN - WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY - MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE - LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, - INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR - INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF - DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU - OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY - OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - diff --git a/tools/gdbst03/makefile.cfg b/tools/gdbst03/makefile.cfg deleted file mode 100644 index 4265258a7..000000000 --- a/tools/gdbst03/makefile.cfg +++ /dev/null @@ -1,67 +0,0 @@ -# -# Makefile.cfg for GDB stub for DJGPP and Mingw -# -# libgdbst Copyright 2000 by Jonathan Brogodn -# - -# -# GNU compiler & tools' flags -# -CC = gcc -CFLAGS = -Wall -Werror -march=i486 -O2 -g - -# Archiver -AR = ar -ARFLAGS = -r - -# Stripper -STRIP = strip - -# Assembler -AS = as -ASFLAGS = - -# Linker -LD = ld -LDFLAGS = - -# Remove -RM = rm -f - -# Echo -ECHO = echo - -# Echo Blank -#ECHOBLANK = echo "" -ECHOBLANK = echo. - -# -# check for OS... badly -# - -ifndef DJDIR -ifndef DJGPP - WINDOWS=1 -endif -endif - -ifndef windir -ifndef WINDOWS - DJGPP=1 -endif -endif - -# -# Rules -# -.SUFFIXES: .c .asm .o - -.asm.o: - @$(CC) $(CFLAGS) -I$(INC_PATH) -c -o ./$@ ./$< - -.s.o: - @$(AS) $(ASFLAGS) ./$< - -.c.o : - @$(CC) $(CFLAGS) -c -I$(INC_PATH) -c -o ./$@ ./$< - diff --git a/tools/gdbst03/readme b/tools/gdbst03/readme deleted file mode 100644 index 316e61cae..000000000 --- a/tools/gdbst03/readme +++ /dev/null @@ -1,171 +0,0 @@ -GDB Stub for DJGPP 0.2 Readme File -================================== - -Copyright ---------- -GDB Stub for DJGPP is distributed under the terms of the GNU Library -General Public License (GNU LGPL) - please see the document LICENSE, -which should be found in the same directory as this file. - -Copyright (c) 2000 by Jonathan Brogdon, 2002 by Gordon Schumacher - -What It Does ------------- -The GDB stub is used to debug a DJGPP target remotely over a one of -the PC COM ports. GDB, running on a host machine, communicates with -the target using the GDB serial protocol over the serial link. For -more information on the GDB stub, see "Debugging with GDB, The GNU -Source-Level Debugger", by Richard M. Stallman and Roland H. Pesch -(http://sources.redhat.com/gdb/download/onlinedocs/gdb.html) - -How It Works ------------- - -Exceptions: - -The GDB stub needs to handle all processor exceptions. Since these -exceptions already handled by DJGPP, we cannot handle them directly. -DJGPP maps all processor exceptions to signals. Therefore, we can -install the GDB stub handler as the signal handler for those signals -that represent processor exceptions. The following table shows the -processor exception to signal mapping: - - Exception/Interrupt: Exception #: Signal: - ------------------- ----------- ------ - Divide Error 0 SIGFPE - Debug Exception 1 SIGTRAP - NMI Interrupt 2 No signal defined - Breakpoint 3 SIGTRAP - INTO-detected overflow 4 SIGFPE - BOUND Range Exceeded 5 SIGSEGV - Invalid Opcode 6 No signal defined - Coprocessor not available 7 SIGNOFP - Double Fault 8 SIGSEGV - Coprocessor Seg overrun 9 SIGSEGV - Invalid Task State Seg 10 No signal defined - Segment not present 11 SIGSEGV - Stack Fault 12 SIGSEGV - General Protection Fault 13 SIGSEGV - Page Fault 14 SIGSEGV - Intel Reserved 15 No signal defined - Coprocessor Error 16 SIGFPE - -The GDB stub handler services requests from the GDB host. These -requests are seen by the GDB stub handler as command messages from -the GDB host. These commands and command formats are defined in -"Debugging with GDB, The GNU Source-Level Debugger", by Richard M. -Stallman and Roland H. Pesch (http://sources.redhat.com/gdb/ -download/onlinedocs/gdb.html -- one of many sources). - -Serial Interface: - -Interface functions for sending and receiving characters from the -serial interface must be provided by the engineer porting the GDB -stub. The following funtions must be provided to support the -implementation. - - int getDebugChar(void); - void putDebugChar(int c); - -There are a variety of serial libraries for DJGPP. The user may -already be using one of these libraries in their application, and -installing more than one serial library often causes conflicts. -To this end, a modular function layer was written that allows any -serial library to be used with the GDB stub. Layers have been -written to support SVAsync, DZComm, and the _bios_serialcom() -function. At the time of this writing, DZComm appears to work the -best for serial debugging. - -Hard Coded Breakpoint: - -A breakpoint() function is provided to manually invoke the stub. -This function, inserts a breakpoint instruction directly in the code -to invoke the GDB stub handler. - -How You Use It --------------- -First, you need to select a serial library. In the i386-supp.c file, -there are lines of the form - - // #include "some_layer.h" - -Uncomment the line for the serial library you intend to use - or add -a new include line for a file written for some other library. -In the main() function of your target program, you should initilize -the GDB serial handlers and the GDB stub. The following functions -are provided in the GDB stub library for this purpose. - - gdb_serial_init(unsigned int port, unsigned int speed); - gdb_target_init(void); - -Where, port is the COM port number, and speed is the baud rate for -the serial link. - -After initialing the GDB serial interface and target, you should -invoke the breakpoint() function somewhere. You may choose to do -this immediately after initialization, or at a specific location in -your code where you wish to set a breakpoint. By putting the -breakpoint() function in the beginning of main(), you can use the -GDB host to set a breakpoint at any place in your code. - -Make sure that you use the '-g' option when compiling your files with -gcc. - -After the target executable is running, start up gdb on the host, -passing the target executable as an argument. - - Example: gdb demo.exe - -Now, tell gdb which serial interface to use for communicating to -the target. - - Example: (gdb) target remote COM1 - -This example uses COM1 on the host to communicate with the target. -GDB is now 'listening' on COM for a valid GDB serial packet. - -Once your GDB host finds your target, you may need to tell GDB where -to find any source files which were used to generate your program. -Use the directory command to do this. - - Example: (gdb) directory ../src/demo - -That's it. You should now be able to single step through code, set -breakpoints, set variables, examine variables, any anthing else that -you would normally use GDB to accomplish. - -What You Build --------------- -Read the INSTALL file for more information on installing the GDB stub -library. After installing the library, your code should include -i386-stub.h for function prototypes. In addition, your code should -link against the libgdb.a library. The source for a demonstration -program has been included with this distributias an example. -As an alternative, you can simply include the i386-stub and i386-supp -files and the layer header for the serial library you plan to use into -your project and link them in directly. - -For More Info -------------- -See "Debugging with GDB, The GNU Source-Level Debugger", by Richard -M. Stallman and Roland H. Pesch (http://sources.redhat.com/gdb/ -download/onlinedocs/gdb.html -- one of many sources). - -TODO ----- -Port for network operation. - -Contact Info ------------- -My contact info is below. If you have any comments, suggestions, bug -reports or problems, please mail me, and I'll see what I can do. - - Regards, - Jonathan Brogdon - - 6th June 2000 - - Modular update: - Gordon Schumacher - - 12th February 2002 \ No newline at end of file diff --git a/tools/gdbst03/src/demo/crc_16.c b/tools/gdbst03/src/demo/crc_16.c deleted file mode 100644 index ad1f53cd1..000000000 --- a/tools/gdbst03/src/demo/crc_16.c +++ /dev/null @@ -1,46 +0,0 @@ -#define POLY 0x8408 -/* -// 16 12 5 -// this is the CCITT CRC 16 polynomial X + X + X + 1. -// This works out to be 0x1021, but the way the algorithm works -// lets us use 0x8408 (the reverse of the bit pattern). The high -// bit is always assumed to be set, thus we only use 16 bits to -// represent the 17 bit value. -*/ - -#include "crc.h" - -WORD crc16(char *data_p, WORD length) -{ - unsigned char i; - unsigned int data; - unsigned int crc = 0xffff; - - if (length == 0) - return (~crc); - - do - { - for (i=0, data=(unsigned int)0xff & *data_p++; - i < 8; - i++, data >>= 1) - { - if ((crc & 0x0001) ^ (data & 0x0001)) - crc = (crc >> 1) ^ POLY; - else crc >>= 1; - } - } while (--length); - - crc = ~crc; - data = crc; - crc = (crc << 8) | ((data >> 8) & 0xff); - - return (crc); -} - - - - - - - diff --git a/tools/gdbst03/src/demo/makefile b/tools/gdbst03/src/demo/makefile deleted file mode 100644 index ab48954b2..000000000 --- a/tools/gdbst03/src/demo/makefile +++ /dev/null @@ -1,42 +0,0 @@ -# -# Makefile for GDB Stub demo -# Written by Jonathan Brogodn -# -# GDB Stub for DJGPP Copyright 2000 by Jonathan Brogdon -# - -include ../../Makefile.cfg - -CFLAGS += -g -CFLAGS += -I../../include -I../include -I. -CFLAGS += -DDEBUG_COM_PORT=1 -CFLAGS += -DDEBUG_COM_PORT_SPEED=9600 -CFLAGS += -DREMOTE_DEBUGGING - -# Objects to build -OBJS = serdbg.o crc_16.o - -all: demo - -demo: $(OBJS) -ifdef DJGPP - @$(LD) $(LDFLAGS) -Map ./$@.map -o../../demo/$@.exe $(DJDIR)/lib/crt0.o $(OBJS) -L$(DJDIR)/lib -L../../lib -lgdbst -ldzcom -lc -lgcc -endif -ifdef WINDOWS - @$(LD) $(LDFLAGS) -Map ./$@.map -o../../demo/$@.exe $(DJDIR)/lib/crt0.o $(OBJS) -L../../lib -lgdbst -lwsock32 -lc -lgcc -endif - -clean: - @$(RM) $(OBJS) - @$(RM) *.map - -distclean: clean - @$(RM) $(OBJS) - @$(RM) depend.dep - @$(RM) ../../demo/*.exe - -dep: - @$(CC) $(CFLAGS) -M *.c > depend.dep - -$(OBJS): -include depend.dep diff --git a/tools/gdbst03/src/demo/serdbg.c b/tools/gdbst03/src/demo/serdbg.c deleted file mode 100644 index 01778789c..000000000 --- a/tools/gdbst03/src/demo/serdbg.c +++ /dev/null @@ -1,102 +0,0 @@ -/*********************************************************************** - * serdbg.c - * - * Description: Pretty simple demonstration program. It accomplishes - * the following. - * - * 1. Allocate a block of memory Feel free to change - * size (memBlockSize) with debugger. - * - * 2. Writes a word pattern to the entire block. Feel - * free to change the pattern (memPatternWord) with - * debugger. - * - * 3. Computes the CRC-16 on the block. Feel free to - * check the size with the debuger. - * - * 4. Free the memory block allocated in step 1. Repeat - * step 1. If you wish to exit, set doneFlag to 0 with - * the debugger. - * - * Credits: Created by Jonathan Brogdon - * - * Terms of use: Use as you will. - * - * Global Data: None. - * Global Functions: main - * - * History - * Engineer: Date: Notes: - * --------- ----- ------ - * Jonathan Brogdon 070500 Genesis - * - ***********************************************************************/ -#include -#include -#include -#include - -#define MEM_BLOCK_SIZE 100 /* Words */ -#define MEM_PATTERN_WORD 0x55AA - -void write_mem_pattern(unsigned short*, unsigned short, unsigned short); - -/************************************************************************ - * - * main() - * - ************************************************************************/ -int main(int argc, char *argv[]) -{ - volatile int doneFlag = 0; - unsigned short crcValue = 0; - unsigned short * memBlockPtr = NULL; - short memBlockSize = MEM_BLOCK_SIZE; - short memPatternWord = MEM_PATTERN_WORD; - -#ifdef REMOTE_DEBUGGING - /* Only setup if demonstrating remote debugging */ - gdb_serial_init(DEBUG_COM_PORT,DEBUG_COM_PORT_SPEED); - gdb_target_init(); - breakpoint(); -#endif - - while(doneFlag != 1) - { - memBlockSize = MEM_BLOCK_SIZE; - memPatternWord = MEM_PATTERN_WORD; - memBlockPtr = (unsigned short *) malloc((int)memBlockSize); - - write_mem_pattern(memBlockPtr, memBlockSize, memPatternWord); - - crcValue = crc16((char *)memBlockPtr,memBlockSize); - - free(memBlockPtr); - } - - exit(0); -} - -/************************************************************************ - * - * write_mem_pattern() - * - * Description: Writes a word pattern to a block of RAM. - * - ************************************************************************/ -void write_mem_pattern(unsigned short *block, unsigned short blockSize, unsigned short patternWord) -{ - int index = 0; - - for(index = 0; index < blockSize; index++) - { - block[index] = patternWord; - } -} - - - - - - - diff --git a/tools/gdbst03/src/include/crc.h b/tools/gdbst03/src/include/crc.h deleted file mode 100644 index 937d0b794..000000000 --- a/tools/gdbst03/src/include/crc.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * CRC.H - header file for CRC functions - */ - -#ifndef _CRC_H_ -#define _CRC_H_ - -#include /* For size_t */ - -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned long DWORD; - -/* -** File: CRC-16.C -*/ - -WORD crc16(char *data_p, WORD length); - -#endif /* _CRC_H_ */ diff --git a/tools/gdbst03/src/include/i386-supp.h b/tools/gdbst03/src/include/i386-supp.h deleted file mode 100644 index e1923377c..000000000 --- a/tools/gdbst03/src/include/i386-supp.h +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** - * - * i386-supp.h - * - * Description: Data definitions and constants for low level - * GDB stub support. - * - * Terms of use: This software is provided for use under the terms - * and conditions of the GNU General Public License. - * You should have received a copy of the GNU General - * Public License along with this program; if not, write - * to the Free Software Foundation, Inc., 59 Temple Place - * Suite 330, Boston, MA 02111-1307, USA. - * - * Credits: Created by Jonathan Brogdon - * - * History - * Engineer: Date: Notes: - * --------- ----- ------ - * Jonathan Brogdon 20000629 Genesis - * Gordon Schumacher 20020212 Updated for modularity - * - ****************************************************************************/ -#ifndef _GDBSUPP_H_ -#define _GDBSUPP_H_ - -extern int putDebugChar(char c); -extern int getDebugChar(void); - -#endif /* _GDBSUPP_H_ */ diff --git a/tools/gdbst03/src/library/bios_layer.h b/tools/gdbst03/src/library/bios_layer.h deleted file mode 100644 index 946f40997..000000000 --- a/tools/gdbst03/src/library/bios_layer.h +++ /dev/null @@ -1,137 +0,0 @@ -//======================================================================================================= -// bios_layer.h - Serial command layer for standard BIOS calls -// It's here if you want it, but I wouldn't suggest it... -//======================================================================================================= - -//======================================================================================================= -//======================================================================================================= - -#ifndef _BIOS_LAYER_H -#define _BIOS_LAYER_H - - -//=============================================================================== -// Include files -//=============================================================================== - -#include - -//=============================================================================== -// Static variable definitions -//=============================================================================== - -unsigned comport; - -//=============================================================================== -// Inline function definitions -//=============================================================================== - -#define BIOS_SER_TIMEOUT 1000000 - -// Initialize the serial library -// Should return 0 if no error occurred -__inline int GDBStub_SerInit(int port) -{ - comport = (unsigned) port; - return 0; -} - - -// Set the serial port speed (and other configurables) -// Should return 0 if the speed is set properly -__inline int GDBStub_SerSpeed(int speed) -{ - unsigned bps; - - switch (speed) - { - case 110: - bps = _COM_110; - break; - - case 150: - bps = _COM_150; - break; - - case 300: - bps = _COM_300; - break; - - case 600: - bps = _COM_600; - break; - - case 1200: - bps = _COM_1200; - break; - - case 2400: - bps = _COM_2400; - break; - - case 4800: - bps = _COM_4800; - break; - - case 9600: - default: - bps = _COM_9600; - break; - } - - _bios_serialcom(_COM_INIT, comport, - bps | _COM_NOPARITY | _COM_CHR8 | _COM_STOP1); - return 0; -} - - -// Check to see if there's room in the buffer to send data -// Should return 0 if it is okay to send -__inline int GDBStub_SerSendOk(void) -{ - return 0; -} - - -// Send a character to the serial port -// Should return 0 if the send succeeds -__inline int GDBStub_SerSend(int c) -{ - register int ret; - register int timeout = 0; - - do - { - ret = _bios_serialcom(_COM_SEND, comport, (unsigned) c); - } while((ret != 0) && (timeout++ < BIOS_SER_TIMEOUT)); - return (timeout >= BIOS_SER_TIMEOUT); -} - - -// Check to see if there are characters waiting in the buffer -// Should return 0 if there's data waiting -__inline int GDBStub_SerRecvOk(void) -{ - return 0; -} - - -// Read a character from the serial port -// Should return the character read -__inline int GDBStub_SerRecv(void) -{ - register int data; - register int timeout = 0; - - do - { - data = _bios_serialcom(_COM_RECEIVE, comport, 0) & 0xff; - } while((data > 0xff) && (timeout++ < BIOS_SER_TIMEOUT)); - - return data; -} - - - - -#endif diff --git a/tools/gdbst03/src/library/dzc_layer.h b/tools/gdbst03/src/library/dzc_layer.h deleted file mode 100644 index cc083077f..000000000 --- a/tools/gdbst03/src/library/dzc_layer.h +++ /dev/null @@ -1,169 +0,0 @@ -//======================================================================================================= -// dzc_layer.h - Serial command layer for DZcomm -// -//======================================================================================================= - -//======================================================================================================= -//======================================================================================================= - -#ifndef _DZC_LAYER_H -#define _DZC_LAYER_H - - -//=============================================================================== -// Include files -//=============================================================================== - -#include - -//=============================================================================== -// Static variable definitions -//=============================================================================== - -comm_port *comport; - -//=============================================================================== -// Inline function definitions -//=============================================================================== - -// Initialize the serial library -// Should return 0 if no error occurred -__inline int GDBStub_SerInit(int port) -{ - int ret; - comm com; - - ret = dzcomm_init(); - if (ret != 0) - { - switch (port) - { - case 4: - com = _com4; - break; - - case 3: - com = _com3; - break; - - case 2: - com = _com2; - break; - - case 1: - default: - com = _com1; - break; - } - comport = comm_port_init(com); - } - return (ret == 0); -} - -// Set the serial port speed (and other configurables) -// Should return 0 if the speed is set properly -__inline int GDBStub_SerSpeed(int speed) -{ - baud_bits bps; - - switch (speed) - { - case 110: - bps = _110; - break; - - case 150: - bps = _150; - break; - - case 300: - bps = _300; - break; - - case 600: - bps = _600; - break; - - case 1200: - bps = _1200; - break; - - case 2400: - bps = _2400; - break; - - case 4800: - bps = _4800; - break; - - case 9600: - bps = _9600; - break; - - case 19200: - bps = _19200; - break; - - case 38400: - bps = _38400; - break; - - case 57600: - bps = _57600; - break; - - case 115200: - default: - bps = _115200; - break; - } - - comm_port_set_baud_rate(comport, bps); - comm_port_set_parity(comport, NO_PARITY); - comm_port_set_data_bits(comport, BITS_8); - comm_port_set_stop_bits(comport, STOP_1); - comm_port_set_flow_control(comport, RTS_CTS); - comm_port_install_handler(comport); - - return 0; -} - -// Check to see if there's room in the buffer to send data -// Should return 0 if it is okay to send -__inline int GDBStub_SerSendOk(void) -{ - return (comm_port_out_full(comport) == 0); -} - -// Send a character to the serial port -// Should return 0 if the send succeeds -__inline int GDBStub_SerSend(int c) -{ - return comm_port_out(comport, (unsigned char) c); -} - -// Check to see if there are characters waiting in the buffer -// Should return 0 if there's data waiting -__inline int GDBStub_SerRecvOk(void) -{ - return (comm_port_in_empty(comport) == 0); -} - -// Read a character from the serial port -// Should return the character read -__inline int GDBStub_SerRecv(void) -{ - return comm_port_test(comport); -} - - - - -#endif - -/*================================================================== - - $Log: $ - - -===============================================================*/ diff --git a/tools/gdbst03/src/library/i386-stub.c b/tools/gdbst03/src/library/i386-stub.c deleted file mode 100644 index 1ab2ceeeb..000000000 --- a/tools/gdbst03/src/library/i386-stub.c +++ /dev/null @@ -1,1555 +0,0 @@ -/**************************************************************************** - - THIS SOFTWARE IS NOT COPYRIGHTED - - HP offers the following for use in the public domain. HP makes no - warranty with regard to the software or it's performance and the - user accepts the software "AS IS" with all faults. - - HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD - TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - -****************************************************************************/ - -/**************************************************************************** - * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ - * - * Module name: remcom.c $ - * Revision: 1.34 $ - * Date: 91/03/09 12:29:49 $ - * Contributor: Lake Stevens Instrument Division$ - * - * Description: low level support for gdb debugger. $ - * - * Considerations: only works on target hardware $ - * - * Written by: Glenn Engel $ - * ModuleState: Experimental $ - * - * NOTES: See Below $ - * - * Modified for 386 by Jim Kingdon, Cygnus Support. - * - * To enable debugger support, two things need to happen. One, a - * call to set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * Two, a breakpoint needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint(). Breakpoint() - * simulates a breakpoint by executing a trap #1. - * - * The external function exceptionHandler() is - * used to attach a specific handler to a specific 386 vector number. - * It should use the same privilege level it runs at. It should - * install it as an interrupt gate so that interrupts are masked - * while the handler runs. - * - * Because gdb will sometimes write to the stack area to execute function - * calls, this program cannot rely on using the supervisor stack so it - * uses it's own stack area reserved in the int array remcomStack. - * - ************* - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $#. - * - * where - * :: - * :: < two hex digits computed as modulo 256 sum of > - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include -#include -#ifdef DJGPP -#include -#include -#include -#include -#endif //#ifdef DJGPP - - -/* - * - * external low-level support routines - */ - -extern void putDebugChar(); /* write a single character */ -extern int getDebugChar(); /* read and return a single char */ -#ifndef DJGPP -extern void exceptionHandler(); /* assign an exception handler */ -#endif - -/* - * BUFMAX defines the maximum number of characters in inbound/outbound buffers - * at least NUMREGBYTES*2 are needed for register packets - */ -#define BUFMAX 400 - -/* - * boolean flag. != 0 means we've been initialized - */ -static char gdb_initialized; - -/* - * debug > 0 prints ill-formed commands in valid packets & checksum errors - */ -int remote_debug; - -/* - * Hexadecimal character string. - */ -#ifndef DJGPP -static const char hexchars[]="0123456789abcdef"; -#else -static char hexchars[]="0123456789abcdef"; -#endif - -/* - * Number of registers. -*/ -#define NUMREGS 16 - -/* - * Number of bytes of registers. -*/ -#define NUMREGBYTES (NUMREGS * 4) - -/* - * i386 Registers - */ -enum regnames {EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, - PC /* also known as eip */, - PS /* also known as eflags */, - CS, SS, DS, ES, FS, GS -}; - -/* - * Register storage buffer. - */ -static int registers[NUMREGS]; - -/* - * Address of a routine to RTE to if we get a memory fault. -*/ -#ifndef DJGPP -static void (*volatile mem_fault_routine) () = NULL; -#else -static void (*mem_fault_routine)() = NULL; -#endif - -/* I/O buffers */ -static char remcomInBuffer[BUFMAX]; -static char remcomOutBuffer[BUFMAX]; - -#if !(defined(DJGPP) || defined(_WIN32)) //MF -#define STACKSIZE 10000 -int remcomStack[STACKSIZE/sizeof(int)]; -static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; -#endif - -#ifdef DJGPP -static void lock_handler_data(void); -#endif //#ifdef DJGPP - -void _returnFromException (); - -/*************************** ASSEMBLY CODE MACROS *************************/ -/* */ - -extern void -return_to_prog (); - -/* Restore the program's registers (including the stack pointer, which - means we get the right stack and don't have to worry about popping our - return address and any stack frames and so on) and return. */ -asm(".text"); -asm(".globl _return_to_prog"); -asm("_return_to_prog:"); -asm(" movw _registers+44, %ss"); -asm(" movl _registers+16, %esp"); -asm(" movl _registers+4, %ecx"); -asm(" movl _registers+8, %edx"); -asm(" movl _registers+12, %ebx"); -asm(" movl _registers+20, %ebp"); -asm(" movl _registers+24, %esi"); -asm(" movl _registers+28, %edi"); -asm(" movw _registers+48, %ds"); -asm(" movw _registers+52, %es"); -asm(" movw _registers+56, %fs"); -asm(" movw _registers+60, %gs"); -asm(" movl _registers+36, %eax"); -asm(" pushl %eax"); /* saved eflags */ -asm(" movl _registers+40, %eax"); -asm(" pushl %eax"); /* saved cs */ -asm(" movl _registers+32, %eax"); -asm(" pushl %eax"); /* saved eip */ -asm(" movl _registers, %eax"); -/* use iret to restore pc and flags together so - that trace flag works right. */ -asm(" iret"); - -/* - * BREAKPOINT macro - */ -#ifdef _MSC_VER //MF -#define BREAKPOINT() __asm int 3; -#else -#define BREAKPOINT() asm(" int $3"); -#endif - -/* - * Store the error code here just in case the user cares. -*/ -int gdb_i386errcode; - -/* - * Store the vector number here (since GDB only gets the signal - * number through the usual means, and that's not very specific). - */ -#ifndef _WIN32 //MF -int gdb_i386vector = -1; -#endif // !_WIN32 - -#if defined(DJGPP) || defined(_WIN32) -static void handle_exception(int); -#endif - -#ifdef DJGPP - -/*********************************************************************** - * save_regs - * - * Description: Retreives the i386 registers as they were when the - * exception occurred. Registers are stored in the - * local static buffer. - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void save_regs(void) -{ - registers[EAX] = (int) __djgpp_exception_state->__eax; - registers[ECX] = (int) __djgpp_exception_state->__ecx; - registers[EDX] = (int) __djgpp_exception_state->__edx; - registers[EBX] = (int) __djgpp_exception_state->__ebx; - registers[ESP] = (int) __djgpp_exception_state->__esp; - registers[EBP] = (int) __djgpp_exception_state->__ebp; - registers[ESI] = (int) __djgpp_exception_state->__esi; - registers[EDI] = (int) __djgpp_exception_state->__edi; - registers[PC] = (int) __djgpp_exception_state->__eip; - registers[PS] = (int) __djgpp_exception_state->__eflags; - registers[CS] = (int) __djgpp_exception_state->__cs; - registers[SS] = (int) __djgpp_exception_state->__ss; - registers[DS] = (int) __djgpp_exception_state->__ds; - registers[ES] = (int) __djgpp_exception_state->__es; - registers[FS] = (int) __djgpp_exception_state->__fs; - registers[GS] = (int) __djgpp_exception_state->__gs; -} -static void end_save_regs(void){} - -/*********************************************************************** - * set_regs - * - * Description: Restores i386 registers to the DJGPP register buffer. - * DJGPP exception handler will restore registers from - * it's buffer on exit from the handler. - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void set_regs(void) -{ - __djgpp_exception_state->__eax = (unsigned long) registers[EAX]; - __djgpp_exception_state->__ecx = (unsigned long) registers[ECX]; - __djgpp_exception_state->__edx = (unsigned long) registers[EDX]; - __djgpp_exception_state->__ebx = (unsigned long) registers[EBX]; - __djgpp_exception_state->__esp = (unsigned long) registers[ESP]; - __djgpp_exception_state->__ebp = (unsigned long) registers[EBP]; - __djgpp_exception_state->__esi = (unsigned long) registers[ESI]; - __djgpp_exception_state->__edi = (unsigned long) registers[EDI]; - __djgpp_exception_state->__eip = (unsigned long) registers[PC]; - __djgpp_exception_state->__eflags = (unsigned long) registers[PS]; - __djgpp_exception_state->__cs = (unsigned long) registers[CS]; - __djgpp_exception_state->__ss = (unsigned long) registers[SS]; - __djgpp_exception_state->__ds = (unsigned long) registers[DS]; - __djgpp_exception_state->__es = (unsigned long) registers[ES]; - __djgpp_exception_state->__fs = (unsigned long) registers[FS]; - __djgpp_exception_state->__gs = (unsigned long) registers[GS]; -} -static void end_set_regs(void){} - -/*********************************************************************** - * sigsegv_handler - * - * Description: Handles SIGSEGV signal - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void sigsegv_handler(int except_num){ - - /* Save general purpose registers */ - save_regs(); - - /* Dispatch memory fault handling routine if one is registered. */ - if(mem_fault_routine != 0) - { - (*mem_fault_routine)(); - mem_fault_routine = NULL; - } - else - { - /* Save error code */ - gdb_i386errcode = __djgpp_exception_state->__sigmask & 0xffff; - - /* Call the general exception handler */ - handle_exception(except_num); - } - /* Write back registers */ - set_regs(); - - /* Return from handler */ - longjmp(__djgpp_exception_state,__djgpp_exception_state->__eax); -} -static void end_sigsegv_handler(void){} - -/*********************************************************************** - * sigfpe_handler - * - * Description: Handles SIGFPE signal - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void sigfpe_handler(int except_num){ - - /* Save general purpose registers */ - save_regs(); - - /* Call the general purpose exception handler */ - handle_exception(except_num); - - /* Write back registers */ - set_regs(); - - /* Return from handler */ - longjmp(__djgpp_exception_state,__djgpp_exception_state->__eax); -} -static void end_sigfpe_handler(void){} - -/*********************************************************************** - * sigtrap_handler - * - * Description: Handles SIGTRAP signal - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void sigtrap_handler(int except_num) { - - /* Save general purpose registers */ - save_regs(); - - /* Call the general purpose exception handler */ - handle_exception(except_num); - - /* Write back registers */ - set_regs(); - - /* Return from handler */ - longjmp(__djgpp_exception_state,__djgpp_exception_state->__eax); -} -static void end_sigtrap_handler(int except_num){} - -/*********************************************************************** - * sigill_handler - * - * Description: Handles SIGILL signal - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void sigill_handler(int except_num) { - - /* Save general purpose registers */ - save_regs(); - - /* Call the general purpose exception handler */ - handle_exception(except_num); - - /* Write back registers */ - set_regs(); - - /* Return from handler */ - longjmp(__djgpp_exception_state,__djgpp_exception_state->__eax); -} -static void end_sigill_handler(int except_num){} -#endif - -#ifdef _WIN32 //MF - -void win32_exception_handler(EXCEPTION_POINTERS* exc_info) -{ - PCONTEXT ctx = exc_info->ContextRecord; - - registers[EAX] = ctx->Eax; - registers[ECX] = ctx->Ecx; - registers[EDX] = ctx->Edx; - registers[EBX] = ctx->Ebx; - registers[ESP] = ctx->Esp; - registers[EBP] = ctx->Ebp; - registers[ESI] = ctx->Esi; - registers[EDI] = ctx->Edi; - registers[PC] = ctx->Eip; - registers[PS] = ctx->EFlags; - registers[CS] = ctx->SegCs; - registers[SS] = ctx->SegSs; - registers[DS] = ctx->SegDs; - registers[ES] = ctx->SegEs; - registers[FS] = ctx->SegFs; - registers[GS] = ctx->SegGs; - - handle_exception((int)(exc_info->ExceptionRecord->ExceptionCode & 0xFFFF)); - - ctx->Eax = registers[EAX]; - ctx->Ecx = registers[ECX]; - ctx->Edx = registers[EDX]; - ctx->Ebx = registers[EBX]; - ctx->Esp = registers[ESP]; - ctx->Ebp = registers[EBP]; - ctx->Esi = registers[ESI]; - ctx->Edi = registers[EDI]; - ctx->Eip = registers[PC]; - ctx->EFlags = registers[PS]; - ctx->SegCs = registers[CS]; - ctx->SegSs = registers[SS]; - ctx->SegDs = registers[DS]; - ctx->SegEs = registers[ES]; - ctx->SegFs = registers[FS]; - ctx->SegGs = registers[GS]; -} - -#endif // _WIN32 - -/*********************************************************************** - * hex - * - * Description: Convert ASCII character values, representing hex - * digits, to the integer value. - * - * Inputs: - * ch - data character - * Outputs: None. - * Returns: integer value represented by the input character. - * - ***********************************************************************/ -static int hex (char ch) -{ - if ((ch >= 'a') && (ch <= 'f')) - return (ch - 'a' + 10); - if ((ch >= '0') && (ch <= '9')) - return (ch - '0'); - if ((ch >= 'A') && (ch <= 'F')) - return (ch - 'A' + 10); - return (-1); -} -#ifdef DJGPP -static void end_hex(void) {} -#endif - -/*********************************************************************** - * getpacket - * - * Description: Retrieve GDB data packet. - * Scan for the sequence $# - * Inputs: None. - * Outputs: None. - * Returns: Beginning of packet buffer. - * - ***********************************************************************/ -static unsigned char *getpacket (void) -{ - unsigned char *buffer = &remcomInBuffer[0]; - unsigned char checksum; - unsigned char xmitcsum; - int count; - char ch; - - while (1) - { - /* wait around for the start character, ignore all other characters */ - while ((ch = getDebugChar ()) != '$') - ; - - retry: - checksum = 0; - xmitcsum = -1; - count = 0; - - /* now, read until a # or end of buffer is found */ - while (count < BUFMAX) - { - ch = getDebugChar (); - if (ch == '$') - goto retry; - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - buffer[count] = 0; - - if (ch == '#') - { - ch = getDebugChar (); - xmitcsum = hex (ch) << 4; - ch = getDebugChar (); - xmitcsum += hex (ch); - - if (checksum != xmitcsum) - { - if (remote_debug) - { - fprintf (stderr, - "bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", - checksum, xmitcsum, buffer); - } - putDebugChar ('-'); /* failed checksum */ - } - else - { - putDebugChar ('+'); /* successful transfer */ - - /* if a sequence char is present, reply the sequence ID */ - if (buffer[2] == ':') - { - putDebugChar (buffer[0]); - putDebugChar (buffer[1]); - - return &buffer[3]; - } - - return &buffer[0]; - } - } - } -} -#ifdef DJGPP -static void end_getpacket(void) {} -#endif - -/*********************************************************************** - * putpacket - * - * Description: Send GDB data packet. - * - * Inputs: Buffer of data to send. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void putpacket (unsigned char *buffer) -{ - unsigned char checksum; - int count; - char ch; - - /* $#. */ - do - { - putDebugChar ('$'); - checksum = 0; - count = 0; - - while ((ch = buffer[count])) - { - putDebugChar (ch); - checksum += ch; - count += 1; - } - - putDebugChar ('#'); - putDebugChar (hexchars[checksum >> 4]); - putDebugChar (hexchars[checksum % 16]); - - } - while (getDebugChar () != '+'); -} -#ifdef DJGPP -static void end_putpacket(void) {} -#endif - - -/*********************************************************************** - * debug_error - * - * Description: Log errors - * - * Inputs: - * format - Format string. - * parm - parameter string - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void debug_error (const char *format, char *parm) -{ - if (remote_debug) - fprintf (stderr, format, parm); -} -#ifdef DJGPP -static void end_debug_error(void) {} -#endif - -/* - * Indicate to caller of mem2hex or hex2mem that there has been an error. - */ -#ifndef DJGPP -static volatile int mem_err = 0; -#else -static int mem_err = 0; -#endif - -/*********************************************************************** - * set_mem_err - * - * Description: set memory error flag - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void set_mem_err (void) -{ - mem_err = 1; -} -#ifdef DJGPP -static void end_set_mem_err(void) {} -#endif - -/*********************************************************************** - * get_char - * - * Description: Retreive a character from the specified address. - * These are separate functions so that they are so - * short and sweet that the compiler won't save any - * registers (if there is a fault to mem_fault, they - * won't get restored, so there better not be any saved). - * - * Inputs: addr - The address to read from. - * Outputs: None. - * Returns: data read from address. - * - ***********************************************************************/ -static int get_char (char *addr) -{ - return *addr; -} -#ifdef DJGPP -static void end_get_char(void) {} -#endif - -/*********************************************************************** - * set_char - * - * Description: Write a value to the specified address. - * These are separate functions so that they are so - * short and sweet that the compiler won't save any - * registers (if there is a fault to mem_fault, they - * won't get restored, so there better not be any saved). - * - * Inputs: - * addr - The address to read from. - * val - value to write. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void set_char (char *addr, int val) -{ - *addr = val; -} -#ifdef DJGPP -static void end_set_char(void) {} -#endif - - -/*********************************************************************** - * mem2hex - * - * Description: Convert the memory pointed to by mem into hex, placing - * result in buf. Return a pointer to the last char put - * in buf (null). If MAY_FAULT is non-zero, then we should - * set mem_err in response to a fault; if zero treat a - * fault like any other fault in the stub. - * - * Inputs: - * mem - Memory address - * buf - data buffer - * count - number of bytes - * may_fault - flag indicating that the operation may cause a mem fault. - * Outputs: None. - * Returns: Pointer to last character. - * - ***********************************************************************/ -static char *mem2hex (char *mem,char *buf,int count,int may_fault) -{ - int i; - unsigned char ch; - -#ifdef _WIN32 //MF - if (IsBadReadPtr(mem, (DWORD)count)) - return mem; -#else - if (may_fault) - mem_fault_routine = set_mem_err; -#endif - for (i = 0; i < count; i++) - { - ch = get_char (mem++); - if (may_fault && mem_err) - return (buf); - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch % 16]; - } - *buf = 0; -#ifndef _WIN32 //MF - if (may_fault) - mem_fault_routine = NULL; -#endif - return (buf); -} -#ifdef DJGPP -static void end_mem2hex(void) {} -#endif - -/*********************************************************************** - * hex2mem - * - * Description: Convert the hex array pointed to by buf into binary to - * be placed in mem. Return a pointer to the character - * AFTER the last byte written - * Inputs: - * buf - * mem - * count - * may_fault - * Outputs: None. - * Returns: Pointer to buffer after last byte. - * - ***********************************************************************/ -static char *hex2mem (char *buf,char *mem,int count,int may_fault) -{ - int i; - unsigned char ch; - -#ifdef _WIN32 //MF - // MinGW does not support structured exception handling, so let's - // go safe and make memory writable by default - DWORD old_protect; - - VirtualProtect(mem, (DWORD)count, PAGE_EXECUTE_READWRITE, &old_protect); -#else - if (may_fault) - mem_fault_routine = set_mem_err; -#endif - for (i = 0; i < count; i++) - { - ch = hex (*buf++) << 4; - ch = ch + hex (*buf++); - set_char (mem++, ch); - if (may_fault && mem_err) - return (mem); - } -#ifndef _WIN32 //MF - if (may_fault) - mem_fault_routine = NULL; -#endif - return (mem); -} -#ifdef DJGPP -static void end_hex2mem(void) {} -#endif - -/*********************************************************************** - * computeSignal - * - * Description: This function takes the 386 exception vector and - * attempts to translate this number into a unix - * compatible signal value. - * Inputs: - * exceptionVector - * Outputs: None. - * Returns: - * - ***********************************************************************/ -static int computeSignal (int exceptionVector) -{ - int sigval; - switch (exceptionVector) - { - case 0: - sigval = 8; - break; /* divide by zero */ - case 1: - sigval = 5; - break; /* debug exception */ - case 3: - sigval = 5; - break; /* breakpoint */ - case 4: - sigval = 16; - break; /* into instruction (overflow) */ - case 5: - sigval = 16; - break; /* bound instruction */ - case 6: - sigval = 4; - break; /* Invalid opcode */ - case 7: - sigval = 8; - break; /* coprocessor not available */ - case 8: - sigval = 7; - break; /* double fault */ - case 9: - sigval = 11; - break; /* coprocessor segment overrun */ - case 10: - sigval = 11; - break; /* Invalid TSS */ - case 11: - sigval = 11; - break; /* Segment not present */ - case 12: - sigval = 11; - break; /* stack exception */ - case 13: - sigval = 11; - break; /* general protection */ - case 14: - sigval = 11; - break; /* page fault */ - case 16: - sigval = 7; - break; /* coprocessor error */ - default: - sigval = 7; /* "software generated" */ - } - return (sigval); -} -#ifdef DJGPP -static void end_computeSignal(void) {} -#endif - -/*********************************************************************** - * hexToInt - * - * Description: Convert an ASCII string to an integer. - * - * Inputs: - * Outputs: None. - * Returns: Number of chars processed - * - ***********************************************************************/ -int hexToInt (char **ptr, int *intValue) -{ - int numChars = 0; - int hexValue; - - *intValue = 0; - - while (**ptr) - { - hexValue = hex (**ptr); - if (hexValue >= 0) - { - *intValue = (*intValue << 4) | hexValue; - numChars++; - } - else - break; - - (*ptr)++; - } - - return (numChars); -} -#ifdef DJGPP -static void end_hexToInt(void) {} -#endif - - -/*********************************************************************** - * handle_exception - * - * Description: This function does all command procesing for interfacing - * to GDB. - * Inputs: - * exceptionVector - number of the vector. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void handle_exception (int exceptionVector) -{ - int sigval, stepping; - int addr, length; - char *ptr; - int newPC; - -#ifndef _WIN32 //MF - gdb_i386vector = exceptionVector; -#endif - - if (remote_debug) - { - printf ("vector=%d, sr=0x%x, pc=0x%x\n", - exceptionVector, registers[PS], registers[PC]); - } - - /* reply to host that an exception has occurred */ - sigval = computeSignal (exceptionVector); - - ptr = remcomOutBuffer; - - *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ - *ptr++ = hexchars[sigval >> 4]; - *ptr++ = hexchars[sigval & 0xf]; - - *ptr++ = hexchars[ESP]; - *ptr++ = ':'; - ptr = mem2hex((char *)®isters[ESP], ptr, 4, 0); /* SP */ - *ptr++ = ';'; - - *ptr++ = hexchars[EBP]; - *ptr++ = ':'; - ptr = mem2hex((char *)®isters[EBP], ptr, 4, 0); /* FP */ - *ptr++ = ';'; - - *ptr++ = hexchars[PC]; - *ptr++ = ':'; - ptr = mem2hex((char *)®isters[PC], ptr, 4, 0); /* PC */ - *ptr++ = ';'; - - *ptr = '\0'; - - putpacket (remcomOutBuffer); - - stepping = 0; - - while (1 == 1) - { - remcomOutBuffer[0] = 0; - ptr = getpacket (); - - switch (*ptr++) - { - case '?': - remcomOutBuffer[0] = 'S'; - remcomOutBuffer[1] = hexchars[sigval >> 4]; - remcomOutBuffer[2] = hexchars[sigval % 16]; - remcomOutBuffer[3] = 0; - break; - case 'd': - remote_debug = !(remote_debug); /* toggle debug flag */ - break; - case 'g': /* return the value of the CPU registers */ - mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0); - break; - case 'G': /* set the value of the CPU registers - return OK */ - hex2mem (ptr, (char *) registers, NUMREGBYTES, 0); - strcpy (remcomOutBuffer, "OK"); - break; - case 'P': /* set the value of a single CPU register - return OK */ - { - int regno; - - if (hexToInt (&ptr, ®no) && *ptr++ == '=') - if (regno >= 0 && regno < NUMREGS) - { - hex2mem (ptr, (char *) ®isters[regno], 4, 0); - strcpy (remcomOutBuffer, "OK"); - break; - } - - strcpy (remcomOutBuffer, "E01"); - break; - } - - /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ - case 'm': - /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ - if (hexToInt (&ptr, &addr)) - if (*(ptr++) == ',') - if (hexToInt (&ptr, &length)) - { - ptr = 0; - mem_err = 0; - mem2hex ((char *) addr, remcomOutBuffer, length, 1); - if (mem_err) - { - strcpy (remcomOutBuffer, "E03"); - debug_error ("%s","memory fault"); - } - } - - if (ptr) - { - strcpy (remcomOutBuffer, "E01"); - } - break; - - /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ - case 'M': - /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ - if (hexToInt (&ptr, &addr)) - if (*(ptr++) == ',') - if (hexToInt (&ptr, &length)) - if (*(ptr++) == ':') - { - mem_err = 0; - hex2mem (ptr, (char *) addr, length, 1); - - if (mem_err) - { - strcpy (remcomOutBuffer, "E03"); - debug_error ("%s","memory fault"); - } - else - { - strcpy (remcomOutBuffer, "OK"); - } - - ptr = 0; - } - if (ptr) - { - strcpy (remcomOutBuffer, "E02"); - } - break; - - /* cAA..AA Continue at address AA..AA(optional) */ - /* sAA..AA Step one instruction from AA..AA(optional) */ - case 's': - stepping = 1; - case 'c': - /* try to read optional parameter, pc unchanged if no parm */ - if (hexToInt (&ptr, &addr)) - registers[PC] = addr; - - newPC = registers[PC]; - - /* clear the trace bit */ - registers[PS] &= 0xfffffeff; - - /* set the trace bit if we're stepping */ - if (stepping) - registers[PS] |= 0x100; - -#ifdef _WIN32 //MF - return; -#else - _returnFromException (); /* this is a jump */ - - break; - - /* kill the program */ - case 'k': /* do nothing */ -#if 0 - /* Huh? This doesn't look like "nothing". - m68k-stub.c and sparc-stub.c don't have it. */ - BREAKPOINT (); -#endif - break; -#endif - } /* switch */ - - /* reply to the request */ - putpacket (remcomOutBuffer); - } -} -#ifdef DJGPP -static void end_handle_exception(void) {} -#endif - -#ifndef DJGPP -/* GDB stores segment registers in 32-bit words (that's just the way - m-i386v.h is written). So zero the appropriate areas in registers. */ -#define SAVE_REGISTERS1() \ - asm ("movl %eax, _registers"); \ - asm ("movl %ecx, _registers+4"); \ - asm ("movl %edx, _registers+8"); \ - asm ("movl %ebx, _registers+12"); \ - asm ("movl %ebp, _registers+20"); \ - asm ("movl %esi, _registers+24"); \ - asm ("movl %edi, _registers+28"); \ - asm ("movw $0, %ax"); \ - asm ("movw %ds, _registers+48"); \ - asm ("movw %ax, _registers+50"); \ - asm ("movw %es, _registers+52"); \ - asm ("movw %ax, _registers+54"); \ - asm ("movw %fs, _registers+56"); \ - asm ("movw %ax, _registers+58"); \ - asm ("movw %gs, _registers+60"); \ - asm ("movw %ax, _registers+62"); -#define SAVE_ERRCODE() \ - asm ("popl %ebx"); \ - asm ("movl %ebx, _gdb_i386errcode"); -#define SAVE_REGISTERS2() \ - asm ("popl %ebx"); /* old eip */ \ - asm ("movl %ebx, _registers+32"); \ - asm ("popl %ebx"); /* old cs */ \ - asm ("movl %ebx, _registers+40"); \ - asm ("movw %ax, _registers+42"); \ - asm ("popl %ebx"); /* old eflags */ \ - asm ("movl %ebx, _registers+36"); \ - /* Now that we've done the pops, we can save the stack pointer."); */ \ - asm ("movw %ss, _registers+44"); \ - asm ("movw %ax, _registers+46"); \ - asm ("movl %esp, _registers+16"); - -/* See if mem_fault_routine is set, if so just IRET to that address. */ -#define CHECK_FAULT() \ - asm ("cmpl $0, _mem_fault_routine"); \ - asm ("jne mem_fault"); - -asm (".text"); -asm ("mem_fault:"); -/* OK to clobber temp registers; we're just going to end up in set_mem_err. */ -/* Pop error code from the stack and save it. */ -asm (" popl %eax"); -asm (" movl %eax, _gdb_i386errcode"); - -asm (" popl %eax"); /* eip */ -/* We don't want to return there, we want to return to the function - pointed to by mem_fault_routine instead. */ -asm (" movl _mem_fault_routine, %eax"); -asm (" popl %ecx"); /* cs (low 16 bits; junk in hi 16 bits). */ -asm (" popl %edx"); /* eflags */ - -/* Remove this stack frame; when we do the iret, we will be going to - the start of a function, so we want the stack to look just like it - would after a "call" instruction. */ -asm (" leave"); - -/* Push the stuff that iret wants. */ -asm (" pushl %edx"); /* eflags */ -asm (" pushl %ecx"); /* cs */ -asm (" pushl %eax"); /* eip */ - -/* Zero mem_fault_routine. */ -asm (" movl $0, %eax"); -asm (" movl %eax, _mem_fault_routine"); - -asm ("iret"); - - -#define CALL_HOOK() asm("call _remcomHandler"); - -/* This function is called when a i386 exception occurs. It saves - * all the cpu regs in the _registers array, munges the stack a bit, - * and invokes an exception handler (remcom_handler). - * - * stack on entry: stack on exit: - * old eflags vector number - * old cs (zero-filled to 32 bits) - * old eip - * - */ -extern void _catchException3(); -asm(".text"); -asm(".globl __catchException3"); -asm("__catchException3:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $3"); -CALL_HOOK(); - -/* Same thing for exception 1. */ -extern void _catchException1(); -asm(".text"); -asm(".globl __catchException1"); -asm("__catchException1:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $1"); -CALL_HOOK(); - -/* Same thing for exception 0. */ -extern void _catchException0(); -asm(".text"); -asm(".globl __catchException0"); -asm("__catchException0:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $0"); -CALL_HOOK(); - -/* Same thing for exception 4. */ -extern void _catchException4(); -asm(".text"); -asm(".globl __catchException4"); -asm("__catchException4:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $4"); -CALL_HOOK(); - -/* Same thing for exception 5. */ -extern void _catchException5(); -asm(".text"); -asm(".globl __catchException5"); -asm("__catchException5:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $5"); -CALL_HOOK(); - -/* Same thing for exception 6. */ -extern void _catchException6(); -asm(".text"); -asm(".globl __catchException6"); -asm("__catchException6:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $6"); -CALL_HOOK(); - -/* Same thing for exception 7. */ -extern void _catchException7(); -asm(".text"); -asm(".globl __catchException7"); -asm("__catchException7:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $7"); -CALL_HOOK(); - -/* Same thing for exception 8. */ -extern void _catchException8(); -asm(".text"); -asm(".globl __catchException8"); -asm("__catchException8:"); -SAVE_REGISTERS1(); -SAVE_ERRCODE(); -SAVE_REGISTERS2(); -asm ("pushl $8"); -CALL_HOOK(); - -/* Same thing for exception 9. */ -extern void _catchException9(); -asm(".text"); -asm(".globl __catchException9"); -asm("__catchException9:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $9"); -CALL_HOOK(); - -/* Same thing for exception 10. */ -extern void _catchException10(); -asm(".text"); -asm(".globl __catchException10"); -asm("__catchException10:"); -SAVE_REGISTERS1(); -SAVE_ERRCODE(); -SAVE_REGISTERS2(); -asm ("pushl $10"); -CALL_HOOK(); - -/* Same thing for exception 12. */ -extern void _catchException12(); -asm(".text"); -asm(".globl __catchException12"); -asm("__catchException12:"); -SAVE_REGISTERS1(); -SAVE_ERRCODE(); -SAVE_REGISTERS2(); -asm ("pushl $12"); -CALL_HOOK(); - -/* Same thing for exception 16. */ -extern void _catchException16(); -asm(".text"); -asm(".globl __catchException16"); -asm("__catchException16:"); -SAVE_REGISTERS1(); -SAVE_REGISTERS2(); -asm ("pushl $16"); -CALL_HOOK(); - -/* For 13, 11, and 14 we have to deal with the CHECK_FAULT stuff. */ - -/* Same thing for exception 13. */ -extern void _catchException13 (); -asm (".text"); -asm (".globl __catchException13"); -asm ("__catchException13:"); -CHECK_FAULT(); -SAVE_REGISTERS1(); -SAVE_ERRCODE(); -SAVE_REGISTERS2(); -asm ("pushl $13"); -CALL_HOOK(); - -/* Same thing for exception 11. */ -extern void _catchException11 (); -asm (".text"); -asm (".globl __catchException11"); -asm ("__catchException11:"); -CHECK_FAULT(); -SAVE_REGISTERS1(); -SAVE_ERRCODE(); -SAVE_REGISTERS2(); -asm ("pushl $11"); -CALL_HOOK(); - -/* Same thing for exception 14. */ -extern void _catchException14 (); -asm (".text"); -asm (".globl __catchException14"); -asm ("__catchException14:"); -CHECK_FAULT(); -SAVE_REGISTERS1(); -SAVE_ERRCODE(); -SAVE_REGISTERS2(); -asm ("pushl $14"); -CALL_HOOK(); - -/* - * remcomHandler is a front end for handle_exception. It moves the - * stack pointer into an area reserved for debugger use. - */ -asm("_remcomHandler:"); -asm(" popl %eax"); /* pop off return address */ -asm(" popl %eax"); /* get the exception number */ -asm(" movl _stackPtr, %esp"); /* move to remcom stack area */ -asm(" pushl %eax"); /* push exception onto stack */ -asm(" call _handle_exception"); /* this never returns */ -#endif - -void _returnFromException () -{ -#ifndef DJGPP - return_to_prog (); -#else -/* Return from handler */ - longjmp(__djgpp_exception_state,__djgpp_exception_state->__eax); -#endif -} - -/* this function is used to set up exception handlers for tracing and - breakpoints */ -#ifndef DJGPP -void -set_debug_traps (void) -{ -#ifndef _WIN32 //MF - stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; - - exceptionHandler (0, _catchException0); - exceptionHandler (1, _catchException1); - exceptionHandler (3, _catchException3); - exceptionHandler (4, _catchException4); - exceptionHandler (5, _catchException5); - exceptionHandler (6, _catchException6); - exceptionHandler (7, _catchException7); - exceptionHandler (8, _catchException8); - exceptionHandler (9, _catchException9); - exceptionHandler (10, _catchException10); - exceptionHandler (11, _catchException11); - exceptionHandler (12, _catchException12); - exceptionHandler (13, _catchException13); - exceptionHandler (14, _catchException14); - exceptionHandler (16, _catchException16); -#endif // _WIN32 - - gdb_initialized = 1; -} -#endif //#ifndef DJGPP - - -// DJGPP stuff -#ifdef DJGPP -/*********************************************************************** - * restore_traps - * - * Description: This function restores all used signal handlers to - * defaults. - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -void restore_traps(void) -{ - /* Restore default signal handlers */ - signal(SIGSEGV,SIG_DFL); - signal(SIGTRAP,SIG_DFL); - signal(SIGFPE,SIG_DFL); - signal(SIGTRAP,SIG_DFL); - signal(SIGILL,SIG_DFL); - - /* Clear init flag */ - gdb_initialized = 0; -} - -/*********************************************************************** - * lock_handler_data - * - * Description: This function locks all data that is used by the signal - * handlers. - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -static void lock_handler_data(void) -{ - _go32_dpmi_lock_data(&gdb_initialized,sizeof(gdb_initialized)); - _go32_dpmi_lock_data(&remote_debug,sizeof(remote_debug)); - _go32_dpmi_lock_data(hexchars,sizeof(hexchars)); - _go32_dpmi_lock_data(registers,sizeof(registers)); - _go32_dpmi_lock_data(&gdb_i386errcode,sizeof(gdb_i386errcode)); - _go32_dpmi_lock_data(&gdb_i386vector,sizeof(gdb_i386vector)); - - _go32_dpmi_lock_data(remcomInBuffer,sizeof(remcomInBuffer)); - _go32_dpmi_lock_data(remcomOutBuffer,sizeof(remcomOutBuffer)); - - _go32_dpmi_lock_code(getpacket,(unsigned long)end_getpacket- - (unsigned long)getpacket); - _go32_dpmi_lock_code(putpacket,(unsigned long)end_putpacket- - (unsigned long)putpacket); - _go32_dpmi_lock_code(debug_error,(unsigned long)end_debug_error- - (unsigned long)debug_error); - - _go32_dpmi_lock_data(&mem_fault_routine,sizeof(mem_fault_routine)); - _go32_dpmi_lock_data(&mem_err,sizeof(mem_err)); - - _go32_dpmi_lock_code(set_mem_err,(unsigned long)end_set_mem_err-(unsigned long)set_mem_err); - _go32_dpmi_lock_code(get_char,(unsigned long)end_get_char-(unsigned long)get_char); - _go32_dpmi_lock_code(set_char,(unsigned long)end_set_char-(unsigned long)set_char); - _go32_dpmi_lock_code(mem2hex,(unsigned long)end_hex-(unsigned long)hex); - _go32_dpmi_lock_code(mem2hex,(unsigned long)end_mem2hex-(unsigned long)mem2hex); - _go32_dpmi_lock_code(hex2mem,(unsigned long)end_hex2mem-(unsigned long)hex2mem); - _go32_dpmi_lock_code(computeSignal,(unsigned long)end_computeSignal- - (unsigned long)computeSignal); - _go32_dpmi_lock_code(hexToInt,(unsigned long)end_hexToInt-(unsigned long)hexToInt); - _go32_dpmi_lock_code(handle_exception,(unsigned long)end_handle_exception- - (unsigned long)handle_exception); - - _go32_dpmi_lock_code(sigsegv_handler, - (unsigned long)end_sigsegv_handler-(unsigned long)sigsegv_handler); - - _go32_dpmi_lock_code(sigfpe_handler, - (unsigned long)end_sigfpe_handler-(unsigned long)sigfpe_handler); - - _go32_dpmi_lock_code(sigtrap_handler, - (unsigned long)end_sigtrap_handler-(unsigned long)sigtrap_handler); - - _go32_dpmi_lock_code(sigill_handler, - (unsigned long)end_sigill_handler-(unsigned long)sigill_handler); - - _go32_dpmi_lock_code(save_regs, - (unsigned long)end_save_regs-(unsigned long)save_regs); - - _go32_dpmi_lock_code(set_regs, - (unsigned long)end_set_regs-(unsigned long)set_regs); - -} - -/*********************************************************************** - * set_debug_traps - * - * Description: This function installs signal handlers. - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -void set_debug_traps(void) -{ - /* Lock any data that may be used by the trap handlers */ - lock_handler_data(); - - /* Install signal handlers here */ - signal(SIGSEGV,sigsegv_handler); - signal(SIGFPE,sigfpe_handler); - signal(SIGTRAP,sigtrap_handler); - signal(SIGILL,sigill_handler); - - /* Set init flag */ - gdb_initialized = 1; - -} -#endif //#ifdef DJGPP - -/*********************************************************************** - * breakpoint - * - * Description: This function will generate a breakpoint exception. - * It is used at the beginning of a program to sync up - * with a debugger and can be used otherwise as a quick - * means to stop program execution and "break" into the - * debugger. - * - * Inputs: None. - * Outputs: None. - * Returns: None. - * - ***********************************************************************/ -void breakpoint () -{ - if (gdb_initialized) - BREAKPOINT (); -} - diff --git a/tools/gdbst03/src/library/i386-supp.c b/tools/gdbst03/src/library/i386-supp.c deleted file mode 100644 index baf465b4e..000000000 --- a/tools/gdbst03/src/library/i386-supp.c +++ /dev/null @@ -1,424 +0,0 @@ -/*********************************************************************** - * i386-supp.c - * - * Description: Support functions for the i386 GDB target stub. - * - * Credits: Created by Jonathan Brogdon - * - * Terms of use: This software is provided for use under the terms - * and conditions of the GNU General Public License. - * You should have received a copy of the GNU General - * Public License along with this program; if not, write - * to the Free Software Foundation, Inc., 59 Temple Place - * Suite 330, Boston, MA 02111-1307, USA. - * - * Global Data: None. - * Global Functions: - * gdb_serial_init - * gdb_target_init - * gdb_target_close - * putDebugChar - * getDebugChar - * - * History - * Engineer: Date: Notes: - * --------- ----- ------ - * Jonathan Brogdon 20000617 Genesis - * Gordon Schumacher 20020212 Updated for modularity - * - ***********************************************************************/ - - -#ifdef DJGPP -#include -#endif - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#define DEBUGBUFFERSIZE 1024 -HANDLE ser_port = (HANDLE)(-1); - -//#include "utility/utility.h" -#ifdef _MSC_VER -#ifndef DEBUG_SERIAL -#pragma comment(lib, "wsock32") -#endif -#endif -#endif - -#include -#include - -#ifdef DJGPP -//#include "bios_layer.h" // Include this for BIOS calls - NOT RECOMMENDED! -//#include "sva_layer.h" // Include this for SVAsync usage -#include "dzc_layer.h" // Include this for DZComm usage - - -#endif -#define SER_TIMEOUT 1000000 - -#ifdef _WIN32 -static LPTOP_LEVEL_EXCEPTION_FILTER s_prev_exc_handler = 0; - - -#define I386_EXCEPTION_CNT 17 - -LONG WINAPI exc_protection_handler(EXCEPTION_POINTERS* exc_info) -{ - int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF; - - if (exc_nr < I386_EXCEPTION_CNT) { - //LOG(FmtString(TEXT("exc_protection_handler: Exception %x"), exc_nr)); - -#if 0 - if (exc_nr==11 || exc_nr==13 || exc_nr==14) { - if (mem_fault_routine) - mem_fault_routine(); - } -#endif - - ++exc_info->ContextRecord->Eip; - } - - return EXCEPTION_CONTINUE_EXECUTION; -} - -LONG WINAPI exc_handler(EXCEPTION_POINTERS* exc_info) -{ - int exc_nr = exc_info->ExceptionRecord->ExceptionCode & 0xFFFF; - - if (exc_nr < I386_EXCEPTION_CNT) { - //LOG(FmtString("Exception %x", exc_nr)); - //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags)); - - // step over initial breakpoint - if (s_initial_breakpoint) { - s_initial_breakpoint = 0; - ++exc_info->ContextRecord->Eip; - } - - SetUnhandledExceptionFilter(exc_protection_handler); - - win32_exception_handler(exc_info); - //LOG(FmtString("EIP=%08X EFLAGS=%08X", exc_info->ContextRecord->Eip, exc_info->ContextRecord->EFlags)); - - SetUnhandledExceptionFilter(exc_handler); - - return EXCEPTION_CONTINUE_EXECUTION; - } - - return EXCEPTION_CONTINUE_SEARCH; -} - -void disable_debugging() -{ - if (s_prev_exc_handler) { - SetUnhandledExceptionFilter(s_prev_exc_handler); - s_prev_exc_handler = 0; - } -} -#endif - -#if !(defined(DJGPP) || defined(_WIN32)) -void exceptionHandler(int exc_nr, void* exc_addr) -{ - if (exc_nr>=0 && exc_nr SER_TIMEOUT) - { - if(WriteFile( ser_port, buffer, 1, &dwLength, NULL )) - return 1; - else if(timeout > SER_TIMEOUT) - return 0; - } - else timeout++; - goto retrywrite; -#endif -} - -/*********************************************************************** - * getDebugChar - * - * Description: gets a character from the debug COM port. - * - * Inputs: None. - * Outputs: None. - * Returns: character data from the serial support. - * - ***********************************************************************/ -int getDebugChar(void) -{ - register int timeout = 0; -#ifdef DJGPP - register int ret = -1; - - while ((GDBStub_SerRecvOk() == 0) && (timeout < SER_TIMEOUT)) - timeout++; - if (timeout < SER_TIMEOUT) - ret = GDBStub_SerRecv(); - - return ret; -#elif defined(_WIN32) - DWORD buffer[DEBUGBUFFERSIZE]; - COMSTAT ComStat ; - DWORD dwErrorFlags; - DWORD dwLength; - - if(ser_port == (HANDLE)-1) - return -1; - - retryread: - ClearCommError( ser_port, &dwErrorFlags, &ComStat ) ; - dwLength = min( DEBUGBUFFERSIZE, ComStat.cbInQue ) ; - - if (dwLength > 0 || timeout > SER_TIMEOUT) - { - if(ReadFile( ser_port, buffer, 1, &dwLength, NULL )) - return buffer[0]; - else if(timeout > SER_TIMEOUT) - return -1; - } - else timeout++; - goto retryread; -#endif -} - -#if 0 -static SOCKET s_rem_fd = INVALID_SOCKET; - -int init_gdb_connect() -{ -#ifdef _WIN32 - WORD wVersionRequested; - WSADATA wsa_data; -#endif - SOCKADDR_IN srv_addr; - SOCKADDR_IN rem_addr; - SOCKET srv_socket; - int rem_len; - - memset(&srv_addr,0,sizeof(srv_addr)); - s_prev_exc_handler = SetUnhandledExceptionFilter(exc_handler); - -#ifdef _WIN32 - wVersionRequested= MAKEWORD( 2, 2 ); - if (WSAStartup(wVersionRequested, &wsa_data)) { - fprintf(stderr, "WSAStartup() failed"); - return 0; - } -#endif - - srv_addr.sin_family = AF_INET; - srv_addr.sin_addr.s_addr = htonl(INADDR_ANY); - srv_addr.sin_port = htons(9999); - - srv_socket = socket(PF_INET, SOCK_STREAM, 0); - if (srv_socket == INVALID_SOCKET) { - perror("socket()"); - return 0; - } - - if (bind(srv_socket, (struct sockaddr*) &srv_addr, sizeof(srv_addr)) == -1) { - perror("bind()"); - return 0; - } - - if (listen(srv_socket, 4) == -1) { - perror("listen()"); - return 0; - } - - rem_len = sizeof(rem_addr); - - for(;;) { - s_rem_fd = accept(srv_socket, (struct sockaddr*)&rem_addr, &rem_len); - - if (s_rem_fd == INVALID_SOCKET) { - if (errno == EINTR) - continue; - - perror("accept()"); - return 0; - } - - break; - } - - return 1; -} - - -int getDebugChar() -{ - char buffer[DEBUGBUFFERSIZE]; - int r; - - if (s_rem_fd == INVALID_SOCKET) - return EOF; - - r = recv(s_rem_fd, buffer, 1, 0); - if (r == -1) { - perror("recv()"); - //LOG(TEXT("debugger connection broken")); - s_rem_fd = INVALID_SOCKET; - return EOF; - } - - if (!r) - return EOF; - - return buffer[0]; -} - -void putDebugChar(int c) -{ - if (s_rem_fd == INVALID_SOCKET) { - const char buffer[] = {c}; - - if (!send(s_rem_fd, buffer, 1, 0)) { - perror("send()"); - //LOG(TEXT("debugger connection broken")); - exit(-1); - } - } -} -#endif diff --git a/tools/gdbst03/src/library/makefile b/tools/gdbst03/src/library/makefile deleted file mode 100644 index 05e1e9030..000000000 --- a/tools/gdbst03/src/library/makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Makefile for GDB Stub for DJGPP -# -# GDB Stub for DJGPP Copyright 2000 by Jonathan Brogdon -# - -include ../../Makefile.cfg - -CFLAGS += -I../../include -I../include - -LOBJS = i386-stub.o i386-supp.o - -all: library - -library: $(LOBJS) - @$(RM) ../../lib/libgdbst.a - @$(AR) rcs ../../lib/libgdbst.a $(LOBJS) - -dep: - @$(CC) $(CFLAGS) -M *.c > depend.dep - -clean: - @$(RM) $(LOBJS) - -distclean: clean - @$(RM) ../../lib/libgdbst.a - @$(RM) depend.dep - -$(OBJS) $(LOBJS): -include depend.dep diff --git a/tools/gdbst03/src/library/sva_layer.h b/tools/gdbst03/src/library/sva_layer.h deleted file mode 100644 index 4cdd1628b..000000000 --- a/tools/gdbst03/src/library/sva_layer.h +++ /dev/null @@ -1,83 +0,0 @@ -//======================================================================================================= -// sva_layer.h - Serial command layer for SVAsync -// -//======================================================================================================= - -//======================================================================================================= -//======================================================================================================= - -#ifndef _SVA_LAYER_H -#define _SVA_LAYER_H - - -//=============================================================================== -// Include files -//=============================================================================== - -#include "svasync.h" - -//=============================================================================== -// Inline function definitions -//=============================================================================== - -// Initialize the serial library -// Should return 0 if no error occurred -__inline int GDBStub_SerInit(int port) -{ - int ret, init; - - ret = init = SVAsyncInit(port - 1); - if (ret == 0) - ret = SVAsyncFifoInit(); - if (init == 0) - atexit(SVAsyncStop); - return ret; -} - - -// Set the serial port speed (and other configurables) -// Should return 0 if the speed is set properly -__inline int GDBStub_SerSpeed(int speed) -{ - SVAsyncSet(speed, BITS_8 | NO_PARITY | STOP_1); - SVAsyncHand(DTR | RTS); - return 0; -} - - -// Check to see if there's room in the buffer to send data -// Should return 0 if it is okay to send -__inline int GDBStub_SerSendOk(void) -{ - return !SVAsyncOutStat(); -} - - -// Send a character to the serial port -// Should return 0 if the send succeeds -__inline int GDBStub_SerSend(int c) -{ - SVAsyncOut((char) c); - return 0; -} - - -// Check to see if there are characters waiting in the buffer -// Should return 0 if there's data waiting -__inline int GDBStub_SerRecvOk(void) -{ - return SVAsyncInStat(); -} - - -// Read a character from the serial port -// Should return the character read -__inline int GDBStub_SerRecv(void) -{ - return SVAsyncIn(); -} - - - - -#endif diff --git a/tools/lumpmod/Makefile b/tools/lumpmod/Makefile deleted file mode 100644 index a01f80278..000000000 --- a/tools/lumpmod/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# Makfile for SRB2 Lumpmod -# by Alam Arias et al. - -SRC=lumpmod.c lump.c -OBJ=$(SRC:.c=.o)# replaces the .c from SRC with .o -EXE=lumpmod - -.PHONY : all # .PHONY ignores files named all -all: $(EXE) # all is dependent on $(BIN) to be complete - -$(EXE): $(OBJ) # $(EXE) is dependent on all of the files in $(OBJ) to exist - $(CC) $(OBJ) $(LDFLAGS) -o $@ - -.PHONY : clean # .PHONY ignores files named clean -clean: - -$(RM) $(OBJ) $(EXE) diff --git a/tools/lumpmod/lump.c b/tools/lumpmod/lump.c deleted file mode 100644 index ed2ff2f9d..000000000 --- a/tools/lumpmod/lump.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - LumpMod v0.2.1, a command-line utility for working with lumps in wad - files. - Copyright (C) 2003 Thunder Palace Entertainment. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - lump.c: Provides functions for dealing with lumps -*/ - -#include -#include -#include -#include -#include "lump.h" - -/* Read contents of a wad file and store them in memory. - * fpoint is the file to read, opened with "rb" mode. - * A pointer to a new wadfile struct will be returned, or NULL on error. - */ -struct wadfile *read_wadfile(FILE *fpoint) { - struct wadfile *wfptr; - struct lumplist *curlump; - long diroffset, filelen; - unsigned long count; - - /* Allocate memory for wadfile struct */ - wfptr = malloc(sizeof(struct wadfile)); - if(wfptr == NULL) return NULL; - - /* Read first four characters (PWAD or IWAD) */ - if(fread(wfptr->id, 4, 1, fpoint) < 1) { - free(wfptr); - return NULL; - } - - /* Read number of lumps */ - if(fread(&(wfptr->numlumps), 4, 1, fpoint) < 1) { - free(wfptr); - return NULL; - } - - /* If number of lumps is zero, nothing more needs to be done */ - if(wfptr->numlumps == 0) { - wfptr->head = NULL; - return wfptr; - } - - /* Read offset of directory */ - if(fread(&diroffset, 4, 1, fpoint) < 1) { - free(wfptr); - return NULL; - } - - /* Verify that the directory as long as it needs to be */ - fseek(fpoint, 0, SEEK_END); - filelen = ftell(fpoint); - if((filelen - diroffset) / DIRENTRYLEN < wfptr->numlumps) { - free(wfptr); - return NULL; - } - - /* Allocate memory for head lumplist item and set head pointer */ - curlump = malloc(sizeof(struct lumplist)); - if(curlump == NULL) { - free(wfptr); - return NULL; - } - wfptr->head = curlump; - curlump->cl = NULL; - - /* Read directory entries and lumps */ - for(count = 0; count < wfptr->numlumps; count++) { - long lumpdataoffset; - - /* Advance to a new list item */ - curlump->next = malloc(sizeof(struct lumplist)); - if(curlump->next == NULL) { - free_wadfile(wfptr); - return NULL; - } - curlump = curlump->next; - curlump->next = NULL; - - /* Allocate memory for the lump info */ - curlump->cl = malloc(sizeof(struct lump)); - if(curlump->cl == NULL) { - free_wadfile(wfptr); - return NULL; - } - - /* Seek to the proper position in the file */ - if(fseek(fpoint, diroffset + (count * DIRENTRYLEN), SEEK_SET) != 0) { - free_wadfile(wfptr); - return NULL; - } - - /* Read offset of lump data */ - if(fread(&lumpdataoffset, 4, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - - /* Read size of lump in bytes */ - if(fread(&(curlump->cl->len), 4, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - - /* Read lump name */ - if(fread(curlump->cl->name, 8, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - - /* Read actual lump data, unless lump size is 0 */ - if(curlump->cl->len > 0) { - if(fseek(fpoint, lumpdataoffset, SEEK_SET) != 0) { - free_wadfile(wfptr); - return NULL; - } - - /* Allocate memory for data */ - curlump->cl->data = malloc(curlump->cl->len); - if(curlump->cl->data == NULL) { - free_wadfile(wfptr); - return NULL; - } - - /* Fill the data buffer */ - if(fread(curlump->cl->data, curlump->cl->len, 1, fpoint) < 1) { - free_wadfile(wfptr); - return NULL; - } - } else curlump->cl->data = NULL; - } /* End of directory reading loop */ - - return wfptr; -} - -/* Free a wadfile from memory as well as all related structures. - */ -void free_wadfile(struct wadfile *wfptr) { - struct lumplist *curlump, *nextlump; - - if(wfptr == NULL) return; - curlump = wfptr->head; - - /* Free items in the lump list */ - while(curlump != NULL) { - - /* Free the actual lump and its data, if necessary */ - if(curlump->cl != NULL) { - if(curlump->cl->data != NULL) free(curlump->cl->data); - free(curlump->cl); - } - - /* Advance to next lump and free this one */ - nextlump = curlump->next; - free(curlump); - curlump = nextlump; - } - - free(wfptr); -} - -/* Write complete wadfile to a file stream, opened with "wb" mode. - * fpoint is the stream to write to. - * wfptr is a pointer to the wadfile structure to use. - * Return zero on success, nonzero on failure. - */ -int write_wadfile(FILE *fpoint, struct wadfile *wfptr) { - struct lumplist *curlump; - long lumpdataoffset, diroffset; - - if(wfptr == NULL) return 1; - - /* Write four-character ID ("PWAD" or "IWAD") */ - if(fwrite(wfptr->id, 4, 1, fpoint) < 1) return 2; - - /* Write number of lumps */ - if(fwrite(&(wfptr->numlumps), 4, 1, fpoint) < 1) return 3; - - /* Offset of directory is not known yet. For now, write number of lumps - * again, just to fill the space. - */ - if(fwrite(&(wfptr->numlumps), 4, 1, fpoint) < 1) return 4; - - /* Loop through lump list, writing lump data */ - for(curlump = wfptr->head; curlump != NULL; curlump = curlump->next) { - - /* Don't write anything for the head of the lump list or for lumps of - zero length */ - if(curlump->cl == NULL || curlump->cl->data == NULL) continue; - - /* Write the data */ - if(fwrite(curlump->cl->data, curlump->cl->len, 1, fpoint) < 1) - return 5; - } - - /* Current position is where directory will start */ - diroffset = ftell(fpoint); - - /* Offset for the first lump's data is always 12 */ - lumpdataoffset = 12; - - /* Loop through lump list again, this time writing directory entries */ - for(curlump = wfptr->head; curlump != NULL; curlump = curlump->next) { - - /* Don't write anything for the head of the lump list */ - if(curlump->cl == NULL) continue; - - /* Write offset for lump data */ - if(fwrite(&lumpdataoffset, 4, 1, fpoint) < 1) return 6; - - /* Write size of lump data */ - if(fwrite(&(curlump->cl->len), 4, 1, fpoint) < 1) return 7; - - /* Write lump name */ - if(fwrite(curlump->cl->name, 8, 1, fpoint) < 1) return 8; - - /* Increment lumpdataoffset variable as appropriate */ - lumpdataoffset += curlump->cl->len; - } - - /* Go back to header and write the proper directory offset */ - fseek(fpoint, 8, SEEK_SET); - if(fwrite(&diroffset, 4, 1, fpoint) < 1) return 9; - - return 0; -} - -/* Get the name of a lump, as a null-terminated string. - * item is a pointer to the lump (not lumplist) whose name will be obtained. - * Return NULL on error. - */ -char *get_lump_name(struct lump *item) { - char convname[9], *retname; - - if(item == NULL) return NULL; - memcpy(convname, item->name, 8); - convname[8] = '\0'; - - retname = malloc(strlen(convname) + 1); - if(retname != NULL) strcpy(retname, convname); - return retname; -} - -/* Find the lump after start and before end having a certain name. - * Return a pointer to the list item for that lump, or return NULL if no lump - * by that name is found or lumpname is too long. - * lumpname is a null-terminated string. - * If end parameter is NULL, search to the end of the entire list. - */ -struct lumplist *find_previous_lump(struct lumplist *start, struct lumplist - *end, char *lumpname) { - struct lumplist *curlump, *lastlump; - char *curname; - int found = 0; - - /* Verify that parameters are valid */ - if(start==NULL || start==end || lumpname==NULL || strlen(lumpname) > 8) - return NULL; - - /* Loop through the list from start parameter */ - lastlump = start; - for(curlump = start->next; curlump != end && curlump != NULL; - curlump = curlump->next) { - - /* Skip header lump */ - if(curlump->cl == NULL) continue; - - /* Find name of this lump */ - curname = get_lump_name(curlump->cl); - if(curname == NULL) continue; - - /* Compare names to see if this is the lump we want */ - if(strcmp(curname, lumpname) == 0) { - found = 1; - break; - } - - /* Free memory allocated to curname */ - free(curname); - - lastlump = curlump; - } - - if(found) return lastlump; - return NULL; -} - -/* Remove a lump from the list, free it, and free its data. - * before is the lump immediately preceding the lump to be removed. - * wfptr is a pointer to the wadfile structure to which the removed lump - * belongs, so that numlumps can be decreased. - */ -void remove_next_lump(struct wadfile *wfptr, struct lumplist *before) { - struct lumplist *removed; - - /* Verify that parameters are valid */ - if(before == NULL || before->next == NULL || wfptr == NULL) return; - - /* Update linked list to omit removed lump */ - removed = before->next; - before->next = removed->next; - - /* Free lump info and data if necessary */ - if(removed->cl != NULL) { - if(removed->cl->data != NULL) free(removed->cl->data); - free(removed->cl); - } - - free(removed); - - /* Decrement numlumps */ - wfptr->numlumps--; -} - -/* Add a lump. - * The lump will follow prev in the list and be named name, with a data size - * of len. - * A copy will be made of the data. - * Return zero on success or nonzero on failure. - */ -int add_lump(struct wadfile *wfptr, struct lumplist *prev, char *name, long - len, unsigned char *data) { - struct lump *newlump; - struct lumplist *newlumplist; - unsigned char *copydata; - - /* Verify that parameters are valid */ - if(wfptr == NULL || prev == NULL || name == NULL || strlen(name) > 8) - return 1; - - /* Allocate space for newlump and newlumplist */ - newlump = malloc(sizeof(struct lump)); - newlumplist = malloc(sizeof(struct lumplist)); - if(newlump == NULL || newlumplist == NULL) return 2; - - /* Copy lump data and set up newlump */ - if(len == 0 || data == NULL) { - newlump->len = 0; - newlump->data = NULL; - } else { - newlump->len = len; - copydata = malloc(len); - if(copydata == NULL) return 3; - memcpy(copydata, data, len); - newlump->data = copydata; - } - - /* Set name of newlump */ - memset(newlump->name, '\0', 8); - if(strlen(name) == 8) memcpy(newlump->name, name, 8); - else strcpy(newlump->name, name); - - /* Set up newlumplist and alter prev appropriately */ - newlumplist->cl = newlump; - newlumplist->next = prev->next; - prev->next = newlumplist; - - /* Increment numlumps */ - wfptr->numlumps++; - - return 0; -} - -/* Rename a lump. - * renamed is a pointer to the lump (not lumplist) that needs renaming. - * newname is a null-terminated string with the new name. - * Return zero on success or nonzero on failure. - */ -int rename_lump(struct lump *renamed, char *newname) { - - /* Verify that parameters are valid. */ - if(newname == NULL || renamed == NULL || strlen(newname) > 8) return 1; - - /* Do the renaming. */ - memset(renamed->name, '\0', 8); - if(strlen(newname) == 8) memcpy(renamed->name, newname, 8); - else strcpy(renamed->name, newname); - - return 0; -} - -/* Find the last lump in a wadfile structure. - * Return this lump or NULL on failure. - */ -struct lumplist *find_last_lump(struct wadfile *wfptr) { - struct lumplist *curlump; - - if(wfptr == NULL || wfptr->head == NULL) return NULL; - curlump = wfptr->head; - - while(curlump->next != NULL) curlump = curlump->next; - return curlump; -} - -/* Find the last lump between start and end. - * Return this lump or NULL on failure. - */ -struct lumplist *find_last_lump_between(struct lumplist *start, struct - lumplist *end) { - struct lumplist *curlump; - - if(start == NULL) return NULL; - curlump = start; - - while(curlump->next != end) { - curlump = curlump->next; - if(curlump == NULL) break; - } - - return curlump; -} - -/* Find the next section lump. A section lump is MAPxx (0 <= x <= 9), ExMy - * (0 <= x <= 9, 0 <= y <= 9), or any lump whose name ends in _START or _END. - * Return NULL if there are no section lumps after start. - */ -struct lumplist *find_next_section_lump(struct lumplist *start) { - struct lumplist *curlump, *found = NULL; - char *curname; - - /* Verify that parameter is valid */ - if(start == NULL || start->next == NULL) return NULL; - - /* Loop through the list from start parameter */ - for(curlump = start->next; curlump != NULL && found == NULL; - curlump = curlump->next) { - - /* Skip header lump */ - if(curlump->cl == NULL) continue; - - /* Find name of this lump */ - curname = get_lump_name(curlump->cl); - if(curname == NULL) continue; - - /* Check to see if this is a section lump */ - if(strlen(curname) == 5 && strncmp("MAP", curname, 3) == 0 && - isdigit(curname[3]) && isdigit(curname[4])) - found = curlump; - else if(strlen(curname) == 4 && curname[0] == 'E' && curname[2] == - 'M' && isdigit(curname[1]) && isdigit(curname[3])) - found = curlump; - else if(strlen(curname) == 7 && strcmp("_START", &curname[1]) == 0) - found = curlump; - else if(strlen(curname) == 8 && strcmp("_START", &curname[2]) == 0) - found = curlump; - else if(strlen(curname) == 5 && strcmp("_END", &curname[1]) == 0) - found = curlump; - else if(strlen(curname) == 6 && strcmp("_END", &curname[2]) == 0) - found = curlump; - - /* Free memory allocated to curname */ - free(curname); - } - - return found; -} diff --git a/tools/lumpmod/lump.h b/tools/lumpmod/lump.h deleted file mode 100644 index 88e478716..000000000 --- a/tools/lumpmod/lump.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - LumpMod v0.2.1, a command-line utility for working with lumps in wad - files. - Copyright (C) 2003 Thunder Palace Entertainment. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - lump.h: Defines constants, structures, and functions used in lump.c -*/ - -#ifndef __LUMP_H -#define __LUMP_H - -/* Entries in the wadfile directory are 16 bytes */ -#define DIRENTRYLEN 16 - -/* Lumps and associated info */ -struct lump { - long len; - unsigned char *data; - char name[8]; -}; - -/* Linked list of lumps */ -struct lumplist { - struct lump *cl; /* actual content of the lump */ - struct lumplist *next; -}; - -/* Structure to contain all wadfile data */ -struct wadfile { - char id[4]; /* IWAD or PWAD */ - long numlumps; /* 32-bit integer */ - struct lumplist *head; /* points to first entry */ -}; - -/* Function declarations */ -struct wadfile *read_wadfile(FILE *); -void free_wadfile(struct wadfile *); -int write_wadfile(FILE *, struct wadfile *); -char *get_lump_name(struct lump *); -struct lumplist *find_previous_lump(struct lumplist *, struct lumplist *, char *); -void remove_next_lump(struct wadfile *, struct lumplist *); -int add_lump(struct wadfile *, struct lumplist *, char *, long, unsigned char *); -int rename_lump(struct lump *, char *); -struct lumplist *find_last_lump(struct wadfile *); -struct lumplist *find_last_lump_between(struct lumplist *, struct lumplist *); -struct lumplist *find_next_section_lump(struct lumplist *); - -#endif diff --git a/tools/lumpmod/lumpmod.c b/tools/lumpmod/lumpmod.c deleted file mode 100644 index e9042615e..000000000 --- a/tools/lumpmod/lumpmod.c +++ /dev/null @@ -1,785 +0,0 @@ -/* - LumpMod v0.2.1, a command-line utility for working with lumps in wad - files. - Copyright (C) 2003 Thunder Palace Entertainment. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - lumpmod.c: Provides program functionality; depends on lump.c and lump.h -*/ - -#include -#include -#include -#include "lump.h" - -int main(int argc, char *argv[]) { - enum commands { C_ADD, C_ADDSECT, C_DELETE, C_DELSECT, C_EXTRACT, C_LIST, - C_RENAME, C_UPDATE } cmd; - struct wadfile *wfptr; - struct lumplist *startitem, *enditem = NULL; - FILE *fpoint; - char *progname, **params; - char *startname = NULL, *endname = NULL; - int numargs, numparams, insection = 0; - - progname = argv[0]; - numargs = argc - 1; - - /* Verify that there are enough arguments */ - if(numargs < 2) { - fprintf(stderr, "%s: not enough arguments\n", progname); - return EXIT_FAILURE; - } - - /* Identify the command used */ - if(strcmp(argv[2], "add" ) == 0) cmd = C_ADD; - else if(strcmp(argv[2], "addsect") == 0) cmd = C_ADDSECT; - else if(strcmp(argv[2], "delete" ) == 0) cmd = C_DELETE; - else if(strcmp(argv[2], "delsect") == 0) cmd = C_DELSECT; - else if(strcmp(argv[2], "extract") == 0) cmd = C_EXTRACT; - else if(strcmp(argv[2], "list" ) == 0) cmd = C_LIST; - else if(strcmp(argv[2], "rename" ) == 0) cmd = C_RENAME; - else if(strcmp(argv[2], "update" ) == 0) cmd = C_UPDATE; - else { - fprintf(stderr, "%s: invalid command %s\n", progname, argv[2]); - return EXIT_FAILURE; - } - - /* Check for -s option */ - if(numargs >= 4 && strcmp(argv[3], "-s") == 0) { - if(cmd == C_ADDSECT || cmd == C_DELSECT) { - fprintf(stderr, "%s: no option -s for command %s\n", progname, argv[2]); - return EXIT_FAILURE; - } - insection = 1; - params = &argv[5]; - numparams = numargs - 4; - - /* Assume a map name if length > 2 */ - if(strlen(argv[4]) > 2) startname = argv[4]; - else { - startname = malloc(strlen(argv[4]) + 7); - endname = malloc(strlen(argv[4]) + 5); - if(startname == NULL || endname == NULL) { - fprintf(stderr, "%s: out of memory\n", progname); - return EXIT_FAILURE; - } - sprintf(startname, "%s_START", argv[4]); - sprintf(endname, "%s_END", argv[4]); - } - } else { - params = &argv[3]; - numparams = numargs - 2; - } /* end of check for -s option */ - - /* Load the wadfile into memory, since all commands require this */ - fpoint = fopen(argv[1], "rb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: unable to open file %s\n", progname, argv[1]); - return EXIT_FAILURE; - } - wfptr = read_wadfile(fpoint); - fclose(fpoint); - if(wfptr == NULL) { - fprintf(stderr, "%s: %s is not a valid wadfile\n", progname, argv[1]); - return EXIT_FAILURE; - } - - /* Find startitem and enditem, using startname and endname */ - if(startname == NULL) startitem = wfptr->head; - else { - startitem = find_previous_lump(wfptr->head, NULL, startname); - if(startitem == NULL) { - fprintf(stderr, "%s: can't find lump %s in %s", progname, - startname, argv[1]); - return EXIT_FAILURE; - } - startitem = startitem->next; - if(endname == NULL) { - if(startitem->next != NULL) { - char *itemname; - - enditem = startitem->next; - itemname = get_lump_name(enditem->cl); - while( strcmp(itemname, "THINGS" ) == 0 || - strcmp(itemname, "LINEDEFS") == 0 || - strcmp(itemname, "SIDEDEFS") == 0 || - strcmp(itemname, "VERTEXES") == 0 || - strcmp(itemname, "SEGS" ) == 0 || - strcmp(itemname, "SSECTORS") == 0 || - strcmp(itemname, "NODES" ) == 0 || - strcmp(itemname, "SECTORS" ) == 0 || - strcmp(itemname, "REJECT" ) == 0 || - strcmp(itemname, "BLOCKMAP") == 0) { - enditem = enditem->next; - if(enditem == NULL) break; - free(itemname); - itemname = get_lump_name(enditem->cl); - } - free(itemname); - if(enditem != NULL) enditem = enditem->next; - } else enditem = NULL; - } else { - enditem = find_previous_lump(startitem, NULL, endname); - if(enditem == NULL) { - fprintf(stderr, "%s: can't find lump %s in %s", progname, - endname, argv[1]); - return EXIT_FAILURE; - } - enditem = enditem->next; - } - } /* end of finding startitem and enditem */ - - /* Do stuff specific to each command */ - switch(cmd) { - case C_ADD: { - struct lumplist *startitem2, *before, *existing; - int overwrite = 1, firstentry = 0, canduplicate = 0; - char *startname2 = NULL; - - /* Parse options: -a, -b, -d, -n */ - while(numparams > 2) { - if(params[0][0] != '-') break; - if(strcmp(params[0], "-n") == 0) overwrite = 0; - else if(strcmp(params[0], "-d") == 0) canduplicate = 1; - else if(strcmp(params[0], "-b") == 0) firstentry = 1; - else if(strcmp(params[0], "-a") == 0) { - params = ¶ms[1]; - numparams--; - startname2 = params[0]; - } else { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - params = ¶ms[1]; - numparams--; - } - - if(numparams < 2) { - fprintf(stderr, "%s: not enough parameters for %s", progname, - argv[2]); - return EXIT_FAILURE; - } - - /* Find the lump after which to add */ - if(firstentry) before = startitem; - else if(startname2 != NULL) { - before = find_previous_lump(startitem, enditem, startname2); - if(before == NULL) { - fprintf(stderr, "%s: can't find lump %s in %s", progname, - startname2, argv[1]); - return EXIT_FAILURE; - } - before = before->next; - } else { - if(insection) { - before = find_last_lump_between(startitem, enditem); - if(before == NULL) before = startitem; - } else before = find_last_lump(wfptr); - } - startitem2 = before; - - /* Add LUMPNAME FILENAME pairs */ - printf("Adding lumps in %s...\n", argv[1]); - for(;;) { - long newlumpsize; - unsigned char *newlumpdata; - - /* Check whether the lump already exists, unless -d is used */ - if(canduplicate) existing = NULL; - else existing = find_previous_lump(startitem, enditem, params[0]); - if(existing != NULL) existing = existing->next; - if(existing != NULL && overwrite == 0) { - printf("Lump %s already exists. Taking no action.\n", params[0]); - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - continue; - } - - /* Read the file with new lump data */ - fpoint = fopen(params[1], "rb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: can't open file %s\n", progname, - params[1]); - return EXIT_FAILURE; - } - - /* Find size of lump data */ - fseek(fpoint, 0, SEEK_END); - newlumpsize = ftell(fpoint); - fseek(fpoint, 0, SEEK_SET); - - /* Copy lump data to memory */ - if(newlumpsize == 0) newlumpdata = NULL; - else { - newlumpdata = malloc(newlumpsize); - if(newlumpdata == NULL) { - fprintf(stderr, "%s: out of memory\n", progname); - return EXIT_FAILURE; - } - if(fread(newlumpdata, newlumpsize, 1, fpoint) < 1) { - fprintf(stderr, "%s: unable to read file %s\n", - progname, params[1]); - return EXIT_FAILURE; - } - } - - /* Close the file */ - fclose(fpoint); - - /* Add or update lump */ - if(existing == NULL) { - if(add_lump(wfptr, before, params[0], newlumpsize, - newlumpdata) != 0) { - fprintf(stderr, "%s: unable to add lump %s\n", - progname, params[0]); - return EXIT_FAILURE; - } - printf("Lump %s added.\n", params[0]); - - /* Other lumps will be added after the new one */ - before = before->next; - } else { - existing->cl->len = newlumpsize; - free(existing->cl->data); - existing->cl->data = malloc(newlumpsize); - if(existing->cl->data == NULL) { - fprintf(stderr, "%s: out of memory\n", progname); - return EXIT_FAILURE; - } - memcpy(existing->cl->data, newlumpdata, newlumpsize); - printf("Lump %s updated.\n", params[0]); - } - - /* Advance to the next pair, if there is a next pair */ - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - } /* end of adding LUMPNAME FILENAME pairs */ - - /* Save the modified wadfile */ - fpoint = fopen(argv[1], "wb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: unable to open file %s for writing\n", - progname, argv[1]); - return EXIT_FAILURE; - } - if(write_wadfile(fpoint, wfptr) != 0) { - fprintf(stderr, "%s: unable to write wadfile to disk\n", - progname); - return EXIT_FAILURE; - } - fclose(fpoint); - printf("File %s successfully updated.\n", argv[1]); - } /* end of C_ADD */ - break; - - case C_UPDATE: { - struct lumplist *existing; - - /* Parse options (none) */ - if(numparams > 2 && params[0][0] == '-') { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - - if(numparams < 2) { - fprintf(stderr, "%s: not enough parameters for %s", progname, - argv[2]); - return EXIT_FAILURE; - } - - /* Update LUMPNAME FILENAME pairs */ - printf("Updating lumps in %s...\n", argv[1]); - for(;;) { - long newlumpsize; - unsigned char *newlumpdata; - - /* Check whether the lump already exists */ - existing = find_previous_lump(startitem, enditem, params[0]); - if(existing == NULL) { - printf("Lump %s does not exist. Taking no action.\n", - params[0]); - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - continue; - } - existing = existing->next; - - /* Read the file with new lump data */ - fpoint = fopen(params[1], "rb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: can't open file %s\n", progname, - params[1]); - return EXIT_FAILURE; - } - - /* Find size of lump data */ - fseek(fpoint, 0, SEEK_END); - newlumpsize = ftell(fpoint); - fseek(fpoint, 0, SEEK_SET); - - /* Copy lump data to memory */ - if(newlumpsize == 0) newlumpdata = NULL; - else { - newlumpdata = malloc(newlumpsize); - if(newlumpdata == NULL) { - fprintf(stderr, "%s: out of memory\n", progname); - return EXIT_FAILURE; - } - if(fread(newlumpdata, newlumpsize, 1, fpoint) < 1) { - fprintf(stderr, "%s: unable to read file %s\n", - progname, params[1]); - return EXIT_FAILURE; - } - } - - /* Close the file */ - fclose(fpoint); - - /* Update lump */ - existing->cl->len = newlumpsize; - free(existing->cl->data); - existing->cl->data = malloc(newlumpsize); - if(existing->cl->data == NULL) { - fprintf(stderr, "%s: out of memory\n", progname); - return EXIT_FAILURE; - } - memcpy(existing->cl->data, newlumpdata, newlumpsize); - printf("Lump %s updated.\n", params[0]); - - /* Advance to the next pair, if there is a next pair */ - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - } /* end of updating LUMPNAME FILENAME pairs */ - - /* Save the modified wadfile */ - fpoint = fopen(argv[1], "wb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: unable to open file %s for writing\n", - progname, argv[1]); - return EXIT_FAILURE; - } - if(write_wadfile(fpoint, wfptr) != 0) { - fprintf(stderr, "%s: unable to write wadfile to disk\n", - progname); - return EXIT_FAILURE; - } - fclose(fpoint); - printf("File %s successfully updated.\n", argv[1]); - } /* end of C_UPDATE */ - break; - - case C_DELETE: { - struct lumplist *before; - - /* Parse options (none) */ - if(numparams > 1 && params[0][0] == '-') { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - - if(numparams < 1) { - fprintf(stderr, "%s: not enough parameters for %s", progname, - argv[2]); - return EXIT_FAILURE; - } - - /* Delete LUMPNAME lumps */ - printf("Deleting lumps in %s...\n", argv[1]); - for(;;) { - - /* Find the lump to delete */ - before = find_previous_lump(startitem, enditem, params[0]); - if(before == NULL) { - printf("Lump %s does not exist. Taking no action.\n", - params[0]); - numparams--; - if(numparams < 1) break; - params = ¶ms[1]; - continue; - } - - /* Delete it */ - remove_next_lump(wfptr, before); - printf("Lump %s deleted.\n", params[0]); - - /* Advance to the next item to delete, if there is one */ - numparams--; - if(numparams < 1) break; - params = ¶ms[1]; - } /* end of deleting LUMPNAME lumps */ - - /* Save the modified wadfile */ - fpoint = fopen(argv[1], "wb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: unable to open file %s for writing\n", - progname, argv[1]); - return EXIT_FAILURE; - } - if(write_wadfile(fpoint, wfptr) != 0) { - fprintf(stderr, "%s: unable to write wadfile to disk\n", - progname); - return EXIT_FAILURE; - } - fclose(fpoint); - printf("File %s successfully updated.\n", argv[1]); - } /* end of C_DELETE */ - break; - - case C_RENAME: { - struct lumplist *renamed; - - /* Parse options (none) */ - if(numparams > 2 && params[0][0] == '-') { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - - if(numparams < 2) { - fprintf(stderr, "%s: not enough parameters for %s", progname, - argv[2]); - return EXIT_FAILURE; - } - - /* Rename OLDNAME NEWNAME pairs */ - printf("Renaming lumps in %s...\n", argv[1]); - for(;;) { - - /* Find the lump to rename */ - renamed = find_previous_lump(startitem, enditem, params[0]); - if(renamed == NULL) { - printf("Lump %s does not exist. Taking no action.\n", - params[0]); - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - continue; - } - renamed = renamed->next; - - /* Rename lump */ - memset(renamed->cl->name, '\0', 8); - if(strlen(params[1]) >= 8) memcpy(renamed->cl->name, - params[1], 8); - else strcpy(renamed->cl->name, params[1]); - - printf("Lump %s renamed to %s.\n", params[0], params[1]); - - /* Advance to the next pair, if there is a next pair */ - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - } /* end of renaming OLDNAME NEWNAME pairs */ - - /* Save the modified wadfile */ - fpoint = fopen(argv[1], "wb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: unable to open file %s for writing\n", - progname, argv[1]); - return EXIT_FAILURE; - } - if(write_wadfile(fpoint, wfptr) != 0) { - fprintf(stderr, "%s: unable to write wadfile to disk\n", - progname); - return EXIT_FAILURE; - } - fclose(fpoint); - printf("File %s successfully updated.\n", argv[1]); - } /* end of C_RENAME */ - break; - - case C_EXTRACT: { - struct lumplist *extracted; - - /* Parse options (none) */ - if(numparams > 2 && params[0][0] == '-') { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - - if(numparams < 2) { - fprintf(stderr, "%s: not enough parameters for %s", progname, - argv[2]); - return EXIT_FAILURE; - } - - /* Extract LUMPNAME FILENAME pairs */ - printf("Extracting lumps from %s...\n", argv[1]); - for(;;) { - - /* Find the lump to extract */ - extracted = find_previous_lump(startitem, enditem, params[0]); - if(extracted == NULL) { - printf("Lump %s does not exist. Taking no action.\n", - params[0]); - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - continue; - } - extracted = extracted->next; - - /* Open the file to extract to */ - fpoint = fopen(params[1], "wb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: can't open file %s for writing\n", - progname, params[1]); - return EXIT_FAILURE; - } - - /* Extract lump */ - if(fwrite(extracted->cl->data, extracted->cl->len, 1, fpoint) - < 1) { - fprintf(stderr, "%s: unable to write lump %s to disk\n", - progname, params[0]); - return EXIT_FAILURE; - } - - /* Close the file */ - fclose(fpoint); - printf("Lump %s saved as %s.\n", params[0], params[1]); - - /* Advance to the next pair, if there is a next pair */ - numparams -= 2; - if(numparams < 2) break; - params = ¶ms[2]; - } /* end of extracting LUMPNAME FILENAME pairs */ - - printf("Finished extracting lumps from file %s.\n", argv[1]); - } /* end of C_EXTRACT */ - break; - - case C_LIST: { - struct lumplist *curlump; - int verbose = 0, i = 0; - - /* Parse options: -v */ - while(numparams > 0) { - if(params[0][0] != '-') break; - if(strcmp(params[0], "-v") == 0) verbose = 1; - else { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - params = ¶ms[1]; - numparams--; - } - - /* Loop through the lump list, printing lump info */ - for(curlump = startitem->next; curlump != enditem; curlump = - curlump->next) { - i++; - if(verbose) printf("%5i %-8s %7li\n", i, - get_lump_name(curlump->cl), curlump->cl->len); - else printf("%s\n", get_lump_name(curlump->cl)); - } - } /* end of C_LIST */ - break; - - case C_DELSECT: { - - /* Parse options (none) */ - if(numparams > 1 && params[0][0] == '-') { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - - if(numparams < 1) { - fprintf(stderr, "%s: not enough parameters for %s", progname, - argv[2]); - return EXIT_FAILURE; - } - - /* Delete sections */ - printf("Deleting sections in %s...\n", argv[1]); - for(;;) { - struct lumplist *curlump; - - /* Assume a map name if length > 2 */ - if(strlen(params[0]) > 2) startname = params[0]; - else { - startname = malloc(strlen(params[0]) + 7); - endname = malloc(strlen(params[0]) + 5); - if(startname == NULL || endname == NULL) { - fprintf(stderr, "%s: out of memory\n", progname); - return EXIT_FAILURE; - } - sprintf(startname, "%s_START", params[0]); - sprintf(endname, "%s_END", params[0]); - } - - /* Find startitem and enditem, using startname and endname */ - startitem = find_previous_lump(wfptr->head, NULL, startname); - if(startitem == NULL) { - fprintf(stderr, "%s: can't find lump %s in %s", progname, - startname, argv[1]); - return EXIT_FAILURE; - } - if(endname == NULL && startitem->next != NULL) { - char *itemname; - - enditem = startitem->next; - itemname = get_lump_name(enditem->cl); - do { - enditem = enditem->next; - if(enditem == NULL) break; - free(itemname); - itemname = get_lump_name(enditem->cl); - } while(strcmp(itemname, "THINGS" ) == 0 || - strcmp(itemname, "LINEDEFS") == 0 || - strcmp(itemname, "SIDEDEFS") == 0 || - strcmp(itemname, "VERTEXES") == 0 || - strcmp(itemname, "SEGS" ) == 0 || - strcmp(itemname, "SSECTORS") == 0 || - strcmp(itemname, "NODES" ) == 0 || - strcmp(itemname, "SECTORS" ) == 0 || - strcmp(itemname, "REJECT" ) == 0 || - strcmp(itemname, "BLOCKMAP") == 0); - free(itemname); - } - else { - enditem = find_previous_lump(startitem, NULL, endname); - if(enditem == NULL) { - fprintf(stderr, "%s: can't find lump %s in %s", - progname, endname, argv[1]); - return EXIT_FAILURE; - } - enditem = enditem->next->next; - } /* end of finding startitem and enditem */ - - /* Loop through the section lumps, deleting them */ - curlump = startitem; - while(curlump->next != enditem) - remove_next_lump(wfptr, curlump); - printf("Deleted section %s.\n", params[0]); - - /* Move to next parameter, if it exists */ - numparams--; - if(numparams < 1) break; - params = ¶ms[1]; - } /* end of deleting sections */ - - /* Save the modified wadfile */ - fpoint = fopen(argv[1], "wb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: unable to open file %s for writing\n", - progname, argv[1]); - return EXIT_FAILURE; - } - if(write_wadfile(fpoint, wfptr) != 0) { - fprintf(stderr, "%s: unable to write wadfile to disk\n", - progname); - return EXIT_FAILURE; - } - fclose(fpoint); - printf("File %s successfully updated.\n", argv[1]); - } /* end of C_DELSECT */ - break; - - case C_ADDSECT: { - - /* Parse options (none) */ - if(numparams > 1 && params[0][0] == '-') { - fprintf(stderr, "%s: no option %s for command %s", - progname, params[0], argv[2]); - return EXIT_FAILURE; - } - - if(numparams < 1) { - fprintf(stderr, "%s: not enough parameters for %s", progname, - argv[2]); - return EXIT_FAILURE; - } - - /* Add sections */ - printf("Adding sections in %s...\n", argv[1]); - for(;;) { - struct lumplist *curlump; - - /* Assume a map name if length > 2 */ - if(strlen(params[0]) > 2) startname = params[0]; - else { - startname = malloc(strlen(params[0]) + 7); - endname = malloc(strlen(params[0]) + 5); - if(startname == NULL || endname == NULL) { - fprintf(stderr, "%s: out of memory\n", progname); - return EXIT_FAILURE; - } - sprintf(startname, "%s_START", params[0]); - sprintf(endname, "%s_END", params[0]); - } - - /* Add section, unless it already exists */ - if(find_previous_lump(wfptr->head, NULL, startname) == NULL) { - struct lumplist *last; - - last = find_last_lump(wfptr); - if(add_lump(wfptr, last, startname, 0, NULL) != 0) { - fprintf(stderr, "%s: unable to add lump %s\n", - progname, startname); - return EXIT_FAILURE; - } - - if(endname != NULL) { - last = last->next; - if(add_lump(wfptr, last, endname, 0, NULL) != 0) { - fprintf(stderr, "%s: unable to add lump %s\n", - progname, endname); - return EXIT_FAILURE; - } - } - - printf("Added section %s.\n", params[0]); - } else - printf("Section %s already exists. Taking no action.\n", - params[0]); - - /* Move to next parameter, if it exists */ - numparams--; - if(numparams < 1) break; - params = ¶ms[1]; - } /* end of adding sections */ - - /* Save the modified wadfile */ - fpoint = fopen(argv[1], "wb"); - if(fpoint == NULL) { - fprintf(stderr, "%s: unable to open file %s for writing\n", - progname, argv[1]); - return EXIT_FAILURE; - } - if(write_wadfile(fpoint, wfptr) != 0) { - fprintf(stderr, "%s: unable to write wadfile to disk\n", - progname); - return EXIT_FAILURE; - } - fclose(fpoint); - printf("File %s successfully updated.\n", argv[1]); - } /* end of C_ADDSECT */ - } /* end of command-specific stuff */ - - return EXIT_SUCCESS; -} diff --git a/tools/lumpmod/lumpmod.html b/tools/lumpmod/lumpmod.html deleted file mode 100644 index 082784178..000000000 --- a/tools/lumpmod/lumpmod.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - -LumpMod v0.2.1 Documentation -

LumpMod v0.2.1

-

LumpMod is a small command-line utility for working with lumps in wad -files in the format used by DOOM and DOOM 2. It can add, delete, extract, -rename, list, and update individual lumps. It can also add sections -(XX_START and XX_END, for instance) and delete entire sections.

-

Usage

-

lumpmod [wadfile] [command] [-s section] [parameters]

-

Sections are MAPxx (xx = 01-99, where that map exists in the file), ExMy -(x, y = 1-9, where that map exists in the file), and anything else will be -the section between WHATEVER_START and WHATEVER_END. Sections that do not -exist in the wad file cannot be used. The section part can be left out to -work with the whole file. Any section specified here while using the addsect -or delsect commands will cause an error.

-

Note that the []... parameters in the command listings can be repeated. -For example, you can use lumpmod clowns.wad add CLOWNS clowns.lmp to -add a CLOWNS lump, or lumpmod clowns.wad add CLOWN1 clown1.lmp CLOWN2 -clown2.lmp to add two clown-related lumps.

-

Note also that lump names and commands are case sensitive. There is an -update command, but no UPDATE command.

-

Commands

-

add [-a lumpname] [-b] [-d] [-n] [LUMPNAME FILENAME]...

-

Add a lump to the end of the wad, or after the lump specified with the -a -option. If the lump already exists, it will be overwritten (with its position -unchanged) unless the -n option is specified, in which case no action will be -taken, or the -d option is specified, in which case an additional lump with -the same name will be added. If the lump specified in the -a option does not -exist, an error will occur. The -b option will add the lump at the beginning, -overriding the -a option.

-

addsect [SECTNAME]...

-

Add a section. The name must be one or two characters long. If section -name is HX, zero-length entries HX_START and HX_END will be added to the end -of the wad file. If this section already exists, no action will be taken.

-

delete [LUMPNAME]...

-

Remove LUMPNAME from the wad.

-

delsect [SECTNAME]...

-

Delete a section and anything inside it. If the section doesn't exist, no -action will be taken.

-

extract [LUMPNAME FILENAME]...

-

Save the contents of LUMPNAME to the file named FILENAME. (Wad file will -not be changed in any way.)

-

list [-v]

-

List all lumps in the wad, in the order they appear in the directory. -With the -v option, include numbers and lump lengths.

-

rename [OLDNAME NEWNAME]...

-

Rename a lump in the wad.

-

update [LUMPNAME FILENAME]...

-

Update LUMPNAME with the contents of FILENAME. If no lump named LUMPNAME -exists in the wad, no action will be taken.

-

Changes

-

Version 0.2.1 adds the -d option to the add command.

-

Version 0.2 contains a fix to a bug involving empty sections. The initial -public release was version 0.1.

-

Bugs

-

LumpMod currently chokes on completely empty wad files (i.e., those that -contain absolutely no lumps). Let me know if you find any other bugs.

-

Author

-

Catatonic Porpoise, <graue@oceanbase.org>. -Updates can be found at http://www.thunderpalace.com/software/.

-

Thanks

-

Thanks to Matthew S. Fell for writing "The Unofficial DOOM -Specs," which were very helpful in making this program.

-

License

-

Copyright © 2003 Thunder Palace Entertainment.

-

This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version.

-

This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details.

-

You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

-