From 6b5fc921f227c506f57b2321279bd36bba81de30 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 7 Dec 2018 16:56:48 -0500 Subject: [PATCH 01/58] Remove windows installer --- ...ES ARE IN new-install ARCHIVE FOLDER !.txt | 0 windows-installer/.gitignore | 10 - windows-installer/BuildInstaller.bat | 76 ---- windows-installer/README.txt | 48 --- windows-installer/VersionFileName.txt | 1 - windows-installer/sfx/7zsd_LZMA2.sfx | Bin 100352 -> 0 bytes windows-installer/sfx/7zsd_LZMA2_x64.sfx | Bin 148992 -> 0 bytes windows-installer/sfx/config-installer.txt | 24 -- windows-installer/sfx/config-patch.txt | 24 -- windows-installer/sfx/config-uninstaller.txt | 13 - .../staging/! SRB2 INSTALL INSTRUCTIONS !.txt | 11 - .../staging/new-install/old-install-list.txt | 15 - .../staging/new-install/staging.bat | 363 ------------------ windows-installer/uninstaller/uninstall.bat | 183 --------- 14 files changed, 768 deletions(-) delete mode 100644 windows-installer/! MAKE SURE FILES ARE IN new-install ARCHIVE FOLDER !.txt delete mode 100644 windows-installer/.gitignore delete mode 100644 windows-installer/BuildInstaller.bat delete mode 100644 windows-installer/README.txt delete mode 100644 windows-installer/VersionFileName.txt delete mode 100644 windows-installer/sfx/7zsd_LZMA2.sfx delete mode 100644 windows-installer/sfx/7zsd_LZMA2_x64.sfx delete mode 100644 windows-installer/sfx/config-installer.txt delete mode 100644 windows-installer/sfx/config-patch.txt delete mode 100644 windows-installer/sfx/config-uninstaller.txt delete mode 100644 windows-installer/staging/! SRB2 INSTALL INSTRUCTIONS !.txt delete mode 100644 windows-installer/staging/new-install/old-install-list.txt delete mode 100644 windows-installer/staging/new-install/staging.bat delete mode 100644 windows-installer/uninstaller/uninstall.bat diff --git a/windows-installer/! MAKE SURE FILES ARE IN new-install ARCHIVE FOLDER !.txt b/windows-installer/! MAKE SURE FILES ARE IN new-install ARCHIVE FOLDER !.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/windows-installer/.gitignore b/windows-installer/.gitignore deleted file mode 100644 index 40ca3713..00000000 --- a/windows-installer/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -* -*.* -!staging -!sfx -!uninstaller -!! MAKE SURE FILES ARE IN new-install ARCHIVE FOLDER !.txt -!BuildInstaller.bat -!README.txt -!VersionFileName.txt -!.gitignore diff --git a/windows-installer/BuildInstaller.bat b/windows-installer/BuildInstaller.bat deleted file mode 100644 index cc6ff74b..00000000 --- a/windows-installer/BuildInstaller.bat +++ /dev/null @@ -1,76 +0,0 @@ -@echo off - -set "SCRIPTDIR=%~dp0" -set "SCRIPTDIR=%SCRIPTDIR:~0,-1%" - -IF [%SRB2VERSIONNAME%] == [] set /p SRB2VERSIONNAME=<"%SCRIPTDIR%\VersionFileName.txt" - -:: Find 7z - -set SVZIP= - -if NOT [%1] == [] ( - echo.%~1 | findstr /C:"7z" 1>nul - if NOT errorlevel 1 ( - if exist "%~1" set "SVZIP=%~1" - ) -) - -if ["%SVZIP%"] == [""] ( - if exist "%ProgramFiles(x86)%\7-Zip\7z.exe" set "SVZIP=%ProgramFiles(x86)%\7-Zip\7z.exe" - if exist "%ProgramFiles%\7-Zip\7z.exe" set "SVZIP=%ProgramFiles%\7-Zip\7z.exe" - if exist "%ProgramW6432%\7-Zip\7z.exe" set "SVZIP=%ProgramW6432%\7-Zip\7z.exe" -) - -:: Is it in PATH? - -if ["%SVZIP%"] == [""] ( - "7z.exe" --help > NUL 2> NUL - if NOT errorlevel 1 ( - set "SVZIP=7z.exe" - ) -) - -:: Create the uninstaller - -if NOT ["%SVZIP%"] == [""] ( - del /f /q "%SCRIPTDIR%\Uninstaller.7z" 2> NUL - "%SVZIP%" a -t7z "%SCRIPTDIR%\Uninstaller.7z" "%SCRIPTDIR%\uninstaller\*" -m5=LZMA2 - copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-uninstaller.txt" + "%SCRIPTDIR%\Uninstaller.7z" "%SCRIPTDIR%\staging\new-install\uninstall.exe" - del /f /q "%SCRIPTDIR%\uninstaller.7z" -) - -:: Operate on install archives - -type NUL > "%SCRIPTDIR%\staging\new-install\staging.txt" - -if exist "%SCRIPTDIR%\Installer.7z" ( - if NOT ["%SVZIP%"] == [""] ( - "%SVZIP%" a "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\staging\*" - ) - copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-installer.txt" + "%SCRIPTDIR%\Installer.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-Installer.exe" -) - -if exist "%SCRIPTDIR%\Patch.7z" ( - if NOT ["%SVZIP%"] == [""] ( - "%SVZIP%" a "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\staging\*" - ) - copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2.sfx" + "%SCRIPTDIR%\sfx\config-patch.txt" + "%SCRIPTDIR%\Patch.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-Patch.exe" -) - -if exist "%SCRIPTDIR%\Installer_x64.7z" ( - if NOT ["%SVZIP%"] == [""] ( - "%SVZIP%" a "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\staging\*" - ) - copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2_x64.sfx" + "%SCRIPTDIR%\sfx\config-installer.txt" + "%SCRIPTDIR%\Installer_x64.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-x64-Installer.exe" -) - -if exist "%SCRIPTDIR%\Patch_x64.7z" ( - if NOT ["%SVZIP%"] == [""] ( - "%SVZIP%" a "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\staging\*" - ) - copy /y /b "%SCRIPTDIR%\sfx\7zsd_LZMA2_x64.sfx" + "%SCRIPTDIR%\sfx\config-patch.txt" + "%SCRIPTDIR%\Patch_x64.7z" "%SCRIPTDIR%\SRB2-%SRB2VERSIONNAME%-x64-Patch.exe" -) - -del /f /q "%SCRIPTDIR%\staging\new-install\staging.txt" -del /f /q "%SCRIPTDIR%\staging\new-install\uninstall.exe" diff --git a/windows-installer/README.txt b/windows-installer/README.txt deleted file mode 100644 index 67995f33..00000000 --- a/windows-installer/README.txt +++ /dev/null @@ -1,48 +0,0 @@ -Windows Install Builder -for SRB2 - -This installer is much like the 7-Zip self-extracting archive, except -this allows for scripting the post-install step. - -This also allows for some light customization, including dialog messages -and program shortcuts. - -The included install scripts manage the game data location depending on the -install location -- if installed in Program Files or AppData\Local, the -game data location is set to %UserProfile%\SRB2. - -Program shortcuts are also added, as well as an uninstaller that -will remove the icons and also selectively uninstall the core game files. -The uninstaller gives you the option to preserve your game data and mods. - -How to Use ----------- - -1. Zip up the install contents in 7z format. - * ALL FILES MUST BE IN THE `new-install/` ARCHIVE SUBFOLDER, OR THE - POST-INSTALL SCRIPT WILL NOT WORK! - * Make sure you are using the LZMA2 algorithm, which is 7-Zip's default. - -2. Copy the 7z archive to this folder using the following names: - * Installer.7z - 32-bit full installer - * Patch.7z - 32-bit patch - * Installer_x64.7z - 64-bit full installer - * Patch_x64.7z - 64-bit patch - -3. Set the text in VersionFilename.txt to the version identifier for the - installer's filename. - * e.g., v2121 for v2.1.21, from "SRB2-v2121-Installer.exe" - * Also look through sfx/config-installer.txt and sfx/config-patch.txt - and update the version strings. Templating is TODO. - -4. Run BuildInstaller.bat [7z.exe install path] - * First argument is the path to 7z.exe. If this is not specified, the - script will try to look for it in C:\Program Files [(x86)] - * This script will automatically add the install scripts to each - installer. - -Credit ------- - -OlegScherbakov/7zSFX -https://github.com/OlegScherbakov/7zSFX diff --git a/windows-installer/VersionFileName.txt b/windows-installer/VersionFileName.txt deleted file mode 100644 index 559abffe..00000000 --- a/windows-installer/VersionFileName.txt +++ /dev/null @@ -1 +0,0 @@ -v2121 \ No newline at end of file diff --git a/windows-installer/sfx/7zsd_LZMA2.sfx b/windows-installer/sfx/7zsd_LZMA2.sfx deleted file mode 100644 index c4ba9c58477ac5dd141d8c02242c6547577d79b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100352 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 KUK{>@!~Zuooo>kh diff --git a/windows-installer/sfx/7zsd_LZMA2_x64.sfx b/windows-installer/sfx/7zsd_LZMA2_x64.sfx deleted file mode 100644 index 758e4c2d02d96b897d50eed125344a23a8a691d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148992 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 JGylJx|3B`_D@y NUL 2> NUL - if NOT errorlevel 1 ( - set "SVZIP=7z.exe" - ) -) - -:: FAILSAFE: Check if staging.txt exists in the directory -:: If not, exit, so we don't mess up anything by accident. - -if NOT exist "!STAGINGDIR!\staging.txt" ( - exit -) - -: CheckPermissionsInstall - -:: Write a dummy file and check for an error. If error, we need administrator rights - -:: NOTE: We should never have to deal with this because the main installer should -:: already have the rights. - -mkdir "!INSTALLDIR!\install-dummy" - -:: TODO elevate automatically -if errorlevel 1 ( - echo Finish installing SRB2 with these steps: - echo. - echo 1. Go to your SRB2 install folder - echo. - echo !INSTALLDIR! - echo. - echo 2. Copy all files from the "new-install" subfolder into the main folder - echo and DELETE staging.bat and staging.txt!!! - echo. - echo 3. Optionally, create a folder in your user profile named "SRB2". - echo This is where your game data and addons may live. - echo To create the folder, go here: - echo. - echo !USERPROFILE! - echo. - echo If anything fails, you may delete the files and try to run the installer - echo again with Administrator Rights: Right-click on the icon and click - echo "Run as administrator." - echo. - "!SystemRoot!\explorer.exe" "!INSTALLDIR!" - set /p ADMINFINAL="Press Enter key to exit. " - - exit -) else ( - rmdir /s /q "!INSTALLDIR!\install-dummy" - goto CheckUserDir -) - -: CheckUserDir - -:: Check if we need to create !userprofile!\SRB2 - -set "USERDIR=!INSTALLDIR!" - -:: Is config.cfg in our install dir? -if exist "!INSTALLDIR!\config.cfg" goto MoveOldInstall - -:: Are we in AppData? -echo.!STAGINGDIR! | findstr /C:"!LocalAppData!" 1>nul -if errorlevel 1 ( - echo. -) else ( - goto SetUserDir -) - -: Are we in Program Files? -echo.!STAGINGDIR! | findstr /C:"!ProgramFiles!" 1>nul -if NOT errorlevel 1 ( - goto SetUserDir -) - -:: Are we in Program Files (x86)? -echo.!STAGINGDIR! | findstr /C:"!ProgramFiles(X86)!" 1>nul -if NOT errorlevel 1 ( - goto SetUserDir -) - -:: Are we 32-bit and actually in Program Files? -echo.!STAGINGDIR! | findstr /C:"!ProgramW6432!" 1>nul -if NOT errorlevel 1 ( - goto SetUserDir -) - -goto MoveOldInstall - -: SetUserDir -: CheckPermissionsUserDir - -set "USERDIR=!UserProfile!\SRB2" - -:: Check for permissions and create the folder -if exist "!USERDIR!\*" ( - mkdir "!USERDIR!\install-dummy" - - if errorlevel 1 ( - echo User profile folder exists, but we won't operate on it. - echo. - goto MoveOldInstall - ) else ( - rmdir /s /q "!USERDIR!\install-dummy" - ) -) else ( - mkdir "!USERDIR!" - - if errorlevel 1 ( - echo Could not create user profile folder - echo Defaulting to install dir: "!INSTALLDIR!" - echo. - set "USERDIR=!INSTALLDIR!" - goto MoveOldInstall - ) -) - -:: Now copy READMEs -:: echo f answers xcopy's prompt as to whether the destination is a file or a folder -echo f | xcopy /y "!STAGINGDIR!\README.txt" "!USERDIR!\README.txt" -echo f | xcopy /y "!STAGINGDIR!\LICENSE.txt" "!USERDIR!\LICENSE.txt" -echo f | xcopy /y "!STAGINGDIR!\LICENSE-3RD-PARTY.txt" "!USERDIR!\LICENSE-3RD-PARTY.txt" -echo Your game data and mods folder is: > "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo !USERDIR! >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo Your install folder is: >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo !INSTALLDIR! >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo To run SRB2, go to: >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo. >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" -echo Start Menu ^> Programs ^> Sonic Robo Blast 2 >> "!USERDIR!\^! Data and Mods Go Here ^!.txt" - -:: Copy path to install folder - -set "SCRIPT=!TEMP!\!RANDOM!-!RANDOM!-!RANDOM!-!RANDOM!.vbs" -echo Set oWS = WScript.CreateObject("WScript.Shell") >> "!SCRIPT!" -echo sLinkFile = "!USERDIR!\^! SRB2 Install Folder ^!.lnk" >> "!SCRIPT!" -echo Set oLink = oWS.CreateShortcut(sLinkFile) >> "!SCRIPT!" -echo oLink.TargetPath = "!INSTALLDIR!" >> "!SCRIPT!" -echo oLink.WorkingDirectory = "!INSTALLDIR!" >> "!SCRIPT!" -echo oLink.Arguments = "" >> "!SCRIPT!" -echo oLink.IconLocation = "!INSTALLDIR!\srb2win.exe,0" >> "!SCRIPT!" -echo oLink.Save >> "!SCRIPT!" -cscript /nologo "!SCRIPT!" -del "!SCRIPT!" - -:: Also do it the other way around - -set "SCRIPT=!TEMP!\!RANDOM!-!RANDOM!-!RANDOM!-!RANDOM!.vbs" -echo Set oWS = WScript.CreateObject("WScript.Shell") >> "!SCRIPT!" -echo sLinkFile = "!INSTALLDIR!\^! SRB2 Data Folder ^!.lnk" >> "!SCRIPT!" -echo Set oLink = oWS.CreateShortcut(sLinkFile) >> "!SCRIPT!" -echo oLink.TargetPath = "!USERDIR!" >> "!SCRIPT!" -echo oLink.WorkingDirectory = "!USERDIR!" >> "!SCRIPT!" -echo oLink.Arguments = "" >> "!SCRIPT!" -echo oLink.IconLocation = "!INSTALLDIR!\srb2win.exe,0" >> "!SCRIPT!" -echo oLink.Save >> "!SCRIPT!" -cscript /nologo "!SCRIPT!" -del "!SCRIPT!" - -: MoveOldInstall - -if exist "!INSTALLDIR!\old-install\*" ( - set "OLDINSTALLDIR=!INSTALLDIR!\old-install-!RANDOM!" -) else ( - set "OLDINSTALLDIR=!INSTALLDIR!\old-install" -) - -mkdir "!OLDINSTALLDIR!" - -:: -:: Move all old install files -:: We support a list of explicit files to copy to old-install -:: And later, we also loop through our staging files, look for the pre-existing copy in -:: install root, then copy that also to old-install -:: - -:: Extract the uninstall-list.txt and uninstall-userdir.txt files from uninstaller.exe -:: if it exists - -if exist "!INSTALLDIR!\uninstall.exe" ( - if NOT ["!SVZIP!"] == [""] ( - "!SVZIP!" x "!INSTALLDIR!\uninstall.exe" "uninstall-list.txt" -o"!INSTALLDIR!" - "!SVZIP!" x "!INSTALLDIR!\uninstall.exe" "uninstall-userdir.txt" -o"!INSTALLDIR!" - ) -) - -set OLDINSTALLCHANGED= - -if exist "!STAGINGDIR!\old-install-list.txt" ( - goto MoveOldInstallOldFiles -) else ( - goto MoveOldInstallNewFiles -) - -: MoveOldInstallOldFiles - -set "TESTFILE=!TEMP!\!RANDOM!.txt" - -:: Do our failsafes before copying the file in the list -:: See uninstall.bat for details -for /F "usebackq tokens=*" %%A in ("!STAGINGDIR!\old-install-list.txt") do ( - if exist "!INSTALLDIR!\%%A" ( - if NOT ["%%A"] == [""] ( - if NOT ["%%A"] == ["%~nx0"] ( - echo %%A> "!TESTFILE!" - findstr /r ".*[<>:\"\"/\\|?*%%].*" "!TESTFILE!" >nul - if !errorlevel! equ 0 ( - echo %%A has invalid characters, skipping... - ) else ( - if exist "!INSTALLDIR!\%%A\*" ( - echo %%A is a folder, skipping... - ) else ( - echo Moving !INSTALLDIR!\%%A to "old-install" folder - echo f | xcopy /y /v "!INSTALLDIR!\%%A" "!OLDINSTALLDIR!\%%A" - if errorlevel 0 del /f /q "!INSTALLDIR!\%%A" - ) - ) - ) - ) - ) -) - -del /q /f "!STAGINGDIR!\old-install-list.txt" - -for %%F in ("!OLDINSTALLDIR!\*") DO ( - set OLDINSTALLCHANGED=1 - goto MoveOldInstallNewFiles -) - -: MoveOldInstallNewFiles - -:: Save a list of standard files -:: So the uninstall script will know what to remove -:: Append to any existing file, in case we are a patch - -dir /b /a-d "!STAGINGDIR!" >> "!INSTALLDIR!\uninstall-list.txt" - -:: Overwrite the last known gamedata folder - -echo !USERDIR! > "!INSTALLDIR!\uninstall-userdir.txt" - -:: Add the install-generated to the uninstall list -:: NO FOLLOWING SPACES AFTER THE FILENAME!!! - -echo uninstall.bat>> "!INSTALLDIR!\uninstall-list.txt" -echo uninstall-list.txt>> "!INSTALLDIR!\uninstall-list.txt" -echo uninstall-userdir.txt>> "!INSTALLDIR!\uninstall-list.txt" -:: *ahem* Prints as ^! SRB2 Data Folder ^!.lnk -:: We need to escape the exclamations (^^!) and the carets themselves (^^^^) -echo ^^^^^^! SRB2 Data Folder ^^^^^^!.lnk>> "!INSTALLDIR!\uninstall-list.txt" - -:: Add the uninstall list files to the uninstall EXE - -if NOT ["!SVZIP!"] == [""] ( - if exist "!INSTALLDIR!\new-install\uninstall.exe" ( - "!SVZIP!" a "!INSTALLDIR!\new-install\uninstall.exe" "!INSTALLDIR!\uninstall-list.txt" -sdel - "!SVZIP!" a "!INSTALLDIR!\new-install\uninstall.exe" "!INSTALLDIR!\uninstall-userdir.txt" -sdel - ) -) - -:: Start moving files - -for %%F in ("!STAGINGDIR!\*") DO ( - if exist "!INSTALLDIR!\%%~nxF" ( - set OLDINSTALLCHANGED=1 - move "!INSTALLDIR!\%%~nxF" "!OLDINSTALLDIR!\%%~nxF" - ) - if NOT ["%%~nxF"] == ["staging.bat"] ( - if NOT ["%%~nxF"] == ["staging.txt"] ( - move "!STAGINGDIR!\%%~nxF" "!INSTALLDIR!\%%~nxF" - ) - ) -) - -: Finished - -del /q /f "!INSTALLDIR!\^! SRB2 INSTALL INSTRUCTIONS ^!.txt" - -set MSGEXE= -if exist "!SystemRoot!\System32\msg.exe" ( - set MSGEXE=!SystemRoot!\System32\msg.exe -) else ( - if exist "!SystemRoot!\Sysnative\msg.exe" ( - set MSGEXE=!SystemRoot!\Sysnative\msg.exe - ) -) - -if ["!OLDINSTALLCHANGED!"] == ["1"] ( - "!systemroot!\explorer.exe" /select, "!OLDINSTALLDIR!" - echo Finished^^! Some of your old installation files were moved to the "old-install" folder. > !TEMP!\srb2msgprompt.txt - echo. >> !TEMP!\srb2msgprompt.txt - echo If you no longer need these files, you may delete the folder safely. >> !TEMP!\srb2msgprompt.txt - echo. >> !TEMP!\srb2msgprompt.txt - echo To run SRB2, go to: Start Menu ^> Programs ^> Sonic Robo Blast 2. >> !TEMP!\srb2msgprompt.txt - !MSGEXE! "!username!" < !TEMP!\srb2msgprompt.txt - del !TEMP!\srb2msgprompt.txt -) else ( - if /I ["!USERDIR!"] == ["!INSTALLDIR!"] ( - "!systemroot!\explorer.exe" "!INSTALLDIR!" - echo Finished^^! > !TEMP!\srb2msgprompt.txt - echo. >> !TEMP!\srb2msgprompt.txt - echo To run SRB2, go to: Start Menu ^> Programs ^> Sonic Robo Blast 2. >> !TEMP!\srb2msgprompt.txt - !MSGEXE! "!username!" < !TEMP!\srb2msgprompt.txt - del !TEMP!\srb2msgprompt.txt - ) else ( - "!systemroot!\explorer.exe" "!USERDIR!" - echo Finished^^! You may find your game data in this folder: > !TEMP!\srb2msgprompt.txt - echo. >> !TEMP!\srb2msgprompt.txt - echo !USERDIR! >> !TEMP!\srb2msgprompt.txt - echo. >> !TEMP!\srb2msgprompt.txt - echo To run SRB2, go to: Start Menu ^> Programs ^> Sonic Robo Blast 2. >> !TEMP!\srb2msgprompt.txt - !MSGEXE! "!username!" < !TEMP!\srb2msgprompt.txt - del !TEMP!\srb2msgprompt.txt - ) -) - -: Attempt to remove OLDINSTALLDIR, in case it's empty -rmdir /q "!OLDINSTALLDIR!" -cd \ -start "" /b "cmd" /s /c " del /f /q "%STAGINGDIR%\*"&rmdir /s /q "%STAGINGDIR%"&exit /b " diff --git a/windows-installer/uninstaller/uninstall.bat b/windows-installer/uninstaller/uninstall.bat deleted file mode 100644 index ed7c3339..00000000 --- a/windows-installer/uninstaller/uninstall.bat +++ /dev/null @@ -1,183 +0,0 @@ -@echo off - -setlocal enabledelayedexpansion - -cls - -set "INSTALLDIR=%~dp0" -set "INSTALLDIR=!INSTALLDIR:~0,-1!" -set /p USERDIR=<"!INSTALLDIR!\uninstall-userdir.txt" -set "USERDIR=!USERDIR:~0,-1!" - -: ProceedPrompt - -if ["%1"] == ["/y"] ( - set "PROCEED=1" -) else ( - set PROCEED= - set /p PROCEED="Are you sure you want to uninstall SRB2? [yes/no] " - - if /I ["!PROCEED:~0,1!"] == ["n"] exit - if /I ["!PROCEED!"] == ["y"] ( - echo Type Yes or No - echo. - goto ProceedPrompt - ) else ( - if /I ["!PROCEED!"] == ["yes"] ( - set PROCEED=1 - ) else ( - echo. - goto ProceedPrompt - ) - ) -) - -:: Failsafe, in case we Ctrl+C and decline "Terminate batch file?" - -if NOT ["!PROCEED!"] == ["1"] ( - exit -) - -: CheckPermissions - -:: Write a dummy file and check for an error. If error, we need administrator rights - -mkdir "!INSTALLDIR!\uninstall-dummy" - -:: TODO elevate automatically -if errorlevel 1 ( - echo We need Administrator Rights to uninstall SRB2. - echo. - echo Try running this uninstaller by right-clicking on the icon - echo and click "Run as administrator" - echo. - set /p ADMINFINAL="Press Enter key to exit. " - exit -) else ( - rmdir /s /q "!INSTALLDIR!\uninstall-dummy" - goto DeleteFiles -) - -: DeleteFiles - -:: Our deletion list is a list of filenames, no paths, in the current folder -:: -:: We apply the following failsafes: -:: 1. Is filename the script itself? -:: 2. Does filename have illegal characters? https://stackoverflow.com/a/33625339/241046 -:: 3. Is filename a directory? -:: -:: TODO hack this to support .\file.txt relative paths -:: Can %%A be substring'd to get only the filename and extension? -:: If so, print that to the temp file instead of the whole line -:: And possibly do the folder check before the invalid char check. -:: ALSO: Don't honor upward relative paths! (..\) -:: -set "TESTFILE=!TEMP!\!RANDOM!.txt" - -for /F "usebackq tokens=*" %%A in ("!INSTALLDIR!\uninstall-list.txt") do ( - if exist "!INSTALLDIR!\%%A" ( - if NOT ["%%A"] == [""] ( - if NOT ["%%A"] == ["%~nx0"] ( - echo %%A> "!TESTFILE!" - findstr /r ".*[<>:\"\"/\\|?*%%].*" "!TESTFILE!" >nul - if !errorlevel! equ 0 ( - echo %%A has invalid characters, skipping... - ) else ( - if exist "!INSTALLDIR!\%%A\*" ( - echo %%A is a folder, skipping... - ) else ( - echo Deleting !INSTALLDIR!\%%A - del /q /f "!INSTALLDIR!\%%A" - ) - ) - ) - ) - ) -) - -del /q /f "!TESTFILE!" - -: AllDone - -:: Delete the program icons -echo Deleting your program icons... -echo. - -cd \ -rmdir /s /q "!AppData!\Microsoft\Windows\Start Menu\Programs\Sonic Robo Blast 2" - -:: Check if our install folder is non-empty - -set USERDIRFILLED= -set INSTALLDIRFILLED= -for /F %%i in ('dir /b /a "!USERDIR!\*"') do ( - if NOT ["%%i"] == ["%~nx0"] ( - set USERDIRFILLED=1 - goto InstallFilledCheck - ) -) - -: InstallFilledCheck - -if /I NOT ["!USERDIR!"] == ["!INSTALLDIR!"] ( - for /F %%i in ('dir /b /a "!INSTALLDIR!\*"') do ( - if ["%%i"] == ["%~nx0"] ( - echo. - ) else ( - set INSTALLDIRFILLED=1 - goto Final - ) - ) -) - -: Final - -echo All done^^! Visit http://www.srb2.org if you want to play SRB2 again^^! -echo. - -set "FINALPROMPT=Press Enter key to exit." -if ["!USERDIRFILLED!"] == ["1"] ( - echo We left your game data and mods alone, so you may delete those manually. - echo. - echo !USERDIR! - echo. - set "FINALPROMPT=Do you want to view your data? [yes/no]" -) - -if ["!INSTALLDIRFILLED!"] == ["1"] ( - echo We left some extra files alone in your install folder. - echo. - echo !INSTALLDIR! - echo. - set "FINALPROMPT=Do you want to view your data? [yes/no]" -) - -set FINALRESPONSE= -set /p FINALRESPONSE="!FINALPROMPT! " - -if NOT ["!FINALPROMPT!"] == ["Press Enter key to exit."] ( - if /I ["!FINALRESPONSE:~0,1!"] == ["y"] ( - if ["!USERDIRFILLED!"] == ["1"] ( - "!SystemRoot!\explorer.exe" "!USERDIR!" - ) - if ["!INSTALLDIRFILLED!"] == ["1"] ( - "!SystemRoot!\explorer.exe" "!INSTALLDIR!" - ) - ) else ( - if ["!FINALRESPONSE!"] == [""] ( - if ["!USERDIRFILLED!"] == ["1"] ( - "!SystemRoot!\explorer.exe" "!USERDIR!" - ) - if ["!INSTALLDIRFILLED!"] == ["1"] ( - "!SystemRoot!\explorer.exe" "!INSTALLDIR!" - ) - ) - ) -) - -: DeferredDelete - -:: Now let's delete our installation folder! -cd \ -start "" /b "cmd" /s /c " del /q /f "%INSTALLDIR%\uninstall.bat"&timeout /t 2 > NUL&rmdir "%INSTALLDIR%"&exit /b " From 01f1933f69e09ccac0d0651465c412e93a354a20 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 8 Dec 2018 14:05:58 -0500 Subject: [PATCH 02/58] Force directsound to fix wrong-pitch sound effects --- src/sdl/mixer_sound.c | 6 ++++++ src/sdl/sdl_sound.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 3f9b09f1..083ef005 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -92,6 +92,12 @@ void I_StartupSound(void) { I_Assert(!sound_started); +#ifdef _WIN32 + // Force DirectSound instead of WASAPI + // SDL 2.0.6+ defaults to the latter and it screws up our sound effects + SDL_setenv("SDL_AUDIODRIVER", "directsound", 1); +#endif + // EE inits audio first so we're following along. if (SDL_WasInit(SDL_INIT_AUDIO) == SDL_INIT_AUDIO) { diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index f4796cd8..7fec9202 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -1186,6 +1186,12 @@ void I_StartupSound(void) // Configure sound device CONS_Printf("I_StartupSound:\n"); + #ifdef _WIN32 + // Force DirectSound instead of WASAPI + // SDL 2.0.6+ defaults to the latter and it screws up our sound effects + SDL_setenv("SDL_AUDIODRIVER", "directsound", 1); + #endif + // EE inits audio first so we're following along. if (SDL_WasInit(SDL_INIT_AUDIO) == SDL_INIT_AUDIO) CONS_Printf("SDL Audio already started\n"); From 47ee3525afed8c071c4bd2dec7251dec9db53214 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 8 Dec 2018 14:10:09 -0500 Subject: [PATCH 03/58] Indentation --- src/sdl/sdl_sound.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c index 7fec9202..41210279 100644 --- a/src/sdl/sdl_sound.c +++ b/src/sdl/sdl_sound.c @@ -1186,11 +1186,11 @@ void I_StartupSound(void) // Configure sound device CONS_Printf("I_StartupSound:\n"); - #ifdef _WIN32 - // Force DirectSound instead of WASAPI - // SDL 2.0.6+ defaults to the latter and it screws up our sound effects - SDL_setenv("SDL_AUDIODRIVER", "directsound", 1); - #endif +#ifdef _WIN32 + // Force DirectSound instead of WASAPI + // SDL 2.0.6+ defaults to the latter and it screws up our sound effects + SDL_setenv("SDL_AUDIODRIVER", "directsound", 1); +#endif // EE inits audio first so we're following along. if (SDL_WasInit(SDL_INIT_AUDIO) == SDL_INIT_AUDIO) From 582c5332f44e4b8547f3b43ed59a9a87406a5023 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Tue, 11 Dec 2018 18:38:35 +0000 Subject: [PATCH 04/58] Add some checks to prevent invalid awayviewmobjs from crashing the game. Not fullproof but at the least the P_CameraThinker crash no longer happens --- src/p_mobj.c | 2 +- src/p_user.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 8811308a..4fea1580 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3506,7 +3506,7 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled if (player->pflags & PF_FLIPCAM && !(player->pflags & PF_NIGHTSMODE) && player->mo->eflags & MFE_VERTICALFLIP) postimg = postimg_flip; - else if (player->awayviewtics && player->awayviewmobj != NULL) // Camera must obviously exist + else if (player->awayviewtics && player->awayviewmobj && !P_MobjWasRemoved(player->awayviewmobj)) // Camera must obviously exist { camera_t dummycam; dummycam.subsector = player->awayviewmobj->subsector; diff --git a/src/p_user.c b/src/p_user.c index cf129669..90616754 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8372,7 +8372,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall if (!(multiplayer || netgame) && !splitscreen) { fixed_t vx = thiscam->x, vy = thiscam->y; - if (player->awayviewtics && player->awayviewmobj != NULL) // Camera must obviously exist + if (player->awayviewtics && player->awayviewmobj != NULL && !P_MobjWasRemoved(player->awayviewmobj)) // Camera must obviously exist { vx = player->awayviewmobj->x; vy = player->awayviewmobj->y; @@ -8534,7 +8534,7 @@ static void P_CalcPostImg(player_t *player) else pviewheight = player->mo->z + player->viewheight; - if (player->awayviewtics) + if (player->awayviewtics && player->awayviewmobj && !P_MobjWasRemoved(player->awayviewmobj)) { sector = player->awayviewmobj->subsector->sector; pviewheight = player->awayviewmobj->z + 20*FRACUNIT; @@ -8701,6 +8701,13 @@ void P_PlayerThink(player_t *player) } } #endif + + if (player->awayviewmobj && P_MobjWasRemoved(player->awayviewmobj)) + { + P_SetTarget(&player->awayviewmobj, NULL); // remove awayviewmobj asap if invalid + player->awayviewtics = 0; // reset to zero + } + if (player->pflags & PF_GLIDING) { if (player->panim != PA_ABILITY) From c68875ad938bc7b8b44607361392360b43066f74 Mon Sep 17 00:00:00 2001 From: MPC Date: Tue, 11 Dec 2018 20:27:26 -0300 Subject: [PATCH 05/58] Fix remote viewpoint cameras for real I'm so sorry --- src/p_user.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index cf129669..af3f7ebf 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8712,9 +8712,15 @@ void P_PlayerThink(player_t *player) if (player->flashcount) player->flashcount--; - // By the time P_MoveChaseCamera is called, this might be zero. Do not do it here. - //if (player->awayviewtics) - // player->awayviewtics--; + // Re-fixed by Jimita (11-12-2018) + if (player->awayviewtics) + { + player->awayviewtics--; + if (!player->awayviewtics) + player->awayviewtics = -1; + // The timer might've reached zero, but we'll run the remote view camera anyway. + // This is completely fine to do, since -1 evaluates to true in a "if (!player->awayviewtics)" conditional. + } /// \note do this in the cheat code if (player->pflags & PF_NOCLIP) @@ -9492,8 +9498,9 @@ void P_PlayerAfterThink(player_t *player) } } - if (player->awayviewtics) - player->awayviewtics--; + // Reset it to zero if it's a -1. + if (player->awayviewtics < 0) + player->awayviewtics = 0; // spectator invisibility and nogravity. if ((netgame || multiplayer) && player->spectator) From 966afb60171cae5351f35262eb35fb6a1e1bfdee Mon Sep 17 00:00:00 2001 From: Jimita <16945067+monster-psychic-cat@users.noreply.github.com> Date: Wed, 12 Dec 2018 13:09:47 -0200 Subject: [PATCH 06/58] Update p_user.c --- src/p_user.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index af3f7ebf..ecb664ad 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8718,8 +8718,7 @@ void P_PlayerThink(player_t *player) player->awayviewtics--; if (!player->awayviewtics) player->awayviewtics = -1; - // The timer might've reached zero, but we'll run the remote view camera anyway. - // This is completely fine to do, since -1 evaluates to true in a "if (!player->awayviewtics)" conditional. + // The timer might've reached zero, but we'll run the remote view camera anyway by setting it to -1. } /// \note do this in the cheat code @@ -9498,7 +9497,6 @@ void P_PlayerAfterThink(player_t *player) } } - // Reset it to zero if it's a -1. if (player->awayviewtics < 0) player->awayviewtics = 0; From 6b22dc183b11fc06cb0f43507f7f3336e64a4c44 Mon Sep 17 00:00:00 2001 From: MPC Date: Wed, 12 Dec 2018 18:01:52 -0300 Subject: [PATCH 07/58] Fix the automap --- src/am_map.c | 362 +++++++++++------------------------------ src/am_map.h | 3 + src/d_main.c | 23 ++- src/hardware/hw_draw.c | 12 -- src/hardware/hw_main.h | 1 - src/p_local.h | 3 - 6 files changed, 116 insertions(+), 288 deletions(-) diff --git a/src/am_map.c b/src/am_map.c index 6b97dd28..ee690017 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -11,8 +11,8 @@ /// \file am_map.c /// \brief Code for the 'automap', former Doom feature used for DEVMODE testing -#include "g_game.h" #include "am_map.h" +#include "g_game.h" #include "g_input.h" #include "p_local.h" #include "p_slopes.h" @@ -33,7 +33,6 @@ static const UINT8 GRAYSRANGE = 16; static const UINT8 BROWNS = (3*16); static const UINT8 YELLOWS = (7*16); static const UINT8 GREENS = (10*16); -static const UINT8 GREENRANGE = 16; static const UINT8 DBLACK = 31; static const UINT8 DWHITE = 0; @@ -50,8 +49,6 @@ static const UINT8 NOCLIMBYELLOWS = (11*16); // Automap colors #define BACKGROUND DBLACK -#define YOURCOLORS DWHITE -#define YOURRANGE 0 #define WALLCOLORS (REDS + REDRANGE/2) #define WALLRANGE (REDRANGE/2) #define NOCLIMBWALLCOLORS (NOCLIMBREDS + NOCLIMBREDRANGE/2) @@ -68,31 +65,23 @@ static const UINT8 NOCLIMBYELLOWS = (11*16); #define CDWALLCOLORS YELLOWS #define NOCLIMBCDWALLCOLORS NOCLIMBYELLOWS #define THINGCOLORS GREENS -#define THINGRANGE GREENRANGE -#define SECRETWALLCOLORS WALLCOLORS -#define SECRETWALLRANGE WALLRANGE #define GRIDCOLORS (GRAYS + GRAYSRANGE/2) -#define GRIDRANGE 0 #define XHAIRCOLORS GRAYS -// drawing stuff -#define FB 0 - -#define AM_PANDOWNKEY KEY_DOWNARROW +// controls #define AM_PANUPKEY KEY_UPARROW -#define AM_PANRIGHTKEY KEY_RIGHTARROW +#define AM_PANDOWNKEY KEY_DOWNARROW #define AM_PANLEFTKEY KEY_LEFTARROW +#define AM_PANRIGHTKEY KEY_RIGHTARROW + #define AM_ZOOMINKEY '=' #define AM_ZOOMOUTKEY '-' -#define AM_STARTKEY KEY_TAB -#define AM_ENDKEY KEY_TAB #define AM_GOBIGKEY '0' + #define AM_FOLLOWKEY 'f' #define AM_GRIDKEY 'g' -#define AM_MARKKEY 'm' -#define AM_CLEARMARKKEY 'c' -#define AM_NUMMARKPOINTS 10 +#define AM_TOGGLEKEY KEY_TAB // scale on entry #define INITSCALEMTOF (FRACUNIT/5) @@ -110,8 +99,11 @@ static const UINT8 NOCLIMBYELLOWS = (11*16); #define FTOM(x) FixedMul(((x)<>FRACBITS) // translates between frame-buffer and map coordinates -#define CXMTOF(x) (f_x + MTOF((x)-m_x)) -#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) +#define CXMTOF(x) (f_x - (f_x/2) + MTOF((x)-m_x)) +#define CYMTOF(y) (f_y - (f_y/2) + (f_h - MTOF((y)-m_y))) + +#define MAPBITS (FRACBITS-4) +#define FRACTOMAPBITS (FRACBITS-MAPBITS) typedef struct { @@ -133,7 +125,10 @@ typedef struct // A line drawing of the player pointing right, // starting from the middle. // + +#define PLAYERRADIUS (16*(1< @@ -166,27 +161,15 @@ static const mline_t thintriangle_guy[] = { #undef R #define NUMTHINTRIANGLEGUYLINES (sizeof (thintriangle_guy)/sizeof (mline_t)) -static INT32 bigstate; //added : 24-01-98 : moved here, toggle between - // user view and large view (full map view) - -static INT32 grid = 0; - -static INT32 leveljuststarted = 1; // kluge until AM_LevelInit() is called +static boolean bigstate; // user view and large view (full map view) +static boolean draw_grid = false; boolean automapactive = false; boolean am_recalc = false; //added : 05-02-98 : true when screen size changes +static boolean am_stopped = true; -// location of window on screen -static INT32 f_x; -static INT32 f_y; - -// size of window on screen -static INT32 f_w; -static INT32 f_h; - -static INT32 lightlev; // used for funky strobing effect -static UINT8 *fb; // pseudo-frame buffer -static INT32 amclock; +static INT32 f_x, f_y; // location of window on screen (always zero for both) +static INT32 f_w, f_h; // size of window on screen (always the screen width and height respectively) static mpoint_t m_paninc; // how far the window pans each tic (map coords) static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords) @@ -210,11 +193,6 @@ static fixed_t max_y; static fixed_t max_w; // max_x-min_x, static fixed_t max_h; // max_y-min_y -// based on player size -static fixed_t min_w; -static fixed_t min_h; - - static fixed_t min_scale_mtof; // used to tell when to stop zooming out static fixed_t max_scale_mtof; // used to tell when to stop zooming in @@ -232,13 +210,7 @@ static fixed_t scale_ftom; static player_t *plr; // the player represented by an arrow -static patch_t *marknums[10]; // numbers used for marking by the automap -static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are -static INT32 markpointnum = 0; // next point to be assigned - -static INT32 followplayer = 1; // specifies whether to follow the player around - -static boolean stopped = true; +static INT32 followplayer = true; // specifies whether to follow the player around // function for drawing lines, depends on rendermode typedef void (*AMDRAWFLINEFUNC) (const fline_t *fl, INT32 color); @@ -277,8 +249,8 @@ static inline void AM_restoreScaleAndLoc(void) } else { - m_x = plr->mo->x - m_w/2; - m_y = plr->mo->y - m_h/2; + m_x = (plr->mo->x >> FRACTOMAPBITS) - m_w/2; + m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2; } m_x2 = m_x + m_w; m_y2 = m_y + m_h; @@ -288,15 +260,6 @@ static inline void AM_restoreScaleAndLoc(void) scale_ftom = FixedDiv(FRACUNIT, scale_mtof); } -/** Adds a marker at the current location. - */ -static inline void AM_addMark(void) -{ - markpoints[markpointnum].x = m_x + m_w/2; - markpoints[markpointnum].y = m_y + m_h/2; - markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS; -} - /** Determines the bounding box around all vertices. * This is used to set global variables controlling the zoom range. */ @@ -322,11 +285,8 @@ static void AM_findMinMaxBoundaries(void) max_y = vertexes[i].y; } - max_w = max_x - min_x; - max_h = max_y - min_y; - - min_w = 2*PLAYERRADIUS; // const? never changed? - min_h = 2*PLAYERRADIUS; + max_w = (max_x >>= FRACTOMAPBITS) - (min_x >>= FRACTOMAPBITS); + max_h = (max_y >>= FRACTOMAPBITS) - (min_y >>= FRACTOMAPBITS); a = FixedDiv(f_w<mo->x - m_w/2; - m_y = plr->mo->y - m_h/2; + if (plr != NULL && plr->mo != NULL) + { + m_x = (plr->mo->x >> FRACTOMAPBITS) - m_w/2; + m_y = (plr->mo->y >> FRACTOMAPBITS) - m_h/2; + } AM_changeWindowLoc(); // for saving & restoring @@ -396,41 +355,27 @@ static void AM_initVariables(void) old_m_h = m_h; } -static const UINT8 *maplump; // pointer to the raw data for the automap background. - -/** Clears all map markers. - */ -static void AM_clearMarks(void) -{ - INT32 i; - - for (i = 0; i < AM_NUMMARKPOINTS; i++) - markpoints[i].x = -1; // means empty - markpointnum = 0; -} - // // should be called at the start of every level // right now, i figure it out myself // static void AM_LevelInit(void) { - leveljuststarted = 0; - f_x = f_y = 0; f_w = vid.width; f_h = vid.height; - if (rendermode == render_soft) - AM_drawFline = AM_drawFline_soft; -#ifdef HWRENDER // not win32 only 19990829 by Kin - else if (rendermode != render_none) + // Jimita +#ifdef MINIAUTOMAP + f_x = f_w / 2; + f_y = f_h / 2; +#endif + + AM_drawFline = AM_drawFline_soft; +#ifdef HWRENDER + if (rendermode == render_opengl) AM_drawFline = HWR_drawAMline; #endif - else - I_Error("Automap can't run without a render system"); - - AM_clearMarks(); AM_findMinMaxBoundaries(); scale_mtof = FixedDiv(min_scale_mtof*10, 7*FRACUNIT); @@ -446,7 +391,7 @@ static void AM_LevelInit(void) void AM_Stop(void) { automapactive = false; - stopped = true; + am_stopped = true; } /** Enables automap. @@ -457,15 +402,14 @@ static inline void AM_Start(void) { static INT32 lastlevel = -1; - if (!stopped) + if (!am_stopped) AM_Stop(); - stopped = false; + am_stopped = false; if (lastlevel != gamemap || am_recalc) // screen size changed { - am_recalc = false; - AM_LevelInit(); lastlevel = gamemap; + am_recalc = false; } AM_initVariables(); } @@ -503,7 +447,7 @@ boolean AM_Responder(event_t *ev) { if (!automapactive) { - if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY) + if (ev->type == ev_keydown && ev->data1 == 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 @@ -515,10 +459,8 @@ boolean AM_Responder(event_t *ev) } } } - else if (ev->type == ev_keydown) { - rc = true; switch (ev->data1) { @@ -554,7 +496,7 @@ boolean AM_Responder(event_t *ev) mtof_zoommul = M_ZOOMIN; ftom_zoommul = M_ZOOMOUT; break; - case AM_ENDKEY: + case AM_TOGGLEKEY: AM_Stop(); break; case AM_GOBIGKEY: @@ -572,13 +514,7 @@ boolean AM_Responder(event_t *ev) f_oldloc.x = INT32_MAX; break; case AM_GRIDKEY: - grid = !grid; - break; - case AM_MARKKEY: - AM_addMark(); - break; - case AM_CLEARMARKKEY: - AM_clearMarks(); + draw_grid = !draw_grid; break; default: rc = false; @@ -632,8 +568,8 @@ static inline void AM_doFollowPlayer(void) { if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) { - m_x = FTOM(MTOF(plr->mo->x)) - m_w/2; - m_y = FTOM(MTOF(plr->mo->y)) - m_h/2; + m_x = FTOM(MTOF(plr->mo->x >> FRACTOMAPBITS)) - m_w/2; + m_y = FTOM(MTOF(plr->mo->y >> FRACTOMAPBITS)) - m_h/2; m_x2 = m_x + m_w; m_y2 = m_y + m_h; f_oldloc.x = plr->mo->x; @@ -651,8 +587,6 @@ void AM_Ticker(void) if (dedicated || !automapactive) return; - amclock++; - if (followplayer) AM_doFollowPlayer(); @@ -671,72 +605,7 @@ void AM_Ticker(void) */ static void AM_clearFB(INT32 color) { -#ifdef HWRENDER - if (rendermode != render_soft && rendermode != render_none) - { - HWR_clearAutomap(); - return; - } -#endif - - if (!maplump) - memset(fb, color, f_w*f_h*vid.bpp); - else - { - INT32 dmapx, dmapy, i, y; - static INT32 mapxstart, mapystart; - UINT8 *dest = screens[0]; - const UINT8 *src; -#define MAPLUMPHEIGHT (200 - 42) - - if (followplayer) - { - static vertex_t oldplr; - - dmapx = MTOF(plr->mo->x) - MTOF(oldplr.x); //fixed point - dmapy = MTOF(oldplr.y) - MTOF(plr->mo->y); - - oldplr.x = plr->mo->x; - oldplr.y = plr->mo->y; - mapxstart += dmapx>>1; - mapystart += dmapy>>1; - - while (mapxstart >= BASEVIDWIDTH) - mapxstart -= BASEVIDWIDTH; - while (mapxstart < 0) - mapxstart += BASEVIDWIDTH; - while (mapystart >= MAPLUMPHEIGHT) - mapystart -= MAPLUMPHEIGHT; - while (mapystart < 0) - mapystart += MAPLUMPHEIGHT; - } - else - { - mapxstart += (MTOF(m_paninc.x)>>1); - mapystart -= (MTOF(m_paninc.y)>>1); - if (mapxstart >= BASEVIDWIDTH) - mapxstart -= BASEVIDWIDTH; - if (mapxstart < 0) - mapxstart += BASEVIDWIDTH; - if (mapystart >= MAPLUMPHEIGHT) - mapystart -= MAPLUMPHEIGHT; - if (mapystart < 0) - mapystart += MAPLUMPHEIGHT; - } - - //blit the automap background to the screen. - for (y = 0; y < f_h; y++) - { - src = maplump + mapxstart + (y + mapystart)*BASEVIDWIDTH; - for (i = 0; i < BASEVIDWIDTH*vid.dupx; i++) - { - while (src > maplump + BASEVIDWIDTH*MAPLUMPHEIGHT) - src -= BASEVIDWIDTH*MAPLUMPHEIGHT; - *dest++ = *src++; - } - dest += vid.width - vid.dupx*BASEVIDWIDTH; - } - } + V_DrawFill(f_x, f_y, f_w, f_h, color|V_NOSCALESTART); } /** Performs automap clipping of lines. @@ -871,7 +740,7 @@ static boolean AM_clipMline(const mline_t *ml, fline_t *fl) // static void AM_drawFline_soft(const fline_t *fl, INT32 color) { - register INT32 x, y, dx, dy, sx, sy, ax, ay, d; + fixed_t x, y, dx, dy, sx, sy, ax, ay, d; #ifdef _DEBUG static INT32 num = 0; @@ -887,7 +756,8 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) } #endif -#define PUTDOT(xx,yy,cc) fb[(yy)*f_w + (xx)]=(UINT8)(cc) + #define PUTDOT(xx,yy,cc) V_DrawFill(xx,yy,1,1,cc|V_NOSCALESTART); + #define CLIPDOT (x >= f_x && y >= f_y && x < f_x + f_w && y < f_y + f_h) dx = fl->b.x - fl->a.x; ax = 2 * (dx < 0 ? -dx : dx); @@ -905,7 +775,8 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) d = ay - ax/2; for (;;) { - PUTDOT(x, y, color); + if (CLIPDOT) + PUTDOT(x, y, color) if (x == fl->b.x) return; if (d >= 0) @@ -922,7 +793,8 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) d = ax - ay/2; for (;;) { - PUTDOT(x, y, color); + if (CLIPDOT) + PUTDOT(x, y, color) if (y == fl->b.y) return; if (d >= 0) @@ -934,6 +806,9 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) d += ax; } } + + #undef CLIPDOT + #undef PUTDOT } // @@ -1004,15 +879,15 @@ static inline void AM_drawWalls(void) for (i = 0; i < numlines; i++) { - l.a.x = lines[i].v1->x; - l.a.y = lines[i].v1->y; - l.b.x = lines[i].v2->x; - l.b.y = lines[i].v2->y; + l.a.x = lines[i].v1->x >> FRACTOMAPBITS; + l.a.y = lines[i].v1->y >> FRACTOMAPBITS; + l.b.x = lines[i].v2->x >> FRACTOMAPBITS; + l.b.y = lines[i].v2->y >> FRACTOMAPBITS; #ifdef ESLOPE #define SLOPEPARAMS(slope, end1, end2, normalheight) \ if (slope) { \ - end1 = P_GetZAt(slope, l.a.x, l.a.y); \ - end2 = P_GetZAt(slope, l.b.x, l.b.y); \ + end1 = P_GetZAt(slope, lines[i].v1->x, lines[i].v1->y); \ + end2 = P_GetZAt(slope, lines[i].v2->x, lines[i].v2->y); \ } else \ end1 = end2 = normalheight; @@ -1025,17 +900,12 @@ static inline void AM_drawWalls(void) #undef SLOPEPARAMS #endif -// AM_drawMline(&l, GRAYS + 3); // Old, everything-is-gray automap if (!lines[i].backsector) // 1-sided { if (lines[i].flags & ML_NOCLIMB) - { - AM_drawMline(&l, NOCLIMBWALLCOLORS+lightlev); - } + AM_drawMline(&l, NOCLIMBWALLCOLORS); else - { - AM_drawMline(&l, WALLCOLORS+lightlev); - } + AM_drawMline(&l, WALLCOLORS); } #ifdef ESLOPE else if ((backf1 == backc1 && backf2 == backc2) // Back is thok barrier @@ -1052,24 +922,16 @@ static inline void AM_drawWalls(void) #endif { if (lines[i].flags & ML_NOCLIMB) - { - AM_drawMline(&l, NOCLIMBTSWALLCOLORS+lightlev); - } + AM_drawMline(&l, NOCLIMBTSWALLCOLORS); else - { - AM_drawMline(&l, TSWALLCOLORS+lightlev); - } + AM_drawMline(&l, TSWALLCOLORS); } else { if (lines[i].flags & ML_NOCLIMB) - { - AM_drawMline(&l, NOCLIMBTHOKWALLCOLORS+lightlev); - } + AM_drawMline(&l, NOCLIMBTHOKWALLCOLORS); else - { - AM_drawMline(&l, THOKWALLCOLORS+lightlev); - } + AM_drawMline(&l, THOKWALLCOLORS); } } else @@ -1081,7 +943,7 @@ static inline void AM_drawWalls(void) if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight) { #endif - AM_drawMline(&l, NOCLIMBFDWALLCOLORS + lightlev); // floor level change + AM_drawMline(&l, NOCLIMBFDWALLCOLORS); // floor level change } #ifdef ESLOPE else if (backc1 != frontc1 || backc2 != frontc2) { @@ -1089,11 +951,10 @@ static inline void AM_drawWalls(void) else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight) { #endif - AM_drawMline(&l, NOCLIMBCDWALLCOLORS+lightlev); // ceiling level change - } - else { - AM_drawMline(&l, NOCLIMBTSWALLCOLORS+lightlev); + AM_drawMline(&l, NOCLIMBCDWALLCOLORS); // ceiling level change } + else + AM_drawMline(&l, NOCLIMBTSWALLCOLORS); } else { @@ -1103,7 +964,7 @@ static inline void AM_drawWalls(void) if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight) { #endif - AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change + AM_drawMline(&l, FDWALLCOLORS); // floor level change } #ifdef ESLOPE else if (backc1 != frontc1 || backc2 != frontc2) { @@ -1111,11 +972,10 @@ static inline void AM_drawWalls(void) else if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight) { #endif - AM_drawMline(&l, CDWALLCOLORS+lightlev); // ceiling level change - } - else { - AM_drawMline(&l, TSWALLCOLORS+lightlev); + AM_drawMline(&l, CDWALLCOLORS); // ceiling level change } + else + AM_drawMline(&l, TSWALLCOLORS); } } } @@ -1176,6 +1036,11 @@ static void AM_drawLineCharacter(const mline_t *lineguy, size_t lineguylines, fi l.b.x += x; l.b.y += y; + l.a.x >>= FRACTOMAPBITS; + l.a.y >>= FRACTOMAPBITS; + l.b.x >>= FRACTOMAPBITS; + l.b.y >>= FRACTOMAPBITS; + AM_drawMline(&l, color); } } @@ -1184,83 +1049,51 @@ static inline void AM_drawPlayers(void) { INT32 i; player_t *p; - INT32 color; + INT32 color = GREENS; if (!multiplayer) { - AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, - plr->mo->angle, DWHITE, plr->mo->x, plr->mo->y); + AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle, DWHITE, plr->mo->x, plr->mo->y); return; } - // multiplayer + // multiplayer (how??) for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i] || players[i].spectator) continue; p = &players[i]; - if (p->skincolor == 0) - color = GREENS; - else + if (p->skincolor > 0) color = R_GetTranslationColormap(TC_DEFAULT, p->skincolor, GTC_CACHE)[GREENS + 8]; - AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle, - color, p->mo->x, p->mo->y); + AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle, color, p->mo->x, p->mo->y); } } -static inline void AM_drawThings(INT32 colors, INT32 colorrange) +static inline void AM_drawThings(UINT8 colors) { size_t i; mobj_t *t; - (void)colorrange; for (i = 0; i < numsectors; i++) { t = sectors[i].thinglist; while (t) { - AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, - 16<angle, colors + lightlev, t->x, t->y); + AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16<angle, colors, t->x, t->y); t = t->snext; } } } -static inline void AM_drawMarks(void) -{ - INT32 i, fx, fy, w, h; - - for (i = 0; i < AM_NUMMARKPOINTS; i++) - { - if (markpoints[i].x != -1 && marknums[i]) - { - // w = SHORT(marknums[i]->width); - // h = SHORT(marknums[i]->height); - w = 5; // because something's wrong with the wad, i guess - h = 6; // because something's wrong with the wad, i guess - fx = CXMTOF(markpoints[i].x); - fy = CYMTOF(markpoints[i].y); - if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h) - V_DrawPatch(fx, fy, FB, marknums[i]); - } - } -} - /** Draws the crosshair, actually just a dot in software mode. * * \param color Color for the crosshair. */ -static inline void AM_drawCrosshair(INT32 color) +static inline void AM_drawCrosshair(UINT8 color) { - if (rendermode != render_soft) - return; // BP: should be putpixel here - - if (scr_bpp == 1) - fb[(f_w*(f_h + 1))/2] = (UINT8)color; // single point for now - else - *((INT16 *)(void *)fb + (f_w*(f_h + 1))/2) = (INT16)color; + V_DrawFill(f_w/2 + f_x, f_h/2 + f_y, 1, 1, color|V_NOSCALESTART); } /** Draws the automap. @@ -1271,13 +1104,10 @@ void AM_Drawer(void) return; AM_clearFB(BACKGROUND); - if (grid) - AM_drawGrid(GRIDCOLORS); + if (draw_grid) AM_drawGrid(GRIDCOLORS); AM_drawWalls(); AM_drawPlayers(); - AM_drawThings(THINGCOLORS, THINGRANGE); + AM_drawThings(THINGCOLORS); AM_drawCrosshair(XHAIRCOLORS); - - AM_drawMarks(); } diff --git a/src/am_map.h b/src/am_map.h index 4e8c782a..bd4221fb 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -31,6 +31,9 @@ typedef struct #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) #define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) +// Jimita +//#define MINIAUTOMAP + extern boolean am_recalc; // true if screen size changes extern boolean automapactive; // In AutoMap mode? diff --git a/src/d_main.c b/src/d_main.c index 23835136..773ff91b 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -319,8 +319,6 @@ static void D_Display(void) if (!gametic) break; HU_Erase(); - if (automapactive) - AM_Drawer(); break; case GS_INTERMISSION: @@ -374,12 +372,22 @@ static void D_Display(void) break; } - // clean up border stuff - // see if the border needs to be initially drawn if (gamestate == GS_LEVEL) { // draw the view directly - if (!automapactive && !dedicated && cv_renderview.value) + boolean dorenderview = cv_renderview.value; + boolean dorenderautomap = false; + + // Jimita + if (automapactive) + { + dorenderautomap = true; +#ifndef MINIAUTOMAP + dorenderview = false; +#endif + } + + if (dorenderview) { if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { @@ -436,8 +444,11 @@ static void D_Display(void) lastdraw = false; } - ST_Drawer(); + // Jimita + if (dorenderautomap) + AM_Drawer(); + ST_Drawer(); HU_Drawer(); } diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 75523f3d..3963fd93 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -770,18 +770,6 @@ void HWR_DrawViewBorder(INT32 clearlines) // AM_MAP.C DRAWING STUFF // ========================================================================== -// Clear the automap part of the screen -void HWR_clearAutomap(void) -{ - FRGBAFloat fColor = {0, 0, 0, 1}; - - // minx,miny,maxx,maxy - HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); - HWD.pfnClearBuffer(true, true, &fColor); - HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); -} - - // -----------------+ // HWR_drawAMline : draw a line of the automap (the clipping is already done in automap code) // Arg : color is a RGB 888 value diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index b0a14d3b..c7284371 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -31,7 +31,6 @@ void HWR_Startup(void); void HWR_Shutdown(void); -void HWR_clearAutomap(void); void HWR_drawAMline(const fline_t *fl, INT32 color); void HWR_FadeScreenMenuBack(UINT32 color, INT32 height); void HWR_DrawConsoleBack(UINT32 color, INT32 height); diff --git a/src/p_local.h b/src/p_local.h index e09b4951..9164fa7a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -41,9 +41,6 @@ // Convenience macro to fix issue with collision along bottom/left edges of blockmap -Red #define BMBOUNDFIX(xl, xh, yl, yh) {if (xl > xh) xl = 0; if (yl > yh) yl = 0;} -// player radius used only in am_map.c -#define PLAYERRADIUS (16*FRACUNIT) - // MAXRADIUS is for precalculated sector block boxes // the spider demon is larger, // but we do not have any moving sectors nearby From 649b6c9ca19648602996f2fae9c86cd0c301342b Mon Sep 17 00:00:00 2001 From: MPC Date: Wed, 12 Dec 2018 18:53:13 -0300 Subject: [PATCH 08/58] Remove MINIAUTOMAP code --- src/am_map.c | 14 ++------------ src/am_map.h | 3 --- src/d_main.c | 19 ++----------------- 3 files changed, 4 insertions(+), 32 deletions(-) diff --git a/src/am_map.c b/src/am_map.c index ee690017..36fd69e9 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -365,12 +365,6 @@ static void AM_LevelInit(void) f_w = vid.width; f_h = vid.height; - // Jimita -#ifdef MINIAUTOMAP - f_x = f_w / 2; - f_y = f_h / 2; -#endif - AM_drawFline = AM_drawFline_soft; #ifdef HWRENDER if (rendermode == render_opengl) @@ -757,7 +751,6 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) #endif #define PUTDOT(xx,yy,cc) V_DrawFill(xx,yy,1,1,cc|V_NOSCALESTART); - #define CLIPDOT (x >= f_x && y >= f_y && x < f_x + f_w && y < f_y + f_h) dx = fl->b.x - fl->a.x; ax = 2 * (dx < 0 ? -dx : dx); @@ -775,8 +768,7 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) d = ay - ax/2; for (;;) { - if (CLIPDOT) - PUTDOT(x, y, color) + PUTDOT(x, y, color) if (x == fl->b.x) return; if (d >= 0) @@ -793,8 +785,7 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) d = ax - ay/2; for (;;) { - if (CLIPDOT) - PUTDOT(x, y, color) + PUTDOT(x, y, color) if (y == fl->b.y) return; if (d >= 0) @@ -807,7 +798,6 @@ static void AM_drawFline_soft(const fline_t *fl, INT32 color) } } - #undef CLIPDOT #undef PUTDOT } diff --git a/src/am_map.h b/src/am_map.h index bd4221fb..4e8c782a 100644 --- a/src/am_map.h +++ b/src/am_map.h @@ -31,9 +31,6 @@ typedef struct #define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8)) #define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8)) -// Jimita -//#define MINIAUTOMAP - extern boolean am_recalc; // true if screen size changes extern boolean automapactive; // In AutoMap mode? diff --git a/src/d_main.c b/src/d_main.c index 773ff91b..df422232 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -319,6 +319,7 @@ static void D_Display(void) if (!gametic) break; HU_Erase(); + AM_Drawer(); break; case GS_INTERMISSION: @@ -375,19 +376,7 @@ static void D_Display(void) if (gamestate == GS_LEVEL) { // draw the view directly - boolean dorenderview = cv_renderview.value; - boolean dorenderautomap = false; - - // Jimita - if (automapactive) - { - dorenderautomap = true; -#ifndef MINIAUTOMAP - dorenderview = false; -#endif - } - - if (dorenderview) + if (cv_renderview.value && !automapactive) { if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { @@ -444,10 +433,6 @@ static void D_Display(void) lastdraw = false; } - // Jimita - if (dorenderautomap) - AM_Drawer(); - ST_Drawer(); HU_Drawer(); } From a5874019cbc1d5b2d68a1668f7c147b8accd743a Mon Sep 17 00:00:00 2001 From: Jimita <16945067+monster-psychic-cat@users.noreply.github.com> Date: Wed, 12 Dec 2018 19:57:52 -0200 Subject: [PATCH 09/58] Update am_map.c --- src/am_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/am_map.c b/src/am_map.c index 36fd69e9..5ee3feaf 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -734,7 +734,7 @@ static boolean AM_clipMline(const mline_t *ml, fline_t *fl) // static void AM_drawFline_soft(const fline_t *fl, INT32 color) { - fixed_t x, y, dx, dy, sx, sy, ax, ay, d; + INT32 x, y, dx, dy, sx, sy, ax, ay, d; #ifdef _DEBUG static INT32 num = 0; From e628d98f20b5145e45f718b798f0b838c1f6934e Mon Sep 17 00:00:00 2001 From: Jimita <16945067+monster-psychic-cat@users.noreply.github.com> Date: Wed, 12 Dec 2018 19:59:21 -0200 Subject: [PATCH 10/58] Update am_map.c --- src/am_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/am_map.c b/src/am_map.c index 5ee3feaf..5e73d2ec 100644 --- a/src/am_map.c +++ b/src/am_map.c @@ -99,8 +99,8 @@ static const UINT8 NOCLIMBYELLOWS = (11*16); #define FTOM(x) FixedMul(((x)<>FRACBITS) // translates between frame-buffer and map coordinates -#define CXMTOF(x) (f_x - (f_x/2) + MTOF((x)-m_x)) -#define CYMTOF(y) (f_y - (f_y/2) + (f_h - MTOF((y)-m_y))) +#define CXMTOF(x) (f_x + MTOF((x)-m_x)) +#define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y))) #define MAPBITS (FRACBITS-4) #define FRACTOMAPBITS (FRACBITS-MAPBITS) From b84470ec51aa09906c73a7d508ea887243a57419 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 12:01:07 -0500 Subject: [PATCH 11/58] Fix savegamename being improperly built due to missing null char after copying timeattackfolder --- src/dehacked.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index edc4e01d..db1d6eed 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3080,7 +3080,7 @@ static void readmaincfg(MYFILE *f) strncpy(timeattackfolder, gamedatafilename, min(filenamelen, sizeof (timeattackfolder))); timeattackfolder[min(filenamelen, sizeof (timeattackfolder) - 1)] = '\0'; - strncpy(savegamename, timeattackfolder, strlen(timeattackfolder)); + strcpy(savegamename, timeattackfolder); strlcat(savegamename, "%u.ssg", sizeof(savegamename)); // can't use sprintf since there is %u in savegamename strcatbf(savegamename, srb2home, PATHSEP); From 93eda4e7c9308c289645bebb36deb4f389d6b534 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:11:25 -0500 Subject: [PATCH 12/58] EXEC: Search for CFG by file path --- src/command.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/command.c b/src/command.c index 47c6d2e5..16f18749 100644 --- a/src/command.c +++ b/src/command.c @@ -32,6 +32,7 @@ #include "hu_stuff.h" #include "p_setup.h" #include "lua_script.h" +#include "d_netfil.h" // findfile //======== // protos. @@ -641,6 +642,7 @@ static void COM_CEchoDuration_f(void) static void COM_Exec_f(void) { UINT8 *buf = NULL; + char filename[256]; if (COM_Argc() < 2 || COM_Argc() > 3) { @@ -649,13 +651,23 @@ static void COM_Exec_f(void) } // load file + // Try with Argv passed verbatim first, for back compat FIL_ReadFile(COM_Argv(1), &buf); if (!buf) { - if (!COM_CheckParm("-noerror")) - CONS_Printf(M_GetText("couldn't execute file %s\n"), COM_Argv(1)); - return; + // Now try by searching the file path + // filename is modified with the full found path + strcpy(filename, COM_Argv(1)); + if (findfile(filename, NULL, true) != FS_NOTFOUND) + FIL_ReadFile(filename, &buf); + + if (!buf) + { + if (!COM_CheckParm("-noerror")) + CONS_Printf(M_GetText("couldn't execute file %s\n"), COM_Argv(1)); + return; + } } if (!COM_CheckParm("-silent")) From b1641aa8e9e5fe5336e89eccfe3b33935d9bc919 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:17:56 -0500 Subject: [PATCH 13/58] Apply srb2home to SAVECONFIG --- src/m_misc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/m_misc.c b/src/m_misc.c index 1ab5f1fe..b6ebbb43 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -518,6 +518,7 @@ void M_FirstLoadConfig(void) void M_SaveConfig(const char *filename) { FILE *f; + char *filepath; // make sure not to write back the config until it's been correctly loaded if (!gameconfig_loaded) @@ -532,10 +533,14 @@ void M_SaveConfig(const char *filename) return; } - f = fopen(filename, "w"); + // append srb2home to beginning of filename + // configfile already has this applied + filepath = va(pandf,srb2home, filename); + + f = fopen(filepath, "w"); // change it only if valid if (f) - strcpy(configfile, filename); + strcpy(configfile, filepath); else { CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), filename); From 93f7f0a8dfecf194108d076b0b87fe673e25817c Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:23:09 -0500 Subject: [PATCH 14/58] Apply srb2home to debugfile --- src/d_net.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/d_net.c b/src/d_net.c index 82c60e4a..cdd63ea3 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -27,6 +27,7 @@ #include "d_clisrv.h" #include "z_zone.h" #include "i_tcp.h" +#include "d_main.h" // srb2home // // NETWORKING @@ -1374,12 +1375,12 @@ boolean D_CheckNetGame(void) { k++; sprintf(filename, "debug%d.txt", k); - debugfile = fopen(filename, "w"); + debugfile = fopen(va("%s" PATHSEP "%s", srb2home, filename), "w"); } if (debugfile) - CONS_Printf(M_GetText("debug output to: %s\n"), filename); + CONS_Printf(M_GetText("debug output to: %s\n"), va("%s" PATHSEP "%s", srb2home, filename)); else - CONS_Alert(CONS_WARNING, M_GetText("cannot debug output to file %s!\n"), filename); + CONS_Alert(CONS_WARNING, M_GetText("cannot debug output to file %s!\n"), va("%s" PATHSEP "%s", srb2home, filename)); } #endif #endif From d18b2cda5947d10a6da7fee313f038a0341593e4 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:32:38 -0500 Subject: [PATCH 15/58] Apply srb2home to saveconfig ONLY if srb2home isn't already there --- src/m_misc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/m_misc.c b/src/m_misc.c index b6ebbb43..a4f53c71 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -534,8 +534,11 @@ void M_SaveConfig(const char *filename) } // append srb2home to beginning of filename - // configfile already has this applied - filepath = va(pandf,srb2home, filename); + // but check if srb2home isn't already there, first + if (!strstr(filename, srb2home)) + filepath = va(pandf,srb2home, filename); + else + filepath = Z_StrDup(filename); f = fopen(filepath, "w"); // change it only if valid @@ -543,7 +546,7 @@ void M_SaveConfig(const char *filename) strcpy(configfile, filepath); else { - CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), filename); + CONS_Alert(CONS_ERROR, M_GetText("Couldn't save game config file %s\n"), filepath); return; } } From dc7992a81523977b87c922c7398e46a2ca5276b0 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 14:59:12 -0500 Subject: [PATCH 16/58] R_Char2Frame special case for backslash: accept plus as substitute --- src/r_things.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/r_things.h b/src/r_things.h index e4a5f426..6614e0aa 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -219,6 +219,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE char R_Frame2Char(UINT8 frame) FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn) { #if 1 // 2.1 compat + if (cn == '+') return '\\' - 'A'; // PK3 can't use backslash, so use + instead return cn - 'A'; #else if (cn >= 'A' && cn <= 'Z') return cn - 'A'; From 9c2197db172c289d5ed30350de4758ed0c3bb59b Mon Sep 17 00:00:00 2001 From: MPC Date: Fri, 14 Dec 2018 14:08:25 -0300 Subject: [PATCH 17/58] Software plane fixes --- src/console.c | 5 +- src/r_bsp.c | 2 - src/r_main.c | 289 +++++++++++++++++++++++-------------------------- src/r_plane.c | 78 ++++++------- src/r_plane.h | 25 +---- src/r_segs.c | 48 ++------ src/r_splats.c | 22 ++-- src/r_things.c | 6 +- src/screen.c | 8 -- 9 files changed, 202 insertions(+), 281 deletions(-) diff --git a/src/console.c b/src/console.c index 2c148bc6..11bf4cb1 100644 --- a/src/console.c +++ b/src/console.c @@ -58,10 +58,7 @@ static boolean consoleready; // console prompt is ready INT32 con_destlines; // vid lines used by console at final position static INT32 con_curlines; // vid lines currently used by console - INT32 con_clipviewtop; // clip value for planes & sprites, so that the - // part of the view covered by the console is not - // drawn when not needed, this must be -1 when - // console is off + INT32 con_clipviewtop; // (useless) static INT32 con_hudlines; // number of console heads up message lines static INT32 con_hudtime[MAXHUDLINES]; // remaining time of display for hud msg lines diff --git a/src/r_bsp.c b/src/r_bsp.c index 35543827..a41c6403 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -1119,7 +1119,6 @@ static void R_Subsector(size_t num) } light = R_GetPlaneLight(frontsector, polysec->floorheight, viewz < polysec->floorheight); - light = 0; ffloor[numffloors].plane = R_FindPlane(polysec->floorheight, polysec->floorpic, polysec->lightlevel, xoff, yoff, polysec->floorpic_angle-po->angle, @@ -1167,7 +1166,6 @@ static void R_Subsector(size_t num) } light = R_GetPlaneLight(frontsector, polysec->ceilingheight, viewz < polysec->ceilingheight); - light = 0; ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic, polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle, NULL, NULL diff --git a/src/r_main.c b/src/r_main.c index 23eff452..2b0fbc39 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -551,13 +551,11 @@ void R_SetViewSize(void) // void R_ExecuteSetViewSize(void) { - fixed_t cosadj; fixed_t dy; INT32 i; INT32 j; INT32 level; INT32 startmapl; - INT32 aspectx; //added : 02-02-98 : for aspect ratio calc. below... setsizeneeded = false; @@ -597,31 +595,22 @@ void R_ExecuteSetViewSize(void) for (i = 0; i < viewwidth; i++) screenheightarray[i] = (INT16)viewheight; - // setup sky scaling (uses pspriteyscale) + // setup sky scaling R_SetSkyScale(); // planes - //aspectx = (((vid.height*centerx*BASEVIDWIDTH)/BASEVIDHEIGHT)/vid.width); - aspectx = centerx; - if (rendermode == render_soft) { // this is only used for planes rendering in software mode - j = viewheight*8; + j = viewheight*16; for (i = 0; i < j; i++) { - dy = ((i - viewheight*2)<>ANGLETOFINESHIFT)); - distscale[i] = FixedDiv(FRACUNIT, cosadj); - } - memset(scalelight, 0xFF, sizeof(scalelight)); // Calculate the light levels to use for each level/scale combination. @@ -734,9 +723,136 @@ static mobj_t *viewmobj; // WARNING: a should be unsigned but to add with 2048, it isn't! #define AIMINGTODY(a) ((FINETANGENT((2048+(((INT32)a)>>ANGLETOFINESHIFT)) & FINEMASK)*160)>>FRACBITS) -void R_SkyboxFrame(player_t *player) +// recalc necessary stuff for mouseaiming +// slopes are already calculated for the full possible view (which is 4*viewheight). +// 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) +static void R_SetupFreelook(void) { INT32 dy = 0; + if (rendermode == render_soft) + { + // clip it in the case we are looking a hardware 90 degrees full aiming + // (lmps, network and use F12...) + G_SoftwareClipAimingPitch((INT32 *)&aimingangle); + dy = AIMINGTODY(aimingangle) * viewwidth/BASEVIDWIDTH; + yslope = &yslopetab[viewheight*8 - (viewheight/2 + dy)]; + } + centery = (viewheight/2) + dy; + centeryfrac = centery<climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD) + chasecam = true; // force chasecam on + else if (player->spectator) // no spectator chasecam + chasecam = false; // force chasecam off + + if (chasecam && !thiscam->chase) + { + P_ResetCamera(player, thiscam); + thiscam->chase = true; + } + else if (!chasecam) + thiscam->chase = false; + + viewsky = !skybox; + if (player->awayviewtics) + { + // cut-away view stuff + viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN + I_Assert(viewmobj != NULL); + viewz = viewmobj->z + 20*FRACUNIT; + aimingangle = player->awayviewaiming; + viewangle = viewmobj->angle; + } + else if (!player->spectator && chasecam) + // use outside cam view + { + viewmobj = NULL; + viewz = thiscam->z + (thiscam->height>>1); + aimingangle = thiscam->aiming; + viewangle = thiscam->angle; + } + else + // use the player's eyes view + { + viewz = player->viewz; + + viewmobj = player->mo; + I_Assert(viewmobj != NULL); + + aimingangle = player->aiming; + viewangle = viewmobj->angle; + + if (!demoplayback && player->playerstate != PST_DEAD) + { + if (player == &players[consoleplayer]) + { + viewangle = localangle; // WARNING: camera uses this + aimingangle = localaiming; + } + else if (player == &players[secondarydisplayplayer]) + { + viewangle = localangle2; + aimingangle = localaiming2; + } + } + } + viewz += quake.z; + + viewplayer = player; + + if (chasecam && !player->awayviewtics && !player->spectator) + { + viewx = thiscam->x; + viewy = thiscam->y; + viewx += quake.x; + viewy += quake.y; + + if (thiscam->subsector) + viewsector = thiscam->subsector->sector; + else + viewsector = R_PointInSubsector(viewx, viewy)->sector; + } + else + { + viewx = viewmobj->x; + viewy = viewmobj->y; + viewx += quake.x; + viewy += quake.y; + + if (viewmobj->subsector) + viewsector = viewmobj->subsector->sector; + else + viewsector = R_PointInSubsector(viewx, viewy)->sector; + } + + viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); + viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); + + R_SetupFreelook(); +} + +void R_SkyboxFrame(player_t *player) +{ camera_t *thiscam; if (splitscreen && player == &players[secondarydisplayplayer] @@ -950,146 +1066,7 @@ void R_SkyboxFrame(player_t *player) viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - // recalc necessary stuff for mouseaiming - // slopes are already calculated for the full possible view (which is 4*viewheight). - // 18/08/18: (No it's actually 8*viewheight, thanks MPC aka Jimita for finding this out) - - if (rendermode == render_soft) - { - // clip it in the case we are looking a hardware 90 degrees full aiming - // (lmps, network and use F12...) - G_SoftwareClipAimingPitch((INT32 *)&aimingangle); - - dy = AIMINGTODY(aimingangle) * viewwidth/BASEVIDWIDTH; - - yslope = &yslopetab[(3*viewheight/2) - dy]; - } - centery = (viewheight/2) + dy; - centeryfrac = centery<climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD) - chasecam = true; // force chasecam on - else if (player->spectator) // no spectator chasecam - chasecam = false; // force chasecam off - - if (chasecam && !thiscam->chase) - { - P_ResetCamera(player, thiscam); - thiscam->chase = true; - } - else if (!chasecam) - thiscam->chase = false; - - viewsky = !skybox; - if (player->awayviewtics) - { - // cut-away view stuff - viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN - I_Assert(viewmobj != NULL); - viewz = viewmobj->z + 20*FRACUNIT; - aimingangle = player->awayviewaiming; - viewangle = viewmobj->angle; - } - else if (!player->spectator && chasecam) - // use outside cam view - { - viewmobj = NULL; - viewz = thiscam->z + (thiscam->height>>1); - aimingangle = thiscam->aiming; - viewangle = thiscam->angle; - } - else - // use the player's eyes view - { - viewz = player->viewz; - - viewmobj = player->mo; - I_Assert(viewmobj != NULL); - - aimingangle = player->aiming; - viewangle = viewmobj->angle; - - if (!demoplayback && player->playerstate != PST_DEAD) - { - if (player == &players[consoleplayer]) - { - viewangle = localangle; // WARNING: camera uses this - aimingangle = localaiming; - } - else if (player == &players[secondarydisplayplayer]) - { - viewangle = localangle2; - aimingangle = localaiming2; - } - } - } - viewz += quake.z; - - viewplayer = player; - - if (chasecam && !player->awayviewtics && !player->spectator) - { - viewx = thiscam->x; - viewy = thiscam->y; - viewx += quake.x; - viewy += quake.y; - - if (thiscam->subsector) - viewsector = thiscam->subsector->sector; - else - viewsector = R_PointInSubsector(viewx, viewy)->sector; - } - else - { - viewx = viewmobj->x; - viewy = viewmobj->y; - viewx += quake.x; - viewy += quake.y; - - if (viewmobj->subsector) - viewsector = viewmobj->subsector->sector; - else - viewsector = R_PointInSubsector(viewx, viewy)->sector; - } - - viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); - viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - - // recalc necessary stuff for mouseaiming - // slopes are already calculated for the full possible view (which is 4*viewheight). - // 18/08/18: (No it's actually 8*viewheight, thanks MPC aka Jimita for finding this out) - - if (rendermode == render_soft) - { - // clip it in the case we are looking a hardware 90 degrees full aiming - // (lmps, network and use F12...) - G_SoftwareClipAimingPitch((INT32 *)&aimingangle); - - dy = AIMINGTODY(aimingangle) * viewwidth/BASEVIDWIDTH; - - yslope = &yslopetab[(3*viewheight/2) - dy]; - } - centery = (viewheight/2) + dy; - centeryfrac = centery<= vid.width) x1 = vid.width - 1; + angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; + planecos = FINECOSINE(angle); + planesin = FINESINE(angle); + if (planeheight != cachedheight[y]) { cachedheight[y] = planeheight; distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale); ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale); + + if ((span = abs(centery-y))) + { + ds_xstep = cachedxstep[y] = FixedMul(planesin, planeheight) / span; + ds_ystep = cachedystep[y] = FixedMul(planecos, planeheight) / span; + } } else { @@ -301,13 +296,8 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) ds_ystep = cachedystep[y]; } - length = FixedMul (distance,distscale[x1]); - angle = (currentplane->viewangle + currentplane->plangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; - /// \note Wouldn't it be faster just to add viewx and viewy - // to the plane's x/yoffs anyway?? - - ds_xfrac = FixedMul(FINECOSINE(angle), length) + xoffs; - ds_yfrac = yoffs - FixedMul(FINESINE(angle), length); + ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; + ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; #ifndef NOWATER if (itswater) @@ -315,8 +305,9 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) const INT32 yay = (wtofs + (distance>>9) ) & 8191; // ripples da water texture bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS; + angle = (currentplane->viewangle + currentplane->plangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; - angle = (angle + 2048) & 8191; //90� + angle = (angle + 2048) & 8191; // 90 degrees ds_xfrac += FixedMul(FINECOSINE(angle), (bgofs<> LIGHTZSHIFT; - if (pindex >= MAXLIGHTZ) pindex = MAXLIGHTZ - 1; @@ -365,8 +355,6 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) // R_ClearPlanes // At begining of frame. // -// NOTE: Uses con_clipviewtop, so that when console is on, -// we don't draw the part of the view hidden under the console. void R_ClearPlanes(void) { INT32 i, p; @@ -376,12 +364,12 @@ void R_ClearPlanes(void) for (i = 0; i < viewwidth; i++) { floorclip[i] = (INT16)viewheight; - ceilingclip[i] = (INT16)con_clipviewtop; + ceilingclip[i] = -1; frontscale[i] = INT32_MAX; for (p = 0; p < MAXFFLOORS; p++) { ffloor[p].f_clip[i] = (INT16)viewheight; - ffloor[p].c_clip[i] = (INT16)con_clipviewtop; + ffloor[p].c_clip[i] = -1; } } diff --git a/src/r_plane.h b/src/r_plane.h index 2ab1e83f..53ecc82e 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -37,27 +37,14 @@ typedef struct visplane_s // colormaps per sector extracolormap_t *extra_colormap; + UINT16 padding; - // leave pads for [minx-1]/[maxx+1] - - // words sucks .. should get rid of that.. but eats memory - // THIS IS UNSIGNED! VERY IMPORTANT!! - UINT16 pad1; UINT16 top[MAXVIDWIDTH]; - UINT16 pad2; - UINT16 pad3; UINT16 bottom[MAXVIDWIDTH]; - UINT16 pad4; - INT32 high, low; // R_PlaneBounds should set these. fixed_t xoffs, yoffs; // Scrolling flats. - // SoM: frontscale should be stored in the first seg of the subsector - // where the planes themselves are stored. I'm doing this now because - // the old way caused trouble with the drawseg array was re-sized. - INT32 scaleseg; - struct ffloor_s *ffloor; #ifdef POLYOBJECTS_PLANES polyobj_t *polyobj; @@ -75,17 +62,15 @@ extern INT16 *lastopening, *openings; extern size_t maxopenings; extern INT16 floorclip[MAXVIDWIDTH], ceilingclip[MAXVIDWIDTH]; -extern fixed_t frontscale[MAXVIDWIDTH], yslopetab[MAXVIDHEIGHT*8]; +extern fixed_t frontscale[MAXVIDWIDTH], yslopetab[MAXVIDHEIGHT*16]; 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 lighttable_t **planezlight; - extern fixed_t *yslope; -extern fixed_t distscale[MAXVIDWIDTH]; +extern lighttable_t **planezlight; void R_InitPlanes(void); void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale); @@ -134,8 +119,8 @@ typedef struct planemgr_s #ifdef POLYOBJECTS_PLANES polyobj_t *polyobj; #endif -} planemgr_t; +} visffloor_t; -extern planemgr_t ffloor[MAXFFLOORS]; +extern visffloor_t ffloor[MAXFFLOORS]; extern INT32 numffloors; #endif diff --git a/src/r_segs.c b/src/r_segs.c index 2122cba1..1637ce90 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -1344,24 +1344,12 @@ static void R_RenderSegLoop (void) if (markfloor) { -#if 0 // Old Doom Legacy code - bottom = floorclip[rw_x]-1; - if (top <= ceilingclip[rw_x]) - top = ceilingclip[rw_x]+1; - if (top <= bottom && floorplane) - { - floorplane->top[rw_x] = (INT16)top; - floorplane->bottom[rw_x] = (INT16)bottom; - } -#else // Spiffy new PRBoom code - top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh; - + top = yh < ceilingclip[rw_x] ? ceilingclip[rw_x] : yh; if (++top <= bottom && floorplane) { floorplane->top[rw_x] = (INT16)top; floorplane->bottom[rw_x] = (INT16)bottom; } -#endif } if (numffloors) @@ -1645,26 +1633,11 @@ static void R_RenderSegLoop (void) } for (i = 0; i < numffloors; i++) - { -#ifdef POLYOBJECTS_PLANES - if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg)) - continue; -#endif - ffloor[i].f_frac += ffloor[i].f_step; - } for (i = 0; i < numbackffloors; i++) { - INT32 y_w; - -#ifdef POLYOBJECTS_PLANES - if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg)) - continue; -#endif - y_w = ffloor[i].b_frac >> HEIGHTBITS; - - ffloor[i].f_clip[rw_x] = ffloor[i].c_clip[rw_x] = (INT16)(y_w & 0xFFFF); + 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; } @@ -2775,11 +2748,6 @@ void R_StoreWallRange(INT32 start, INT32 stop) { for (i = 0; i < numffloors; i++) { -#ifdef POLYOBJECTS_PLANES - if (ffloor[i].polyobj && (!curline->polyseg || ffloor[i].polyobj != curline->polyseg)) - continue; -#endif - ffloor[i].f_pos >>= 4; #ifdef ESLOPE ffloor[i].f_pos_slope >>= 4; @@ -3060,7 +3028,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (ceilingplane) //SoM: 3/29/2000: Check for null ceiling planes ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1); else - markceiling = 0; + markceiling = false; + + // Don't render the ceiling again when rendering polyobjects + if (curline->polyseg) + markceiling = false; } // get a new or use the same visplane @@ -3069,7 +3041,11 @@ void R_StoreWallRange(INT32 start, INT32 stop) if (floorplane) //SoM: 3/29/2000: Check for null planes floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1); else - markfloor = 0; + markfloor = false; + + // Don't render the floor again when rendering polyobjects + if (curline->polyseg) + markfloor = false; } ds_p->numffloorplanes = 0; diff --git a/src/r_splats.c b/src/r_splats.c index 8d0a84fa..9ab67127 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -365,9 +365,8 @@ static void R_RenderFloorSplat(floorsplat_t *pSplat, vertex_t *verts, UINT8 *pTe #else lighttable_t **planezlight; fixed_t planeheight; - angle_t angle; - fixed_t distance; - fixed_t length; + angle_t angle, planecos, planesin; + fixed_t distance, span; size_t indexr; INT32 light; #endif @@ -473,12 +472,22 @@ static void R_RenderFloorSplat(floorsplat_t *pSplat, vertex_t *verts, UINT8 *pTe if (x2 >= vid.width) x2 = vid.width - 1; + angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; + planecos = FINECOSINE(angle); + planesin = FINESINE(angle); + if (planeheight != cachedheight[y]) { cachedheight[y] = planeheight; distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); ds_xstep = cachedxstep[y] = FixedMul(distance,basexscale); ds_ystep = cachedystep[y] = FixedMul(distance,baseyscale); + + if ((span = abs(centery-y))) + { + ds_xstep = cachedxstep[y] = FixedMul(planesin, planeheight) / span; + ds_ystep = cachedystep[y] = FixedMul(planecos, planeheight) / span; + } } else { @@ -486,10 +495,9 @@ static void R_RenderFloorSplat(floorsplat_t *pSplat, vertex_t *verts, UINT8 *pTe ds_xstep = cachedxstep[y]; ds_ystep = cachedystep[y]; } - length = FixedMul(distance, distscale[x1]); - angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT; - ds_xfrac = viewx + FixedMul(FINECOSINE(angle), length); - ds_yfrac = -viewy - FixedMul(FINESINE(angle), length); + + ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; + ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; ds_xfrac -= offsetx; ds_yfrac += offsety; diff --git a/src/r_things.c b/src/r_things.c index b7c925e3..67a45a76 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1733,7 +1733,7 @@ static void R_CreateDrawNodes(void) plane = ds->curline->polyseg->visplane; R_PlaneBounds(plane); - if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low) + if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low) ; else { // Put it in! @@ -1762,7 +1762,7 @@ static void R_CreateDrawNodes(void) plane = ds->ffloorplanes[p]; R_PlaneBounds(plane); - if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low || plane->polyobj) + if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low || plane->polyobj) { ds->ffloorplanes[p] = NULL; continue; @@ -1799,7 +1799,7 @@ static void R_CreateDrawNodes(void) plane = PolyObjects[i].visplane; R_PlaneBounds(plane); - if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low) + if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low) { PolyObjects[i].visplane = NULL; continue; diff --git a/src/screen.c b/src/screen.c index d5beaf36..af6aed03 100644 --- a/src/screen.c +++ b/src/screen.c @@ -309,14 +309,6 @@ void SCR_Recalc(void) if (automapactive) AM_Stop(); - // r_plane stuff: visplanes, openings, floorclip, ceilingclip, spanstart, - // spanstop, yslope, distscale, cachedheight, cacheddistance, - // cachedxstep, cachedystep - // -> allocated at the maximum vidsize, static. - - // r_main: xtoviewangle, allocated at the maximum size. - // r_things: negonearray, screenheightarray allocated max. size. - // set the screen[x] ptrs on the new vidbuffers V_Init(); From 3a125dbbd585587330f52a5dc74b317d40defa50 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 17:14:03 +0000 Subject: [PATCH 18/58] compare with actual doubles, not ints --- src/hardware/hw_bsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index a180697d..f9f310a6 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -193,14 +193,14 @@ static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, v2dy = bsp->dy; den = v2dy*v1dx - v2dx*v1dy; - if (den == 0) + if (den == 0.0) return NULL; // parallel // first check the frac along the polygon segment, // (do not accept hit with the extensions) num = (v2x - v1x)*v2dy + (v1y - v2y)*v2dx; frac = num / den; - if (frac < 0 || frac > 1) + if (frac < 0.0 || frac > 1.0) return NULL; // now get the frac along the BSP line From 4089b6b8e9da1075c8e3c463ec7f268b384bda58 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:00:08 +0000 Subject: [PATCH 19/58] use continue if NULL instead of a big if block if ...not NULL also, SplitPoly returns if ps < 0, so there's no need to check for ps >= 0 afterwards --- src/hardware/hw_bsp.c | 144 +++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index f9f310a6..271d832a 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -294,57 +294,57 @@ static void SplitPoly (fdivline_t *bsp, //splitting parametric line // start & end points pv = fracdivline(bsp, &poly->pts[i], &poly->pts[j]); - if (pv) + if (pv == NULL) + continue; + + if (ps < 0) { - if (ps < 0) + // first point + ps = i; + vs = *pv; + fracs = bspfrac; + } + else + { + //the partition line traverse a junction between two segments + // or the two points are so close, they can be considered as one + // thus, don't accept, since split 2 must be another vertex + if (SameVertice(pv, &lastpv)) { - // first point - ps = i; - vs = *pv; - fracs = bspfrac; - } - else - { - //the partition line traverse a junction between two segments - // or the two points are so close, they can be considered as one - // thus, don't accept, since split 2 must be another vertex - if (SameVertice(pv, &lastpv)) + if (pe < 0) { - if (pe < 0) - { - ps = i; - psonline = 1; - } - else - { - pe = i; - peonline = 1; - } + ps = i; + psonline = 1; } else { - if (pe < 0) - { - pe = i; - ve = *pv; - frace = bspfrac; - } - else - { - // a frac, not same vertice as last one - // we already got pt2 so pt 2 is not on the line, - // so we probably got back to the start point - // which is on the line - if (SameVertice(pv, &vs)) - psonline = 1; - break; - } + pe = i; + peonline = 1; + } + } + else + { + if (pe < 0) + { + pe = i; + ve = *pv; + frace = bspfrac; + } + else + { + // a frac, not same vertice as last one + // we already got pt2 so pt 2 is not on the line, + // so we probably got back to the start point + // which is on the line + if (SameVertice(pv, &vs)) + psonline = 1; + break; } } - - // remember last point intercept to detect identical points - lastpv = *pv; } + + // remember last point intercept to detect identical points + lastpv = *pv; } // no split: the partition line is either parallel and @@ -368,7 +368,7 @@ static void SplitPoly (fdivline_t *bsp, //splitting parametric line return; } - if (ps >= 0 && pe < 0) + if (pe < 0) { //I_Error("SplitPoly: only one point for split line (%d %d)", ps, pe); *frontpoly = poly; @@ -482,42 +482,42 @@ static poly_t *CutOutSubsecPoly(seg_t *lseg, INT32 count, poly_t *poly) pv = fracdivline(&cutseg, &poly->pts[i], &poly->pts[j]); - if (pv) + if (pv == NULL) + continue; + + if (ps < 0) { - if (ps < 0) + ps = i; + vs = *pv; + fracs = bspfrac; + } + else + { + //frac 1 on previous segment, + // 0 on the next, + //the split line goes through one of the convex poly + // vertices, happens quite often since the convex + // poly is already adjacent to the subsector segs + // on most borders + if (SameVertice(pv, &vs)) + continue; + + if (fracs <= bspfrac) { + nump = 2 + poly->numpts - (i-ps); + pe = ps; ps = i; - vs = *pv; - fracs = bspfrac; + ve = *pv; } else { - //frac 1 on previous segment, - // 0 on the next, - //the split line goes through one of the convex poly - // vertices, happens quite often since the convex - // poly is already adjacent to the subsector segs - // on most borders - if (SameVertice(pv, &vs)) - continue; - - if (fracs <= bspfrac) - { - nump = 2 + poly->numpts - (i-ps); - pe = ps; - ps = i; - ve = *pv; - } - else - { - nump = 2 + (i-ps); - pe = i; - ve = vs; - vs = *pv; - } - //found 2nd point - break; + nump = 2 + (i-ps); + pe = i; + ve = vs; + vs = *pv; } + //found 2nd point + break; } } From 02fc845a723effa6a40797cd5c6bbead9b0bae3a Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:01:18 +0000 Subject: [PATCH 20/58] Make sure nptfront is explicitly > 0, so we don't alloc a poly for negative number points at all --- src/hardware/hw_bsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 271d832a..c75d0b48 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -387,7 +387,7 @@ static void SplitPoly (fdivline_t *bsp, //splitting parametric line *backpoly = HWR_AllocPoly(2 + nptback); else *backpoly = NULL; - if (nptfront) + if (nptfront > 0) *frontpoly = HWR_AllocPoly(2 + nptfront); else *frontpoly = NULL; From 52fd3dcbed185f78e367cc5d2183d4a39ddfc092 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:11:30 +0000 Subject: [PATCH 21/58] split loading status code into a separate function --- src/hardware/hw_bsp.c | 51 +++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index c75d0b48..09620263 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -589,10 +589,36 @@ static inline void SearchDivline(node_t *bsp, fdivline_t *divline) divline->dy = FIXED_TO_FLOAT(bsp->dy); } +#ifdef HWR_LOADING_SCREEN //Hurdler: implement a loading status static size_t ls_count = 0; static UINT8 ls_percent = 0; +static void loading_status(void) +{ + char s[16]; + int x, y; + + I_OsPolling(); + CON_Drawer(); + sprintf(s, "%d%%", (++ls_percent)<<1); + x = BASEVIDWIDTH/2; + y = BASEVIDHEIGHT/2; + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Black background to match fade in effect + //V_DrawPatchFill(W_CachePatchName("SRB2BACK",PU_CACHE)); // SRB2 background, ehhh too bright. + M_DrawTextBox(x-58, y-8, 13, 1); + V_DrawString(x-50, y, V_YELLOWMAP, "Loading..."); + V_DrawRightAlignedString(x+50, y, V_YELLOWMAP, s); + + // Is this really necessary at this point..? + V_DrawCenteredString(BASEVIDWIDTH/2, 40, V_YELLOWMAP, "OPENGL MODE IS INCOMPLETE AND MAY"); + V_DrawCenteredString(BASEVIDWIDTH/2, 50, V_YELLOWMAP, "NOT DISPLAY SOME SURFACES."); + V_DrawCenteredString(BASEVIDWIDTH/2, 70, V_YELLOWMAP, "USE AT SONIC'S RISK."); + + I_UpdateNoVsync(); +} +#endif + // poly : the convex polygon that encloses all child subsectors static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *bbox) { @@ -631,32 +657,13 @@ static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *b else { HWR_SubsecPoly(bspnum&(~NF_SUBSECTOR), poly); - //Hurdler: implement a loading status + //Hurdler: implement a loading status #ifdef HWR_LOADING_SCREEN if (ls_count-- <= 0) { - char s[16]; - int x, y; - - I_OsPolling(); ls_count = numsubsectors/50; - CON_Drawer(); - sprintf(s, "%d%%", (++ls_percent)<<1); - x = BASEVIDWIDTH/2; - y = BASEVIDHEIGHT/2; - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Black background to match fade in effect - //V_DrawPatchFill(W_CachePatchName("SRB2BACK",PU_CACHE)); // SRB2 background, ehhh too bright. - M_DrawTextBox(x-58, y-8, 13, 1); - V_DrawString(x-50, y, V_YELLOWMAP, "Loading..."); - V_DrawRightAlignedString(x+50, y, V_YELLOWMAP, s); - - // Is this really necessary at this point..? - V_DrawCenteredString(BASEVIDWIDTH/2, 40, V_YELLOWMAP, "OPENGL MODE IS INCOMPLETE AND MAY"); - V_DrawCenteredString(BASEVIDWIDTH/2, 50, V_YELLOWMAP, "NOT DISPLAY SOME SURFACES."); - V_DrawCenteredString(BASEVIDWIDTH/2, 70, V_YELLOWMAP, "USE AT SONIC'S RISK."); - - I_UpdateNoVsync(); + loading_status(); } #endif } @@ -968,7 +975,9 @@ void HWR_CreatePlanePolygons(INT32 bspnum) fixed_t rootbbox[4]; CONS_Debug(DBG_RENDER, "Creating polygons, please wait...\n"); +#ifdef HWR_LOADING_SCREEN ls_count = ls_percent = 0; // reset the loading status +#endif CON_Drawer(); //let the user know what we are doing I_FinishUpdate(); // page flip or blit buffer From b42c306ef36213496910f20ebbd5d593deb59b2b Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:14:08 +0000 Subject: [PATCH 22/58] remove code from SearchDivline that was disabled ...and doesn't seem to exist anymore anyway --- src/hardware/hw_bsp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 09620263..95978c48 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -581,8 +581,6 @@ static inline void HWR_SubsecPoly(INT32 num, poly_t *poly) // search for the segs source of this divline static inline void SearchDivline(node_t *bsp, fdivline_t *divline) { -#if 0 // MAR - If you don't use the same partition line that the BSP uses, the front/back polys won't match the subsectors in the BSP! -#endif divline->x = FIXED_TO_FLOAT(bsp->x); divline->y = FIXED_TO_FLOAT(bsp->y); divline->dx = FIXED_TO_FLOAT(bsp->dx); From 9c04a066d96ab24530c383a0d43a84aaa4741986 Mon Sep 17 00:00:00 2001 From: MPC Date: Fri, 14 Dec 2018 15:49:32 -0300 Subject: [PATCH 23/58] Update r_plane.h --- src/r_plane.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/r_plane.h b/src/r_plane.h index 53ecc82e..6e6a6d49 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -21,7 +21,6 @@ // // Now what is a visplane, anyway? // Simple: kinda floor/ceiling polygon optimised for SRB2 rendering. -// 7764 bytes! (for win32, anyway) // typedef struct visplane_s { @@ -37,10 +36,10 @@ typedef struct visplane_s // colormaps per sector extracolormap_t *extra_colormap; - UINT16 padding; - UINT16 top[MAXVIDWIDTH]; - UINT16 bottom[MAXVIDWIDTH]; + // leave pads for [minx-1]/[maxx+1] + UINT16 padtopstart, top[MAXVIDWIDTH], padtopend; + UINT16 padbottomstart, bottom[MAXVIDWIDTH], padbottomend; INT32 high, low; // R_PlaneBounds should set these. fixed_t xoffs, yoffs; // Scrolling flats. From 623d1574cec726852364ad242bdababaf4e291da Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 21:00:53 +0000 Subject: [PATCH 24/58] minor cleanup --- src/hardware/hw_bsp.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 95978c48..8fec4f96 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -654,7 +654,7 @@ static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *b } else { - HWR_SubsecPoly(bspnum&(~NF_SUBSECTOR), poly); + HWR_SubsecPoly(bspnum & ~NF_SUBSECTOR, poly); //Hurdler: implement a loading status #ifdef HWR_LOADING_SCREEN @@ -666,7 +666,7 @@ static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *b #endif } M_ClearBox(bbox); - poly = extrasubsectors[bspnum&~NF_SUBSECTOR].planepoly; + poly = extrasubsectors[bspnum & ~NF_SUBSECTOR].planepoly; for (i = 0, pt = poly->pts; i < poly->numpts; i++,pt++) M_AddToBox(bbox, FLOAT_TO_FIXED(pt->x), FLOAT_TO_FIXED(pt->y)); @@ -698,14 +698,13 @@ static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *b if (backpoly) { // Correct back bbox to include floor/ceiling convex polygon - WalkBSPNode(bsp->children[1], backpoly, &bsp->children[1], - bsp->bbox[1]); + WalkBSPNode(bsp->children[1], backpoly, &bsp->children[1], bsp->bbox[1]); - // enlarge bbox with seconde child + // enlarge bbox with second child M_AddToBox(bbox, bsp->bbox[1][BOXLEFT ], - bsp->bbox[1][BOXTOP ]); + bsp->bbox[1][BOXTOP ]); M_AddToBox(bbox, bsp->bbox[1][BOXRIGHT ], - bsp->bbox[1][BOXBOTTOM]); + bsp->bbox[1][BOXBOTTOM]); } } @@ -785,9 +784,9 @@ static void SearchSegInBSP(INT32 bspnum,polyvertex_t *p,poly_t *poly) if (bspnum & NF_SUBSECTOR) { - if (bspnum!=-1) + if (bspnum != -1) { - bspnum&=~NF_SUBSECTOR; + bspnum &= ~NF_SUBSECTOR; q = extrasubsectors[bspnum].planepoly; if (poly == q || !q) return; From fa3cc130244b78a25c657863d4f7090abe48ff5f Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:19:38 -0500 Subject: [PATCH 25/58] Add symlink to debian package for /usr/games/srb2 --- debian/rules | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/rules b/debian/rules index 02e3dc78..ff80d50b 100755 --- a/debian/rules +++ b/debian/rules @@ -59,6 +59,7 @@ DBGNAME = debug/$(EXENAME) PKGDIR = usr/games/SRB2 DBGDIR = usr/lib/debug/$(PKGDIR) +LINKDIR = usr/games PIXMAPS_DIR = usr/share/pixmaps DESKTOP_DIR = usr/share/applications PREFIX = $(shell test "$(CROSS_COMPILE_BUILD)" != "$(CROSS_COMPILE_HOST)" && echo "PREFIX=$(CROSS_COMPILE_HOST)") @@ -133,7 +134,7 @@ binary-arch: # dh_installcron # dh_installinfo # dh_installman - # dh_link + dh_link $(PKGDIR)/$(EXENAME) $(LINKDIR)/$(EXENAME) dh_compress dh_fixperms # dh_perl From 09d9a555c65e0fed2329bc79860bb572e2969a22 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:21:07 -0500 Subject: [PATCH 26/58] compiler SSE tweak for 32-bit --- src/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index fbf75f26..36cd1608 100644 --- a/src/Makefile +++ b/src/Makefile @@ -288,7 +288,8 @@ OPTS += -DCOMPVERSION ifndef NONX86 ifndef GCC29 - M5=-march=pentium + #M5=-march=pentium + M5=-march=nocona -msse -mfpmath=sse M4=-march=i486 else M5=-mpentium From c1e0041a0bf1becf6902a8290d08c7fe18a36cf8 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 21:22:13 +0000 Subject: [PATCH 27/58] copy doom legacy's replacement for the den == 0.0 calc in fracdivline --- src/hardware/hw_bsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 8fec4f96..e0ab5b0d 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -193,7 +193,7 @@ static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, v2dy = bsp->dy; den = v2dy*v1dx - v2dx*v1dy; - if (den == 0.0) + if (fabs(den) < 1.0E-36f) // avoid checking exactly for 0.0 return NULL; // parallel // first check the frac along the polygon segment, From abae63a64bb99ded02e91d1edf29f33fff5aeb1a Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:47:24 -0500 Subject: [PATCH 28/58] SameVertice floating point match; fixes 64-bit OGL holes --- src/hardware/hw_bsp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index e0ab5b0d..dc49908b 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -254,10 +254,21 @@ static boolean SameVertice (polyvertex_t *p1, polyvertex_t *p2) if (diff < -1.5f || diff > 1.5f) return false; #else +#if 0 if (p1->x != p2->x) return false; if (p1->y != p2->y) return false; +#else +#define DIVLINE_VERTEX_DIFF 0.45f + float ep = DIVLINE_VERTEX_DIFF; + if (fabsf( p2->x - p1->x ) > ep ) + return false; + if (fabsf( p2->y - p1->y ) > ep ) + return false; + // p1 and p2 are considered the same vertex + return true; +#endif #endif // p1 and p2 are considered the same vertex return true; From de96fe8e7b9c00eab7eeef2c8a907a85b19ac5cc Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:47:38 -0500 Subject: [PATCH 29/58] Revert "compiler SSE tweak for 32-bit" This reverts commit 09d9a555c65e0fed2329bc79860bb572e2969a22. --- src/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 36cd1608..fbf75f26 100644 --- a/src/Makefile +++ b/src/Makefile @@ -288,8 +288,7 @@ OPTS += -DCOMPVERSION ifndef NONX86 ifndef GCC29 - #M5=-march=pentium - M5=-march=nocona -msse -mfpmath=sse + M5=-march=pentium M4=-march=i486 else M5=-mpentium From e0079ea1a29c918b8493183f3aeb1622684b7714 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 23:28:07 +0000 Subject: [PATCH 30/58] remove NearVertice (which was unused anyway), clean up maz's changes --- src/hardware/hw_bsp.c | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index dc49908b..53602cc7 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -217,29 +217,6 @@ static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, return &pt; } -#if 0 -//Hurdler: it's not used anymore -static boolean NearVertice (polyvertex_t *p1, polyvertex_t *p2) -{ -#if 1 - float diff; - diff = p2->x - p1->x; - if (diff < -1.5f || diff > 1.5f) - return false; - diff = p2->y - p1->y; - if (diff < -1.5f || diff > 1.5f) - return false; -#else - if (p1->x != p2->x) - return false; - if (p1->y != p2->y) - return false; -#endif - // p1 and p2 are considered the same vertex - return true; -} -#endif - // if two vertice coords have a x and/or y difference // of less or equal than 1 FRACUNIT, they are considered the same // point. Note: hardcoded value, 1.0f could be anything else. @@ -253,8 +230,7 @@ static boolean SameVertice (polyvertex_t *p1, polyvertex_t *p2) diff = p2->y - p1->y; if (diff < -1.5f || diff > 1.5f) return false; -#else -#if 0 +#elif 0 if (p1->x != p2->x) return false; if (p1->y != p2->y) @@ -263,12 +239,9 @@ static boolean SameVertice (polyvertex_t *p1, polyvertex_t *p2) #define DIVLINE_VERTEX_DIFF 0.45f float ep = DIVLINE_VERTEX_DIFF; if (fabsf( p2->x - p1->x ) > ep ) - return false; - if (fabsf( p2->y - p1->y ) > ep ) - return false; - // p1 and p2 are considered the same vertex - return true; -#endif + return false; + if (fabsf( p2->y - p1->y ) > ep ) + return false; #endif // p1 and p2 are considered the same vertex return true; From f4ce770c1c9773502df85dca664c79844ab32165 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 23:56:11 +0000 Subject: [PATCH 31/58] try out using offsetof for these three macros in d_clisrv.h --- src/d_clisrv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index a906758f..dd1aaf4e 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -429,9 +429,9 @@ extern doomdata_t *netbuffer; extern consvar_t cv_playbackspeed; -#define BASEPACKETSIZE ((size_t)&(((doomdata_t *)0)->u)) -#define FILETXHEADER ((size_t)((filetx_pak *)0)->data) -#define BASESERVERTICSSIZE ((size_t)&(((doomdata_t *)0)->u.serverpak.cmds[0])) +#define BASEPACKETSIZE offsetof(doomdata_t, u) +#define FILETXHEADER offsetof(filetx_pak, data) +#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0]) #define KICK_MSG_GO_AWAY 1 #define KICK_MSG_CON_FAIL 2 From 6fd66bdb49fe85b675216b1d24ab5fd10ae45a85 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 14 Dec 2018 19:33:40 -0500 Subject: [PATCH 32/58] Clear float equal warnings --- src/Makefile.cfg | 4 +--- src/command.c | 2 +- src/hardware/hw_bsp.c | 9 +++++++-- src/hardware/hw_draw.c | 12 ++++++------ src/hardware/hw_main.c | 10 +++++----- src/hardware/r_opengl/r_opengl.c | 11 +++++++---- src/r_data.c | 2 +- src/sdl/mixer_sound.c | 6 ++++-- 8 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/Makefile.cfg b/src/Makefile.cfg index cdd4c3c7..1238050b 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -112,9 +112,7 @@ ifndef GCC295 WFLAGS+=-Wno-div-by-zero endif #WFLAGS+=-Wsystem-headers -ifndef ERRORMODE -#WFLAGS+=-Wfloat-equal -endif +WFLAGS+=-Wfloat-equal #WFLAGS+=-Wtraditional ifdef VCHELP WFLAGS+=-Wdeclaration-after-statement diff --git a/src/command.c b/src/command.c index 16f18749..3183ba70 100644 --- a/src/command.c +++ b/src/command.c @@ -1102,7 +1102,7 @@ static void Setvalue(consvar_t *var, const char *valstr, boolean stealth) if (var->flags & CV_FLOAT) { double d = atof(valstr); - if (!d && valstr[0] != '0') + if (fpclassify(d) == FP_ZERO && valstr[0] != '0') v = INT32_MIN; else v = (INT32)(d * FRACUNIT); diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index a180697d..98f10c95 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -193,7 +193,7 @@ static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, v2dy = bsp->dy; den = v2dy*v1dx - v2dx*v1dy; - if (den == 0) + if (fabsf(den) < 1.0E-36f) return NULL; // parallel // first check the frac along the polygon segment, @@ -253,11 +253,16 @@ static boolean SameVertice (polyvertex_t *p1, polyvertex_t *p2) diff = p2->y - p1->y; if (diff < -1.5f || diff > 1.5f) return false; -#else +#elif 0 if (p1->x != p2->x) return false; if (p1->y != p2->y) return false; +#else + if (fabsf( p2->x - p1->x ) > 1.0E-36f ) + return false; + if (fabsf( p2->y - p1->y ) > 1.0E-36f ) + return false; #endif // p1 and p2 are considered the same vertex return true; diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index 75523f3d..a2ebcb05 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -227,14 +227,14 @@ void HWR_DrawFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, Z_Free(realpatch); } // centre screen - if ((float)vid.width != (float)BASEVIDWIDTH * dupx) + if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) { if (option & V_SNAPTORIGHT) cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); else if (!(option & V_SNAPTOLEFT)) cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2; } - if ((float)vid.height != (float)BASEVIDHEIGHT * dupy) + if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f) { if ((option & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) cy += ((float)vid.height/2 - ((float)BASEVIDHEIGHT/2 * dupy)); @@ -375,14 +375,14 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal Z_Free(realpatch); } // centre screen - if ((float)vid.width != (float)BASEVIDWIDTH * dupx) + if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) { if (option & V_SNAPTORIGHT) cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); else if (!(option & V_SNAPTOLEFT)) cx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx))/2; } - if ((float)vid.height != (float)BASEVIDHEIGHT * dupy) + if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f) { if ((option & (V_SPLITSCREEN|V_SNAPTOBOTTOM)) == (V_SPLITSCREEN|V_SNAPTOBOTTOM)) cy += ((float)vid.height/2 - ((float)BASEVIDHEIGHT/2 * dupy)); @@ -846,14 +846,14 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color) fw *= dupx; fh *= dupy; - if ((float)vid.width != (float)BASEVIDWIDTH * dupx) + if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) { if (color & V_SNAPTORIGHT) fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)); else if (!(color & V_SNAPTOLEFT)) fx += ((float)vid.width - ((float)BASEVIDWIDTH * dupx)) / 2; } - if ((float)vid.height != (float)BASEVIDHEIGHT * dupy) + if (fabsf((float)vid.height - (float)BASEVIDHEIGHT * dupy) > 1.0E-36f) { // same thing here if (color & V_SNAPTOBOTTOM) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index fb5e2a71..2c31c01e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4137,7 +4137,7 @@ static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float t swallVerts[0].z = swallVerts[3].z = spr->z1; swallVerts[2].z = swallVerts[1].z = spr->z2; - if (spr->mobj && this_scale != 1.0f) + if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) { // Always a pixel above the floor, perfectly flat. swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3); @@ -4305,7 +4305,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) wallVerts[1].z = wallVerts[2].z = spr->z2; wallVerts[2].y = wallVerts[3].y = spr->ty; - if (spr->mobj && this_scale != 1.0f) + if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale; else wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; @@ -4585,7 +4585,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) wallVerts[0].x = wallVerts[3].x = spr->x1; wallVerts[2].x = wallVerts[1].x = spr->x2; wallVerts[2].y = wallVerts[3].y = spr->ty; - if (spr->mobj && this_scale != 1.0f) + if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale; else wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; @@ -4831,7 +4831,7 @@ static void HWR_SortVisSprites(void) best = ds; } // order visprites of same scale by dispoffset, smallest first - else if (ds->tz == bestdist && ds->dispoffset < bestdispoffset) + else if (fabsf(ds->tz - bestdist) < 1.0E-36f && ds->dispoffset < bestdispoffset) { bestdispoffset = ds->dispoffset; best = ds; @@ -5752,7 +5752,7 @@ void HWR_SetViewSize(void) gr_viewwindowx = (vid.width - gr_viewwidth) / 2; gr_windowcenterx = (float)(vid.width / 2); - if (gr_viewwidth == vid.width) + if (fabsf(gr_viewwidth - vid.width) < 1.0E-36f) { gr_baseviewwindowy = 0; gr_basewindowcentery = gr_viewheight / 2; // window top left corner at 0,0 diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 2d9f4219..773fe74a 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -602,7 +602,8 @@ static void GLPerspective(GLdouble fovy, GLdouble aspect) const GLdouble deltaZ = zFar - zNear; GLdouble cotangent; - if ((deltaZ == 0.0f) || (sine == 0.0f) || (aspect == 0.0f)) { + if ((fabsf(deltaZ) < 1.0E-36f) || fpclassify(sine) == FP_ZERO || fpclassify(aspect) == FP_ZERO) + { return; } cotangent = cos(radians) / sine; @@ -641,7 +642,7 @@ static void GLProject(GLdouble objX, GLdouble objY, GLdouble objZ, out[2] * projMatrix[2*4+i] + out[3] * projMatrix[3*4+i]; } - if (in[3] == 0.0f) return; + if (fpclassify(in[3]) == FP_ZERO) return; in[0] /= in[3]; in[1] /= in[3]; in[2] /= in[3]; @@ -1986,7 +1987,7 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, pglTexCoord2f(s, t); - if (!nextframe || pol == 0.0f) + if (!nextframe || fpclassify(pol) == FP_ZERO) { pglNormal3f(frame->vertices[pindex].normal[0], frame->vertices[pindex].normal[1], @@ -2055,6 +2056,7 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) pglLoadIdentity(); if (stransform) { + boolean fovx90; // keep a trace of the transformation for md2 memcpy(&md2_transform, stransform, sizeof (md2_transform)); @@ -2069,7 +2071,8 @@ EXPORT void HWRAPI(SetTransform) (FTransform *stransform) pglMatrixMode(GL_PROJECTION); pglLoadIdentity(); - special_splitscreen = (stransform->splitscreen && stransform->fovxangle == 90.0f); + fovx90 = stransform->fovxangle > 0.0f && fabsf(stransform->fovxangle - 90.0f) < 0.5f; + special_splitscreen = (stransform->splitscreen && fovx90); if (special_splitscreen) GLPerspective(53.13l, 2*ASPECT_RATIO); // 53.13 = 2*atan(0.5) else diff --git a/src/r_data.c b/src/r_data.c index 453ef69e..abac871d 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1220,7 +1220,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) continue; if (maskcolor == extra_colormaps[i].maskcolor && fadecolor == extra_colormaps[i].fadecolor - && (float)maskamt == (float)extra_colormaps[i].maskamt + && fabsf(maskamt - extra_colormaps[i].maskamt) < 1.0E-36f && fadestart == extra_colormaps[i].fadestart && fadeend == extra_colormaps[i].fadeend && fog == extra_colormaps[i].fog) diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c index 3f9b09f1..f43be8bc 100644 --- a/src/sdl/mixer_sound.c +++ b/src/sdl/mixer_sound.c @@ -759,6 +759,7 @@ void I_UnloadSong(void) boolean I_PlaySong(boolean looping) { + boolean lpz = fpclassify(loop_point) == FP_ZERO; #ifdef HAVE_LIBGME if (gme) { @@ -772,14 +773,15 @@ boolean I_PlaySong(boolean looping) if (!music) return false; - if (Mix_PlayMusic(music, looping && loop_point == 0.0f ? -1 : 0) == -1) + + if (Mix_PlayMusic(music, looping && lpz ? -1 : 0) == -1) { CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError()); return false; } Mix_VolumeMusic((UINT32)music_volume*128/31); - if (loop_point != 0.0f) + if (!lpz) Mix_HookMusicFinished(music_loop); return true; } From 78634679f1759ef91ac05de655bb5836069460f0 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 14 Dec 2018 20:42:37 -0500 Subject: [PATCH 33/58] fix compiling for MSVC --- src/hardware/r_opengl/r_opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 773fe74a..b324fced 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -602,7 +602,7 @@ static void GLPerspective(GLdouble fovy, GLdouble aspect) const GLdouble deltaZ = zFar - zNear; GLdouble cotangent; - if ((fabsf(deltaZ) < 1.0E-36f) || fpclassify(sine) == FP_ZERO || fpclassify(aspect) == FP_ZERO) + if ((fabsf((float)deltaZ) < 1.0E-36f) || fpclassify(sine) == FP_ZERO || fpclassify(aspect) == FP_ZERO) { return; } From 15d067368513dec677986b8a39d9c96be65ff0d8 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 14 Dec 2018 21:31:00 -0500 Subject: [PATCH 34/58] fix compiling for clang --- src/hardware/hw_bsp.c | 2 +- src/r_data.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_bsp.c b/src/hardware/hw_bsp.c index 98f10c95..2348d71a 100644 --- a/src/hardware/hw_bsp.c +++ b/src/hardware/hw_bsp.c @@ -193,7 +193,7 @@ static polyvertex_t *fracdivline(fdivline_t *bsp, polyvertex_t *v1, v2dy = bsp->dy; den = v2dy*v1dx - v2dx*v1dy; - if (fabsf(den) < 1.0E-36f) + if (fabsf((float)den) < 1.0E-36f) return NULL; // parallel // first check the frac along the polygon segment, diff --git a/src/r_data.c b/src/r_data.c index abac871d..e0b9a814 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1220,7 +1220,7 @@ INT32 R_CreateColormap(char *p1, char *p2, char *p3) continue; if (maskcolor == extra_colormaps[i].maskcolor && fadecolor == extra_colormaps[i].fadecolor - && fabsf(maskamt - extra_colormaps[i].maskamt) < 1.0E-36f + && fabsf((float)(maskamt - extra_colormaps[i].maskamt)) < 1.0E-36f && fadestart == extra_colormaps[i].fadestart && fadeend == extra_colormaps[i].fadeend && fog == extra_colormaps[i].fog) From 6e79722437560d3444f6e1a993cbc6c2dd5e5d05 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 16 Dec 2018 14:01:28 -0500 Subject: [PATCH 35/58] Fix float-equal warning in Win32 interface --- src/win32/win_vid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c index a9dd097b..cca7810b 100644 --- a/src/win32/win_vid.c +++ b/src/win32/win_vid.c @@ -996,7 +996,7 @@ static INT32 WINAPI VID_SetDirectDrawMode(viddef_t *lvid, vmode_t *currentmode) // but rather render to memory bitmap buffer lvid->direct = NULL; - if (!cv_stretch.value && (float)vid.width/vid.height != ((float)BASEVIDWIDTH/BASEVIDHEIGHT)) + 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; From 4ba23e1028f4fd2dbd714ac13596676ddf5bc2b2 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 15:58:47 -0500 Subject: [PATCH 36/58] Expose R_TextureNumForName Backport from SRB2Kart --- src/lua_baselib.c | 23 +++++++++++++++++++++++ src/lua_maplib.c | 8 ++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 96998776..a178b17f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1682,6 +1682,25 @@ static int lib_rSetPlayerSkin(lua_State *L) return 0; } +// R_DATA +//////////// + +static int lib_rCheckTextureNumForName(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + //HUDSAFE + lua_pushinteger(L, R_CheckTextureNumForName(name)); + return 1; +} + +static int lib_rTextureNumForName(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + //HUDSAFE + lua_pushinteger(L, R_TextureNumForName(name)); + return 1; +} + // S_SOUND //////////// @@ -2165,6 +2184,10 @@ static luaL_Reg lib[] = { {"R_Frame2Char",lib_rFrame2Char}, {"R_SetPlayerSkin",lib_rSetPlayerSkin}, + // r_data + {"R_CheckTextureNumForName",lib_rCheckTextureNumForName), + {"R_TextureNumForName",lib_rTextureNumForName), + // s_sound {"S_StartSound",lib_sStartSound}, {"S_StartSoundAtVolume",lib_sStartSoundAtVolume}, diff --git a/src/lua_maplib.c b/src/lua_maplib.c index efe9e6f4..5eb6cb4a 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -795,16 +795,16 @@ static int side_set(lua_State *L) side->rowoffset = luaL_checkfixed(L, 3); break; case side_toptexture: - side->toptexture = luaL_checkinteger(L, 3); + side->toptexture = luaL_checkinteger(L, 3); break; case side_bottomtexture: - side->bottomtexture = luaL_checkinteger(L, 3); + side->bottomtexture = luaL_checkinteger(L, 3); break; case side_midtexture: - side->midtexture = luaL_checkinteger(L, 3); + side->midtexture = luaL_checkinteger(L, 3); break; case side_repeatcnt: - side->repeatcnt = luaL_checkinteger(L, 3); + side->repeatcnt = luaL_checkinteger(L, 3); break; } return 0; From cc22ef3f050073aabd1d311ac746d297a63ce482 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 16:05:18 -0500 Subject: [PATCH 37/58] Add deprecation warning to admin --- src/dehacked.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dehacked.c b/src/dehacked.c index db1d6eed..dd671fd7 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8303,6 +8303,7 @@ static inline int lib_getenum(lua_State *L) LUA_PushUserdata(L, &players[serverplayer], META_PLAYER); return 1; } else if (fastcmp(word,"admin")) { // BACKWARDS COMPATIBILITY HACK: This was replaced with IsPlayerAdmin(), but some 2.1 Lua scripts still use the admin variable. It now points to the first admin player in the array. + LUA_Deprecated(L, "admin", "IsPlayerAdmin(player)"); if (!playeringame[adminplayers[0]] || IsPlayerAdmin(serverplayer)) return 0; LUA_PushUserdata(L, &players[adminplayers[0]], META_PLAYER); From c69cfefb6daa9a14988c1ad0387bd1123c99e93f Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 17:45:49 -0500 Subject: [PATCH 38/58] 2.2 backport of jump/spin axes Needs the config default-changing shenanigans done still, not sure how to tackle that yet. Now the game is TOTALLY playable from a fresh install if you just plug in a controller. --- src/d_netcmd.c | 4 ++++ src/g_game.c | 42 ++++++++++++++++++++++++++++++++++-------- src/g_game.h | 4 ++-- src/m_menu.c | 30 +++++++++++++++++------------- 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 8abfb870..1879c0d9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -689,6 +689,10 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_moveaxis2); CV_RegisterVar(&cv_lookaxis); CV_RegisterVar(&cv_lookaxis2); + CV_RegisterVar(&cv_jumpaxis); + CV_RegisterVar(&cv_jumpaxis2); + CV_RegisterVar(&cv_spinaxis); + CV_RegisterVar(&cv_spinaxis2); CV_RegisterVar(&cv_fireaxis); CV_RegisterVar(&cv_fireaxis2); CV_RegisterVar(&cv_firenaxis); diff --git a/src/g_game.c b/src/g_game.c index 5cc78d4b..55730fa7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -375,6 +375,8 @@ typedef enum AXISLOOK, AXISSTRAFE, AXISDEAD, //Axises that don't want deadzones + AXISJUMP, + AXISSPIN, AXISFIRE, AXISFIRENORMAL, } axis_input_e; @@ -384,6 +386,8 @@ consvar_t cv_turnaxis = {"joyaxis_turn", "LStick.X", CV_SAVE, joyaxis_cons_t, NU consvar_t cv_moveaxis = {"joyaxis_move", "LStick.Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_sideaxis = {"joyaxis_side", "RStick.X", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_lookaxis = {"joyaxis_look", "RStick.Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_jumpaxis = {"joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_spinaxis = {"joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fireaxis = {"joyaxis_fire", "LAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_firenaxis = {"joyaxis_firenormal", "RAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #else @@ -410,8 +414,10 @@ consvar_t cv_lookaxis = {"joyaxis_look", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL consvar_t cv_lookaxis = {"joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif #endif -consvar_t cv_fireaxis = {"joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_firenaxis = {"joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_jumpaxis = {"joyaxis_jump", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_spinaxis = {"joyaxis_spin", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_fireaxis = {"joyaxis_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_firenaxis = {"joyaxis_firenormal", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif #if defined (_WII) || defined (WMINPUT) @@ -419,6 +425,8 @@ consvar_t cv_turnaxis2 = {"joyaxis2_turn", "LStick.X", CV_SAVE, joyaxis_cons_t, consvar_t cv_moveaxis2 = {"joyaxis2_move", "LStick.Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_sideaxis2 = {"joyaxis2_side", "RStick.X", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_lookaxis2 = {"joyaxis2_look", "RStick.Y", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_jumpaxis2 = {"joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_spinaxis2 = {"joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_fireaxis2 = {"joyaxis2_fire", "LAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "RAnalog", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #else @@ -437,8 +445,10 @@ consvar_t cv_sideaxis2 = {"joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NU #ifndef _XBOX consvar_t cv_lookaxis2 = {"joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif -consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_jumpaxis2 = {"joyaxis2_jump", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_spinaxis2 = {"joyaxis2_spin", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_fireaxis2 = {"joyaxis2_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif @@ -804,6 +814,12 @@ static INT32 JoyAxis(axis_input_e axissel) case AXISSTRAFE: axisval = cv_sideaxis.value; break; + case AXISJUMP: + axisval = cv_jumpaxis.value; + break; + case AXISSPIN: + axisval = cv_spinaxis.value; + break; case AXISFIRE: axisval = cv_fireaxis.value; break; @@ -881,6 +897,12 @@ static INT32 Joy2Axis(axis_input_e axissel) case AXISSTRAFE: axisval = cv_sideaxis2.value; break; + case AXISJUMP: + axisval = cv_jumpaxis2.value; + break; + case AXISSPIN: + axisval = cv_spinaxis2.value; + break; case AXISFIRE: axisval = cv_fireaxis2.value; break; @@ -1126,7 +1148,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) cmd->buttons |= BT_CUSTOM3; // use with any button/key - if (PLAYER1INPUTDOWN(gc_use)) + axis = JoyAxis(AXISSPIN); + if (PLAYER1INPUTDOWN(gc_use) || (cv_usejoystick.value && axis > 0)) cmd->buttons |= BT_USE; // Camera Controls @@ -1148,7 +1171,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics) resetdown = false; // jump button - if (PLAYER1INPUTDOWN(gc_jump)) + axis = JoyAxis(AXISJUMP); + if (PLAYER1INPUTDOWN(gc_jump) || (cv_usejoystick.value && axis > 0)) cmd->buttons |= BT_JUMP; // player aiming shit, ahhhh... @@ -1423,7 +1447,8 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) cmd->buttons |= BT_CUSTOM3; // use with any button/key - if (PLAYER2INPUTDOWN(gc_use)) + axis = Joy2Axis(AXISSPIN); + if (PLAYER2INPUTDOWN(gc_use) || (cv_usejoystick2.value && axis > 0)) cmd->buttons |= BT_USE; // Camera Controls @@ -1445,7 +1470,8 @@ void G_BuildTiccmd2(ticcmd_t *cmd, INT32 realtics) resetdown = false; // jump button - if (PLAYER2INPUTDOWN(gc_jump)) + axis = Joy2Axis(AXISJUMP); + if (PLAYER2INPUTDOWN(gc_jump) || (cv_usejoystick2.value && axis > 0)) cmd->buttons |= BT_JUMP; // player aiming shit, ahhhh... diff --git a/src/g_game.h b/src/g_game.h index 891e7b3e..e4d155eb 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -59,8 +59,8 @@ extern consvar_t cv_invertmouse, cv_alwaysfreelook, cv_chasefreelook, cv_mousemo extern consvar_t cv_invertmouse2, cv_alwaysfreelook2, cv_chasefreelook2, cv_mousemove2; extern consvar_t cv_useranalog, cv_useranalog2; extern consvar_t cv_analog, cv_analog2; -extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_fireaxis,cv_firenaxis; -extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_fireaxis2,cv_firenaxis2; +extern consvar_t cv_sideaxis,cv_turnaxis,cv_moveaxis,cv_lookaxis,cv_jumpaxis,cv_spinaxis,cv_fireaxis,cv_firenaxis; +extern consvar_t cv_sideaxis2,cv_turnaxis2,cv_moveaxis2,cv_lookaxis2,cv_jumpaxis2,cv_spinaxis2,cv_fireaxis2,cv_firenaxis2; extern consvar_t cv_ghost_bestscore, cv_ghost_besttime, cv_ghost_bestrings, cv_ghost_last, cv_ghost_guest; // mouseaiming (looking up/down with the mouse or keyboard) diff --git a/src/m_menu.c b/src/m_menu.c index 1e1b1e69..0c549ead 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1089,25 +1089,29 @@ static menuitem_t OP_Joystick1Menu[] = {IT_STRING | IT_CVAR, NULL, "Axis For Moving" , &cv_moveaxis , 40}, {IT_STRING | IT_CVAR, NULL, "Axis For Strafe" , &cv_sideaxis , 50}, {IT_STRING | IT_CVAR, NULL, "Axis For Looking" , &cv_lookaxis , 60}, - {IT_STRING | IT_CVAR, NULL, "Axis For Firing" , &cv_fireaxis , 70}, - {IT_STRING | IT_CVAR, NULL, "Axis For NFiring" , &cv_firenaxis , 80}, + {IT_STRING | IT_CVAR, NULL, "Axis For Jumping" , &cv_jumpaxis , 70}, + {IT_STRING | IT_CVAR, NULL, "Axis For Spinning" , &cv_spinaxis , 80}, + {IT_STRING | IT_CVAR, NULL, "Axis For Firing" , &cv_fireaxis , 90}, + {IT_STRING | IT_CVAR, NULL, "Axis For NFiring" , &cv_firenaxis , 100}, - {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 100}, - {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 110}, + {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook, 120}, + {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook, 130}, }; static menuitem_t OP_Joystick2Menu[] = { - {IT_STRING | IT_CALL, NULL, "Select Joystick...", M_Setup2PJoystickMenu, 10}, - {IT_STRING | IT_CVAR, NULL, "Axis For Turning" , &cv_turnaxis2 , 30}, - {IT_STRING | IT_CVAR, NULL, "Axis For Moving" , &cv_moveaxis2 , 40}, - {IT_STRING | IT_CVAR, NULL, "Axis For Strafe" , &cv_sideaxis2 , 50}, - {IT_STRING | IT_CVAR, NULL, "Axis For Looking" , &cv_lookaxis2 , 60}, - {IT_STRING | IT_CVAR, NULL, "Axis For Firing" , &cv_fireaxis2 , 70}, - {IT_STRING | IT_CVAR, NULL, "Axis For NFiring" , &cv_firenaxis2 , 80}, + {IT_STRING | IT_CALL, NULL, "Select Joystick...", M_Setup2PJoystickMenu, 10}, + {IT_STRING | IT_CVAR, NULL, "Axis For Turning" , &cv_turnaxis2 , 30}, + {IT_STRING | IT_CVAR, NULL, "Axis For Moving" , &cv_moveaxis2 , 40}, + {IT_STRING | IT_CVAR, NULL, "Axis For Strafe" , &cv_sideaxis2 , 50}, + {IT_STRING | IT_CVAR, NULL, "Axis For Looking" , &cv_lookaxis2 , 60}, + {IT_STRING | IT_CVAR, NULL, "Axis For Jumping" , &cv_jumpaxis2 , 70}, + {IT_STRING | IT_CVAR, NULL, "Axis For Spinning" , &cv_spinaxis2 , 80}, + {IT_STRING | IT_CVAR, NULL, "Axis For Firing" , &cv_fireaxis2 , 90}, + {IT_STRING | IT_CVAR, NULL, "Axis For NFiring" , &cv_firenaxis2 , 100}, - {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2, 100}, - {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 110}, + {IT_STRING | IT_CVAR, NULL, "First-Person Vert-Look", &cv_alwaysfreelook2,120}, + {IT_STRING | IT_CVAR, NULL, "Third-Person Vert-Look", &cv_chasefreelook2, 130}, }; static menuitem_t OP_JoystickSetMenu[] = From 14e98df69b6c097e4e737a26763c660d28e8b067 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 16 Dec 2018 22:57:39 +0000 Subject: [PATCH 39/58] Revert "Merge branch 'kart-luatextures-backport' into 'next'" This reverts merge request !387 --- src/lua_baselib.c | 23 ----------------------- src/lua_maplib.c | 8 ++++---- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index a178b17f..96998776 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1682,25 +1682,6 @@ static int lib_rSetPlayerSkin(lua_State *L) return 0; } -// R_DATA -//////////// - -static int lib_rCheckTextureNumForName(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - //HUDSAFE - lua_pushinteger(L, R_CheckTextureNumForName(name)); - return 1; -} - -static int lib_rTextureNumForName(lua_State *L) -{ - const char *name = luaL_checkstring(L, 1); - //HUDSAFE - lua_pushinteger(L, R_TextureNumForName(name)); - return 1; -} - // S_SOUND //////////// @@ -2184,10 +2165,6 @@ static luaL_Reg lib[] = { {"R_Frame2Char",lib_rFrame2Char}, {"R_SetPlayerSkin",lib_rSetPlayerSkin}, - // r_data - {"R_CheckTextureNumForName",lib_rCheckTextureNumForName), - {"R_TextureNumForName",lib_rTextureNumForName), - // s_sound {"S_StartSound",lib_sStartSound}, {"S_StartSoundAtVolume",lib_sStartSoundAtVolume}, diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 5eb6cb4a..efe9e6f4 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -795,16 +795,16 @@ static int side_set(lua_State *L) side->rowoffset = luaL_checkfixed(L, 3); break; case side_toptexture: - side->toptexture = luaL_checkinteger(L, 3); + side->toptexture = luaL_checkinteger(L, 3); break; case side_bottomtexture: - side->bottomtexture = luaL_checkinteger(L, 3); + side->bottomtexture = luaL_checkinteger(L, 3); break; case side_midtexture: - side->midtexture = luaL_checkinteger(L, 3); + side->midtexture = luaL_checkinteger(L, 3); break; case side_repeatcnt: - side->repeatcnt = luaL_checkinteger(L, 3); + side->repeatcnt = luaL_checkinteger(L, 3); break; } return 0; From e763eab6cd9d835e4d6360ee731d9ee9cfc7448d Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 18:18:59 -0500 Subject: [PATCH 40/58] 2.2 camera changes backport - Very slightly less claustrophobic camera defaults - Changed camera settings are saved - Camera distance increases relatively with splitscreen & analog mode. These changes are kind of debatable because them not saving was an intentional decision initially, and the camera being farther out could potentially clip more geometry where it previously didn't... still, thought I'd open this for consideration --- src/g_game.c | 10 ---------- src/p_setup.c | 17 ++++++++++------- src/p_user.c | 30 ++++++++++++++++++++++-------- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 5cc78d4b..8dcad940 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1585,11 +1585,6 @@ static void Analog_OnChange(void) // cameras are not initialized at this point - if (leveltime > 1) - CV_SetValue(&cv_cam_dist, 128); - if (cv_analog.value || demoplayback) - CV_SetValue(&cv_cam_dist, 192); - if (!cv_chasecam.value && cv_analog.value) { CV_SetValue(&cv_analog, 0); return; @@ -1605,11 +1600,6 @@ static void Analog2_OnChange(void) // cameras are not initialized at this point - if (leveltime > 1) - CV_SetValue(&cv_cam2_dist, 128); - if (cv_analog2.value) - CV_SetValue(&cv_cam2_dist, 192); - if (!cv_chasecam2.value && cv_analog2.value) { CV_SetValue(&cv_analog2, 0); return; diff --git a/src/p_setup.c b/src/p_setup.c index 93eb7558..3601a5b0 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2689,8 +2689,9 @@ boolean P_SetupLevel(boolean skipprecip) if (!dedicated) { - if (!cv_cam_speed.changed) - CV_Set(&cv_cam_speed, cv_cam_speed.defaultvalue); + // Salt: CV_ClearChangedFlags() messes with your settings :( + /*if (!cv_cam_speed.changed) + CV_Set(&cv_cam_speed, cv_cam_speed.defaultvalue);*/ if (!cv_chasecam.changed) CV_SetValue(&cv_chasecam, chase); @@ -3025,20 +3026,22 @@ boolean P_SetupLevel(boolean skipprecip) { P_SetupCamera(); - if (!cv_cam_height.changed) + // Salt: CV_ClearChangedFlags() messes with your settings :( + /*if (!cv_cam_height.changed) CV_Set(&cv_cam_height, cv_cam_height.defaultvalue); if (!cv_cam_dist.changed) CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue); - if (!cv_cam_rotate.changed) - CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue); - if (!cv_cam2_height.changed) CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue); if (!cv_cam2_dist.changed) - CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue); + CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue);*/ + + // Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P + if (!cv_cam_rotate.changed) + CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue); if (!cv_cam2_rotate.changed) CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue); diff --git a/src/p_user.c b/src/p_user.c index 90616754..c128efca 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -7781,18 +7781,18 @@ static CV_PossibleValue_t CV_CamSpeed[] = {{0, "MIN"}, {1*FRACUNIT, "MAX"}, {0, static CV_PossibleValue_t rotation_cons_t[] = {{1, "MIN"}, {45, "MAX"}, {0, NULL}}; static CV_PossibleValue_t CV_CamRotate[] = {{-720, "MIN"}, {720, "MAX"}, {0, NULL}}; -consvar_t cv_cam_dist = {"cam_dist", "128", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam_height = {"cam_height", "20", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_dist = {"cam_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_height = {"cam_height", "25", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_still = {"cam_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam_speed = {"cam_speed", "0.25", CV_FLOAT, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_speed = {"cam_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam_rotate = {"cam_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", 0, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam2_dist = {"cam2_dist", "128", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam2_height = {"cam2_height", "20", CV_FLOAT, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam_rotspeed = {"cam_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_dist = {"cam2_dist", "160", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_height = {"cam2_height", "25", CV_FLOAT|CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_still = {"cam2_still", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam2_speed = {"cam2_speed", "0.25", CV_FLOAT, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_speed = {"cam2_speed", "0.3", CV_FLOAT|CV_SAVE, CV_CamSpeed, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_cam2_rotate = {"cam2_rotate", "0", CV_CALL|CV_NOINIT, CV_CamRotate, CV_CamRotate2_OnChange, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", 0, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_cam2_rotspeed = {"cam2_rotspeed", "10", CV_SAVE, rotation_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; fixed_t t_cam_dist = -42; fixed_t t_cam_height = -42; @@ -8048,6 +8048,20 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall { dist = camdist; + // x1.5 dist for splitscreen + if (splitscreen) + { + dist = FixedMul(dist, 3*FRACUNIT/2); + camheight = FixedMul(camheight, 3*FRACUNIT/2); + } + + // x1.2 dist for analog + if (P_AnalogMove(player)) + { + dist = FixedMul(dist, 6*FRACUNIT/5); + camheight = FixedMul(camheight, 6*FRACUNIT/5); + } + if (player->climbing || player->exiting || player->playerstate == PST_DEAD || (player->pflags & (PF_MACESPIN|PF_ITEMHANG|PF_ROPEHANG))) dist <<= 1; } From ec53e122947acdf87dbafc347362a0a30fba41de Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 18:19:53 -0500 Subject: [PATCH 41/58] Foolish --- src/lua_baselib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index a178b17f..e53ec252 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2185,8 +2185,8 @@ static luaL_Reg lib[] = { {"R_SetPlayerSkin",lib_rSetPlayerSkin}, // r_data - {"R_CheckTextureNumForName",lib_rCheckTextureNumForName), - {"R_TextureNumForName",lib_rTextureNumForName), + {"R_CheckTextureNumForName",lib_rCheckTextureNumForName}, + {"R_TextureNumForName",lib_rTextureNumForName}, // s_sound {"S_StartSound",lib_sStartSound}, From 9e596d15afff03e150249acde6506fb3fdd68aa1 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 20:09:59 -0500 Subject: [PATCH 42/58] Save override for level header Kind of like 2.2's, but with backwards-compatability with 2.1 --- src/dehacked.c | 17 +++++++++++++++++ src/doomstat.h | 6 ++++++ src/lua_maplib.c | 2 ++ src/p_setup.c | 29 +++++++++++++++++++++++++---- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index db1d6eed..4e243302 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1248,6 +1248,18 @@ static void readlevelheader(MYFILE *f, INT32 num) deh_warning("Level header %d: invalid bonus type number %d", num, i); } + else if (fastcmp(word, "SAVEOVERRIDE")) + { + if (fastcmp(word2, "DEFAULT")) i = SAVE_DEFAULT; + else if (fastcmp(word2, "ALWAYS")) i = SAVE_ALWAYS; + else if (fastcmp(word2, "NEVER")) i = SAVE_NEVER; + + if (i >= SAVE_NEVER && i <= SAVE_ALWAYS) + mapheaderinfo[num-1]->saveoverride = (SINT8)i; + else + deh_warning("Level header %d: invalid save override number %d", num, i); + } + else if (fastcmp(word, "LEVELFLAGS")) mapheaderinfo[num-1]->levelflags = (UINT8)i; else if (fastcmp(word, "MENUFLAGS")) @@ -7074,6 +7086,11 @@ struct { {"LF2_NIGHTSATTACK",LF2_NIGHTSATTACK}, {"LF2_NOVISITNEEDED",LF2_NOVISITNEEDED}, + // Save override + {"SAVE_NEVER",SAVE_NEVER}, + {"SAVE_DEFAULT",SAVE_DEFAULT}, + {"SAVE_ALWAYS",SAVE_ALWAYS}, + // NiGHTS grades {"GRADE_F",GRADE_F}, {"GRADE_E",GRADE_E}, diff --git a/src/doomstat.h b/src/doomstat.h index 7b4aa264..d37ae440 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -234,6 +234,7 @@ typedef struct SINT8 unlockrequired; ///< Is an unlockable required to play this level? -1 if no. UINT8 levelselect; ///< Is this map available in the level select? If so, which map list is it available in? SINT8 bonustype; ///< What type of bonus does this level have? (-1 for null.) + SINT8 saveoverride; ///< Set how the game is allowed to save (1 for always, -1 for never, 0 is 2.1 default) UINT8 levelflags; ///< LF_flags: merged eight booleans into one UINT8 for space, see below UINT8 menuflags; ///< LF2_flags: options that affect record attack / nights mode menus @@ -261,6 +262,11 @@ typedef struct #define LF2_NIGHTSATTACK 8 ///< Show this map in NiGHTS mode menu #define LF2_NOVISITNEEDED 16 ///< Available in time attack/nights mode without visiting the level +// Save override +#define SAVE_NEVER -1 +#define SAVE_DEFAULT 0 +#define SAVE_ALWAYS 1 + extern mapheader_t* mapheaderinfo[NUMMAPS]; enum TypeOfLevel diff --git a/src/lua_maplib.c b/src/lua_maplib.c index efe9e6f4..68323a58 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -1504,6 +1504,8 @@ static int mapheaderinfo_get(lua_State *L) lua_pushinteger(L, header->levelselect); else if (fastcmp(field,"bonustype")) lua_pushinteger(L, header->bonustype); + else if (fastcmp(field,"saveoverride")) + lua_pushinteger(L, header->saveoverride); else if (fastcmp(field,"levelflags")) lua_pushinteger(L, header->levelflags); else if (fastcmp(field,"menuflags")) diff --git a/src/p_setup.c b/src/p_setup.c index 93eb7558..4d9233a2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -219,6 +219,8 @@ static void P_ClearSingleMapHeaderInfo(INT16 i) mapheaderinfo[num]->levelselect = 0; DEH_WriteUndoline("BONUSTYPE", va("%d", mapheaderinfo[num]->bonustype), UNDO_NONE); mapheaderinfo[num]->bonustype = 0; + DEH_WriteUndoline("SAVEOVERRIDE", va("%d", mapheaderinfo[num]->saveoverride), UNDO_NONE); + mapheaderinfo[num]->saveoverride = SAVE_DEFAULT; DEH_WriteUndoline("LEVELFLAGS", va("%d", mapheaderinfo[num]->levelflags), UNDO_NONE); mapheaderinfo[num]->levelflags = 0; DEH_WriteUndoline("MENUFLAGS", va("%d", mapheaderinfo[num]->menuflags), UNDO_NONE); @@ -2626,6 +2628,28 @@ static void P_SetupCamera(void) } } +static boolean P_CanSave(void) +{ + // Saving is completely ignored under these conditions: + if ((cursaveslot < 0) // Playing without saving + || (!modifiedgame || savemoddata) // Game is modified + || (netgame || multiplayer) // Not in single-player + || (demoplayback || demorecording || metalrecording) // Currently in demo + || (players[consoleplayer].lives <= 0) // Completely dead + || (modeattacking || ultimatemode || G_IsSpecialStage(gamemap))) // Specialized instances + return false; + + if (mapheaderinfo[gamemap-1]->saveoverride == SAVE_ALWAYS) + return true; // Saving should ALWAYS happen! + else if (mapheaderinfo[gamemap-1]->saveoverride == SAVE_NEVER) + return false; // Saving should NEVER happen! + + // Default condition: In a non-hidden map, at the beginning of a zone or on a completed save-file, and not on save reload. + return (!(mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) + && (mapheaderinfo[gamemap-1]->actnum < 2 || gamecomplete) + && (gamemap != lastmapsaved)); +} + /** Loads a level from a lump or external wad. * * \param skipprecip If true, don't spawn precipitation. @@ -3103,10 +3127,7 @@ boolean P_SetupLevel(boolean skipprecip) P_RunCachedActions(); - if (!(netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || players[consoleplayer].lives <= 0) - && (!modifiedgame || savemoddata) && cursaveslot >= 0 && !ultimatemode - && !(mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU) - && (!G_IsSpecialStage(gamemap)) && gamemap != lastmapsaved && (mapheaderinfo[gamemap-1]->actnum < 2 || gamecomplete)) + if (P_CanSave()) G_SaveGame((UINT32)cursaveslot); if (savedata.lives > 0) From bef3bb23f8c90aee94eae11dec7cb00c630f4c84 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 21:36:54 -0500 Subject: [PATCH 43/58] Undo dc92bb49 --- src/lua_baselib.c | 19 +++++++++++++++++++ src/lua_maplib.c | 8 ++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index e6efb40e..e53ec252 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1682,6 +1682,25 @@ static int lib_rSetPlayerSkin(lua_State *L) return 0; } +// R_DATA +//////////// + +static int lib_rCheckTextureNumForName(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + //HUDSAFE + lua_pushinteger(L, R_CheckTextureNumForName(name)); + return 1; +} + +static int lib_rTextureNumForName(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + //HUDSAFE + lua_pushinteger(L, R_TextureNumForName(name)); + return 1; +} + // S_SOUND //////////// diff --git a/src/lua_maplib.c b/src/lua_maplib.c index efe9e6f4..5eb6cb4a 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -795,16 +795,16 @@ static int side_set(lua_State *L) side->rowoffset = luaL_checkfixed(L, 3); break; case side_toptexture: - side->toptexture = luaL_checkinteger(L, 3); + side->toptexture = luaL_checkinteger(L, 3); break; case side_bottomtexture: - side->bottomtexture = luaL_checkinteger(L, 3); + side->bottomtexture = luaL_checkinteger(L, 3); break; case side_midtexture: - side->midtexture = luaL_checkinteger(L, 3); + side->midtexture = luaL_checkinteger(L, 3); break; case side_repeatcnt: - side->repeatcnt = luaL_checkinteger(L, 3); + side->repeatcnt = luaL_checkinteger(L, 3); break; } return 0; From 03a4bd8f53f980b699e3afcf48d6063a8ba23f14 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 18 Dec 2018 12:55:05 -0500 Subject: [PATCH 44/58] Revert default changes Digiku said they'd handle the new button defaults so \m/ --- src/g_game.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 55730fa7..9f63df42 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -414,10 +414,10 @@ consvar_t cv_lookaxis = {"joyaxis_look", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL consvar_t cv_lookaxis = {"joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif #endif -consvar_t cv_jumpaxis = {"joyaxis_jump", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_spinaxis = {"joyaxis_spin", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_fireaxis = {"joyaxis_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_firenaxis = {"joyaxis_firenormal", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_jumpaxis = {"joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_spinaxis = {"joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_fireaxis = {"joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_firenaxis = {"joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif #if defined (_WII) || defined (WMINPUT) @@ -445,10 +445,10 @@ consvar_t cv_sideaxis2 = {"joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NU #ifndef _XBOX consvar_t cv_lookaxis2 = {"joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif -consvar_t cv_jumpaxis2 = {"joyaxis2_jump", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_spinaxis2 = {"joyaxis2_spin", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_fireaxis2 = {"joyaxis2_fire", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_jumpaxis2 = {"joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_spinaxis2 = {"joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; #endif From 0e34e7f32fb49d4868ebf8c0f0a05a104fbca176 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 18 Dec 2018 14:48:04 -0500 Subject: [PATCH 45/58] G_SetCustomExitVars for setting nextmapoverride & skipstats This is desparately needed for KIMOKAWAIII, since there's many instances I need to change nextlevel but still want to use the existing player exit stuff. --- src/lua_baselib.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 96998776..5298c1e3 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1923,6 +1923,38 @@ static int lib_gExitLevel(lua_State *L) return 0; } +// Another Lua function that doesn't actually exist! +// Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts. +static int lib_gSetCustomExitVars(lua_State *L) +{ + int n = lua_gettop(L); // Num arguments + NOHUD + + // LUA EXTENSION: Custom exit like support + // Supported: + // G_SetCustomExitVars(); [reset to defaults] + // G_SetCustomExitVars(int) [nextmap override only] + // G_SetCustomExitVars(bool) [skipstats only] + // G_SetCustomExitVars(int, bool) [both of the above] + if (n >= 1) + { + if (lua_isnumber(L, 1) || n >= 2) + { + nextmapoverride = (INT16)luaL_checknumber(L, 1); + lua_pop(L, 1); // pop nextmapoverride; skipstats now 1 if available + } + skipstats = lua_optboolean(L, 1); + } + else + { + nextmapoverride = 0; + skipstats = false; + } + // --- + + return 0; +} + static int lib_gIsSpecialStage(lua_State *L) { INT32 mapnum = luaL_optinteger(L, 1, gamemap); @@ -2180,6 +2212,7 @@ static luaL_Reg lib[] = { {"G_BuildMapName",lib_gBuildMapName}, {"G_DoReborn",lib_gDoReborn}, {"G_ExitLevel",lib_gExitLevel}, + {"G_SetCustomExitVars",lib_gSetCustomExitVars}, {"G_IsSpecialStage",lib_gIsSpecialStage}, {"G_GametypeUsesLives",lib_gGametypeUsesLives}, {"G_GametypeHasTeams",lib_gGametypeHasTeams}, From 42a9e66883aa209a3be78bfad0225c0ca1201477 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 18 Dec 2018 15:03:54 -0500 Subject: [PATCH 46/58] Let lib_gExitLevel call lib_gSetCustomExitVars, for reduced code duplication. --- src/lua_baselib.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 5298c1e3..40ca1963 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1897,32 +1897,6 @@ static int lib_gDoReborn(lua_State *L) return 0; } -static int lib_gExitLevel(lua_State *L) -{ - int n = lua_gettop(L); // Num arguments - NOHUD - - // LUA EXTENSION: Custom exit like support - // Supported: - // G_ExitLevel(); [no modifications] - // G_ExitLevel(int) [nextmap override only] - // G_ExitLevel(bool) [skipstats only] - // G_ExitLevel(int, bool) [both of the above] - if (n >= 1) - { - if (lua_isnumber(L, 1) || n >= 2) - { - nextmapoverride = (INT16)luaL_checknumber(L, 1); - lua_pop(L, 1); // pop nextmapoverride; skipstats now 1 if available - } - skipstats = lua_optboolean(L, 1); - } - // --- - - G_ExitLevel(); - return 0; -} - // Another Lua function that doesn't actually exist! // Sets nextmapoverride & skipstats without instantly ending the level, for instances where other sources should be exiting the level, like normal signposts. static int lib_gSetCustomExitVars(lua_State *L) @@ -1955,6 +1929,17 @@ static int lib_gSetCustomExitVars(lua_State *L) return 0; } +static int lib_gExitLevel(lua_State *L) +{ + int n = lua_gettop(L); // Num arguments + NOHUD + // Moved this bit to G_SetCustomExitVars + if (n >= 1) // Don't run the reset to defaults option + lib_gSetCustomExitVars(L); + G_ExitLevel(); + return 0; +} + static int lib_gIsSpecialStage(lua_State *L) { INT32 mapnum = luaL_optinteger(L, 1, gamemap); @@ -2211,8 +2196,8 @@ static luaL_Reg lib[] = { // g_game {"G_BuildMapName",lib_gBuildMapName}, {"G_DoReborn",lib_gDoReborn}, - {"G_ExitLevel",lib_gExitLevel}, {"G_SetCustomExitVars",lib_gSetCustomExitVars}, + {"G_ExitLevel",lib_gExitLevel}, {"G_IsSpecialStage",lib_gIsSpecialStage}, {"G_GametypeUsesLives",lib_gGametypeUsesLives}, {"G_GametypeHasTeams",lib_gGametypeHasTeams}, From 67cd6dcdd2479fcf4b58a4299cc17a57b9102304 Mon Sep 17 00:00:00 2001 From: Azeonus Date: Tue, 18 Dec 2018 16:37:01 -0500 Subject: [PATCH 47/58] dispoffset OGL fix [by Azeonus] --- src/hardware/hw_main.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index fb5e2a71..d7ab4f39 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4333,7 +4333,17 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) wallVerts[3].tow = wallVerts[2].tow = 0; wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t; } - + + // if it has a dispoffset, push it a little towards the camera + if (spr->dispoffset) { + float co = -gr_viewcos*(0.05*spr->dispoffset); + float si = -gr_viewsin*(0.05*spr->dispoffset); + wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; + wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; + wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; + wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; + } + realtop = top = wallVerts[3].y; realbot = bot = wallVerts[0].y; towtop = wallVerts[3].tow; @@ -4634,7 +4644,17 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) //////////////////// HWR_DrawSpriteShadow(spr, gpatch, this_scale); } - + + // if it has a dispoffset, push it a little towards the camera + if (spr->dispoffset) { + float co = -gr_viewcos*(0.05*spr->dispoffset); + float si = -gr_viewsin*(0.05*spr->dispoffset); + wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; + wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; + wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; + wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; + } + // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // sprite lighting by modulating the RGB components /// \todo coloured From 96cad09db674c5810a9992124aa694ccad1f1877 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Tue, 18 Dec 2018 16:59:59 -0500 Subject: [PATCH 48/58] Change 0.05 to 0.05f --- src/hardware/hw_main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d7ab4f39..db679223 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4333,17 +4333,17 @@ static void HWR_SplitSprite(gr_vissprite_t *spr) wallVerts[3].tow = wallVerts[2].tow = 0; wallVerts[0].tow = wallVerts[1].tow = gpatch->max_t; } - + // if it has a dispoffset, push it a little towards the camera if (spr->dispoffset) { - float co = -gr_viewcos*(0.05*spr->dispoffset); - float si = -gr_viewsin*(0.05*spr->dispoffset); + float co = -gr_viewcos*(0.05f*spr->dispoffset); + float si = -gr_viewsin*(0.05f*spr->dispoffset); wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; } - + realtop = top = wallVerts[3].y; realbot = bot = wallVerts[0].y; towtop = wallVerts[3].tow; @@ -4644,17 +4644,17 @@ static void HWR_DrawSprite(gr_vissprite_t *spr) //////////////////// HWR_DrawSpriteShadow(spr, gpatch, this_scale); } - + // if it has a dispoffset, push it a little towards the camera if (spr->dispoffset) { - float co = -gr_viewcos*(0.05*spr->dispoffset); - float si = -gr_viewsin*(0.05*spr->dispoffset); + float co = -gr_viewcos*(0.05f*spr->dispoffset); + float si = -gr_viewsin*(0.05f*spr->dispoffset); wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; } - + // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // sprite lighting by modulating the RGB components /// \todo coloured From 78501dcd0c5ed09d7cd65b7da2d72b39579cb3a3 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 01:11:07 -0500 Subject: [PATCH 49/58] Comment out stray PK3 blockmap message --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index 93eb7558..2e568800 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2000,7 +2000,7 @@ static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname if (!count || count >= 0x20000) return false; - CONS_Printf("Reading blockmap lump for pk3...\n"); + //CONS_Printf("Reading blockmap lump for pk3...\n"); // no need to malloc anything, assume the data is uncompressed for now count /= 2; From ed7178bca473dc7bb4110ba45e66f2cd35e4cf6c Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 17 Dec 2018 13:13:35 -0500 Subject: [PATCH 50/58] Assign joy button defaults for 1 and 2 player --- src/g_input.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/g_input.c b/src/g_input.c index 44d9f2b2..833883f2 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1165,7 +1165,9 @@ void G_Controldefault(void) gamecontrol[gc_turnleft ][0] = KEY_LEFTARROW; gamecontrol[gc_turnright ][0] = KEY_RIGHTARROW; gamecontrol[gc_weaponnext ][0] = 'e'; + gamecontrol[gc_weaponnext ][1] = KEY_JOY1+1; // B gamecontrol[gc_weaponprev ][0] = 'q'; + gamecontrol[gc_weaponprev ][1] = KEY_JOY1+2; // X gamecontrol[gc_wepslot1 ][0] = '1'; gamecontrol[gc_wepslot2 ][0] = '2'; gamecontrol[gc_wepslot3 ][0] = '3'; @@ -1180,24 +1182,45 @@ void G_Controldefault(void) gamecontrol[gc_fire ][1] = KEY_MOUSE1+0; gamecontrol[gc_firenormal ][0] = 'c'; gamecontrol[gc_tossflag ][0] = '\''; + gamecontrol[gc_tossflag ][1] = KEY_JOY1+0; // A gamecontrol[gc_use ][0] = KEY_LSHIFT; + gamecontrol[gc_use ][1] = KEY_JOY1+4; // LB gamecontrol[gc_camtoggle ][0] = 'v'; + gamecontrol[gc_camtoggle ][1] = KEY_HAT1+0; // D-Pad Up gamecontrol[gc_camleft ][0] = '['; gamecontrol[gc_camright ][0] = ']'; gamecontrol[gc_camreset ][0] = 'r'; + gamecontrol[gc_camreset ][1] = KEY_JOY1+3; // Y gamecontrol[gc_lookup ][0] = KEY_UPARROW; gamecontrol[gc_lookdown ][0] = KEY_DOWNARROW; gamecontrol[gc_centerview ][0] = KEY_END; gamecontrol[gc_talkkey ][0] = 't'; + gamecontrol[gc_talkkey ][1] = KEY_HAT1+2; // D-Pad Left gamecontrol[gc_teamkey ][0] = 'y'; gamecontrol[gc_scores ][0] = KEY_TAB; + gamecontrol[gc_scores ][1] = KEY_HAT1+3; // D-Pad Right gamecontrol[gc_jump ][0] = KEY_SPACE; + gamecontrol[gc_jump ][1] = KEY_JOY1+5; // RB gamecontrol[gc_console ][0] = KEY_CONSOLE; gamecontrol[gc_pause ][0] = 'p'; + gamecontrol[gc_pause ][1] = KEY_JOY1+6; // Back gamecontrol[gc_screenshot ][0] = KEY_F8; + gamecontrol[gc_screenshot ][1] = KEY_HAT1+1; // D-Pad Down gamecontrol[gc_recordgif ][0] = KEY_F9; gamecontrol[gc_viewpoint ][0] = KEY_F12; gamecontrol[gc_systemmenu ][0] = KEY_JOY1+7; // Start + gamecontrolbis[gc_weaponnext][0] = KEY_2JOY1+1; // B + gamecontrolbis[gc_weaponprev][0] = KEY_2JOY1+2; // X + gamecontrolbis[gc_tossflag ][0] = KEY_2JOY1+0; // A + gamecontrolbis[gc_use ][0] = KEY_2JOY1+4; // LB + gamecontrolbis[gc_camreset ][0] = KEY_2JOY1+3; // Y + gamecontrolbis[gc_jump ][0] = KEY_2JOY1+5; // RB + gamecontrolbis[gc_pause ][0] = KEY_2JOY1+6; // Back + gamecontrolbis[gc_systemmenu][0] = KEY_2JOY1+7; // Start + gamecontrolbis[gc_camtoggle ][0] = KEY_2HAT1+0; // D-Pad Up + gamecontrolbis[gc_screenshot][0] = KEY_2HAT1+1; // D-Pad Down + gamecontrolbis[gc_talkkey ][0] = KEY_2HAT1+2; // D-Pad Left + gamecontrolbis[gc_scores ][0] = KEY_2HAT1+3; // D-Pad Right #ifdef WMINPUT gamecontrol[gc_forward ][0] = KEY_JOY1+02; //UP gamecontrol[gc_backward ][0] = KEY_JOY1+03; //DOWN From 7f8d16d3cd1326a3cc621852f3c62cacee2e32ce Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 02:25:36 -0500 Subject: [PATCH 51/58] Add DEVELOP build flag to version string --- src/d_netcmd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 8abfb870..bc641726 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -3440,7 +3440,7 @@ static void Command_Version_f(void) #elif defined(__linux__) CONS_Printf("Linux "); #elif defined(MACOSX) - CONS_Printf("macOS" ); + CONS_Printf("macOS "); #elif defined(UNIXCOMMON) CONS_Printf("Unix (Common) "); #else @@ -3465,6 +3465,11 @@ static void Command_Version_f(void) CONS_Printf("\x85" "DEBUG " "\x80"); #endif + // DEVELOP build +#ifdef DEVELOP + CONS_Printf("\x87" "DEVELOP " "\x80"); +#endif + CONS_Printf("\n"); } From e2b8ff26db34bc5a4ff111605880e910fa71f6b8 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 10:56:36 -0500 Subject: [PATCH 52/58] Fix lua_pop -> lua_remove use in G_SetCustomExitVars lua --- src/lua_baselib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 1a62f392..4666394e 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1934,7 +1934,7 @@ static int lib_gSetCustomExitVars(lua_State *L) if (lua_isnumber(L, 1) || n >= 2) { nextmapoverride = (INT16)luaL_checknumber(L, 1); - lua_pop(L, 1); // pop nextmapoverride; skipstats now 1 if available + lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available } skipstats = lua_optboolean(L, 1); } From 76fe78571ef3a13a9cb966114c02869ede589205 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Thu, 20 Dec 2018 16:47:17 +0000 Subject: [PATCH 53/58] fix ffloor.toppic/bottompic to be consistent in behavior with sector.floorpic/ceilingpic --- src/lua_maplib.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lua_maplib.c b/src/lua_maplib.c index ce4a1fe9..1f2414ba 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -1090,6 +1090,7 @@ static int ffloor_get(lua_State *L) { ffloor_t *ffloor = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR)); enum ffloor_e field = luaL_checkoption(L, 2, ffloor_opt[0], ffloor_opt); + INT16 i; if (!ffloor) { @@ -1109,11 +1110,11 @@ static int ffloor_get(lua_State *L) lua_pushfixed(L, *ffloor->topheight); return 1; case ffloor_toppic: { // toppic - levelflat_t *levelflat; - INT16 i; - for (i = 0, levelflat = levelflats; i != *ffloor->toppic; i++, levelflat++) - ; - lua_pushlstring(L, levelflat->name, 8); + levelflat_t *levelflat = &levelflats[*ffloor->toppic]; + for (i = 0; i < 8; i++) + if (!levelflat->name[i]) + break; + lua_pushlstring(L, levelflat->name, i); return 1; } case ffloor_toplightlevel: @@ -1123,11 +1124,11 @@ static int ffloor_get(lua_State *L) lua_pushfixed(L, *ffloor->bottomheight); return 1; case ffloor_bottompic: { // bottompic - levelflat_t *levelflat; - INT16 i; - for (i = 0, levelflat = levelflats; i != *ffloor->bottompic; i++, levelflat++) - ; - lua_pushlstring(L, levelflat->name, 8); + levelflat_t *levelflat = &levelflats[*ffloor->bottompic]; + for (i = 0; i < 8; i++) + if (!levelflat->name[i]) + break; + lua_pushlstring(L, levelflat->name, i); return 1; } #ifdef ESLOPE From b57204fc129b4d865cd0da05163aced4c9fea988 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 16:37:49 -0500 Subject: [PATCH 54/58] Fix 2p control menu graying out --- src/m_menu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 1e1b1e69..c7b1b24f 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -6837,9 +6837,10 @@ static void M_Setup2PControlsMenu(INT32 choice) OP_MPControlsMenu[0].status = IT_GRAYEDOUT2; OP_MPControlsMenu[1].status = IT_GRAYEDOUT2; OP_MPControlsMenu[2].status = IT_GRAYEDOUT2; - // Hide the pause/console controls too + // Hide the pause/console and system menu controls too OP_MiscControlsMenu[3].status = IT_GRAYEDOUT2; - OP_MiscControlsMenu[4].status = IT_GRAYEDOUT2; + OP_MiscControlsMenu[6].status = IT_GRAYEDOUT2; + OP_MiscControlsMenu[8].status = IT_GRAYEDOUT2; OP_ControlListDef.prevMenu = &OP_P2ControlsDef; M_SetupNextMenu(&OP_ControlListDef); From fe5001a38a991c36e1205acec52093dffa525aa7 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 16:40:59 -0500 Subject: [PATCH 55/58] Dummy out 2p pause, system menu, talk, and scores buttons because grayed out in-menu --- src/g_input.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/g_input.c b/src/g_input.c index 833883f2..95664e2d 100644 --- a/src/g_input.c +++ b/src/g_input.c @@ -1215,12 +1215,12 @@ void G_Controldefault(void) gamecontrolbis[gc_use ][0] = KEY_2JOY1+4; // LB gamecontrolbis[gc_camreset ][0] = KEY_2JOY1+3; // Y gamecontrolbis[gc_jump ][0] = KEY_2JOY1+5; // RB - gamecontrolbis[gc_pause ][0] = KEY_2JOY1+6; // Back - gamecontrolbis[gc_systemmenu][0] = KEY_2JOY1+7; // Start + //gamecontrolbis[gc_pause ][0] = KEY_2JOY1+6; // Back + //gamecontrolbis[gc_systemmenu][0] = KEY_2JOY1+7; // Start gamecontrolbis[gc_camtoggle ][0] = KEY_2HAT1+0; // D-Pad Up gamecontrolbis[gc_screenshot][0] = KEY_2HAT1+1; // D-Pad Down - gamecontrolbis[gc_talkkey ][0] = KEY_2HAT1+2; // D-Pad Left - gamecontrolbis[gc_scores ][0] = KEY_2HAT1+3; // D-Pad Right + //gamecontrolbis[gc_talkkey ][0] = KEY_2HAT1+2; // D-Pad Left + //gamecontrolbis[gc_scores ][0] = KEY_2HAT1+3; // D-Pad Right #ifdef WMINPUT gamecontrol[gc_forward ][0] = KEY_JOY1+02; //UP gamecontrol[gc_backward ][0] = KEY_JOY1+03; //DOWN From 0519d8c52d298fe9d258d6174c8e2dc6176754b9 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 16:46:40 -0500 Subject: [PATCH 56/58] Update CMake paths for Windows DLLs --- src/sdl/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index a3626970..f7b7c7ba 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -278,13 +278,13 @@ if(${SDL2_FOUND}) if (${CMAKE_GENERATOR} STREQUAL "MinGW Makefiles") if(${SRB2_SYSTEM_BITS} EQUAL 64) find_library(SRB2_SDL2_DLL_${dllname} "${defaultname}" - HINTS ${CMAKE_SOURCE_DIR}/Bin/Resources/x86_64 + HINTS ${CMAKE_SOURCE_DIR}/libs/dll-binaries/x86_64 HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2/x86_64-w64-mingw32/bin HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2_mixer/x86_64-w64-mingw32/bin ) else() find_library(SRB2_SDL2_DLL_${dllname} "${defaultname}" - HINTS ${CMAKE_SOURCE_DIR}/Bin/Resources/i686 + HINTS ${CMAKE_SOURCE_DIR}/libs/dll-binaries/i686 HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2/i686-w64-mingw32/bin HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2_mixer/i686-w64-mingw32/bin ) @@ -292,13 +292,13 @@ if(${SDL2_FOUND}) else() if(${SRB2_SYSTEM_BITS} EQUAL 64) find_library(SRB2_SDL2_DLL_${dllname} "${defaultname}" - HINTS ${CMAKE_SOURCE_DIR}/Bin/Resources/x86_64 + HINTS ${CMAKE_SOURCE_DIR}/libs/dll-binaries/x86_64 HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2/lib/x64 HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2_mixer/lib/x64 ) else() find_library(SRB2_SDL2_DLL_${dllname} "${defaultname}" - HINTS ${CMAKE_SOURCE_DIR}/Bin/Resources/i686 + HINTS ${CMAKE_SOURCE_DIR}/libs/dll-binaries/i686 HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2/lib/x86 HINTS ${CMAKE_SOURCE_DIR}/libs/SDL2_mixer/lib/x86 ) From f66ee8c4cd81f39257f1bb5cfce00406133cb423 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 17:27:25 -0500 Subject: [PATCH 57/58] Add sirjuddington and CodeImp to Special Thanks credits --- src/f_finale.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/f_finale.c b/src/f_finale.c index 484a0afe..3aa400be 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1087,6 +1087,9 @@ static const char *credits[] = { "Alex \"MistaED\" Fuller", "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak "Randi Heit ()", // For their MSPaint sprite that we nicked + "Simon \"sirjuddington\" Judd", // SLADE developer + "Pascal \"CodeImp\" vd Heiden", // Doom Builder developer + "", "\1Produced By", "Sonic Team Junior", From 90832938c922df9802a2f81b585f806c79d64433 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 21 Dec 2018 11:40:35 -0500 Subject: [PATCH 58/58] Re-order Special Thanks -- groups first, then names in ABC order --- src/f_finale.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 3aa400be..fa6d6dba 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1082,13 +1082,13 @@ static const char *credits[] = { "Bill \"Tets\" Reed", "", "\1Special Thanks", - "Doom Legacy Project", "iD Software", - "Alex \"MistaED\" Fuller", + "Doom Legacy Project", "FreeDoom Project", // Used some of the mancubus and rocket launcher sprites for Brak + "Alex \"MistaED\" Fuller", + "Pascal \"CodeImp\" vd Heiden", // Doom Builder developer "Randi Heit ()", // For their MSPaint sprite that we nicked "Simon \"sirjuddington\" Judd", // SLADE developer - "Pascal \"CodeImp\" vd Heiden", // Doom Builder developer "", "\1Produced By",