From 4a712f936d133237d0892eee5785385ea3833dc3 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 7 Dec 2018 16:56:48 -0500 Subject: [PATCH 01/61] 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 e69de29bb..000000000 diff --git a/windows-installer/.gitignore b/windows-installer/.gitignore deleted file mode 100644 index 40ca37130..000000000 --- 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 cc6ff74b4..000000000 --- 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 67995f336..000000000 --- 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 559abffe4..000000000 --- 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 ed7c33391..000000000 --- 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 71aa97fc222cda717315669ec16030a78629eab7 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 8 Dec 2018 14:05:58 -0500 Subject: [PATCH 02/61] 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 3f9b09f10..083ef0054 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 f4796cd80..7fec92029 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 e1c0a7158badd86d156e620dc397bd791eddb8e4 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Sat, 8 Dec 2018 14:10:09 -0500 Subject: [PATCH 03/61] 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 7fec92029..412102790 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 ee474bab23e8bf386b14f22a6a4b4acf287cddb0 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Tue, 11 Dec 2018 18:38:35 +0000 Subject: [PATCH 04/61] 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 8811308a7..4fea15802 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 cf1296694..906167548 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 a1b1d91acb4950cb44ed4fe42c0e27e3e7df0f40 Mon Sep 17 00:00:00 2001 From: MPC Date: Tue, 11 Dec 2018 20:27:26 -0300 Subject: [PATCH 05/61] 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 cf1296694..af3f7ebf8 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 ad32af337b38eba5d58892bc4d9917ba21929cf6 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/61] 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 af3f7ebf8..ecb664ad4 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 3e70ce2565ad946fda6c6f8a399c2e70a129738e Mon Sep 17 00:00:00 2001 From: MPC Date: Wed, 12 Dec 2018 18:01:52 -0300 Subject: [PATCH 07/61] 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 6b97dd282..ee6900179 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 4e8c782a9..bd4221fb1 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 23835136a..773ff91bb 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 75523f3d2..3963fd931 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 b0a14d3b5..c72843715 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 e09b49517..9164fa7a0 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 91abc8ae9cb09eece4d3b5e20a1998368a7d6a5b Mon Sep 17 00:00:00 2001 From: MPC Date: Wed, 12 Dec 2018 18:53:13 -0300 Subject: [PATCH 08/61] 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 ee6900179..36fd69e94 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 bd4221fb1..4e8c782a9 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 773ff91bb..df422232e 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 05571230323e19b12f93eb61736a04a05fb9fdf0 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/61] 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 36fd69e94..5ee3feaf7 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 c29ce1158adf7cc3f6a1f9d4ed170f41fcfd14eb 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/61] 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 5ee3feaf7..5e73d2ec4 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 847350d664c35b489357eebb5262d7334d2fc6cf Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 12:01:07 -0500 Subject: [PATCH 11/61] 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 edc4e01d3..db1d6eed8 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 56e54a38cceeeab885b0d6a0513d97bd755e26f8 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:11:25 -0500 Subject: [PATCH 12/61] 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 47c6d2e5f..16f18749b 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 2406de3167d6ebaacc31be493f34c3cb0a4c51bc Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:17:56 -0500 Subject: [PATCH 13/61] 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 1ab5f1fe3..b6ebbb433 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 17766f313077e0d114fbc2060f3ac14aa9632901 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:23:09 -0500 Subject: [PATCH 14/61] 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 82c60e4ae..cdd63ea32 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 a396ad524054473cf1191322759295d1265b925e Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 13:32:38 -0500 Subject: [PATCH 15/61] 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 b6ebbb433..a4f53c711 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 bde0d7ac3a5a4e4d342af831016d38edf7ce2360 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 13 Dec 2018 14:59:12 -0500 Subject: [PATCH 16/61] 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 e4a5f4260..6614e0aa4 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 9372baf427d1f1157fcc265a31e21ba6758eba5b Mon Sep 17 00:00:00 2001 From: MPC Date: Fri, 14 Dec 2018 14:08:25 -0300 Subject: [PATCH 17/61] 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 2c148bc69..11bf4cb11 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 355438272..a41c6403c 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 23eff452c..2b0fbc39d 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 2ab1e83f5..53ecc82e0 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 2122cba17..1637ce905 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 8d0a84fa4..9ab671274 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 b7c925e39..67a45a76e 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 d5beaf360..af6aed03c 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 b3eba87d718f114346191077d56da9fe65d75982 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 17:14:03 +0000 Subject: [PATCH 18/61] 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 a180697d5..f9f310a6a 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 acb1e3772908f5dd9509abf38ce89c141ce2fbf1 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:00:08 +0000 Subject: [PATCH 19/61] 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 f9f310a6a..271d832a4 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 7169b8841aacf7aef22084fde63dacac26cf27e9 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:01:18 +0000 Subject: [PATCH 20/61] 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 271d832a4..c75d0b485 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 2ab24111baf2c05279062dc6873e8aafc59312ae Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:11:30 +0000 Subject: [PATCH 21/61] 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 c75d0b485..096202635 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 c787353df27b1559ef3527dce423fa09d37cdae2 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 18:14:08 +0000 Subject: [PATCH 22/61] 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 096202635..95978c48f 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 18b09c4417cb1d862d45ec2a2fde4b5966af715e Mon Sep 17 00:00:00 2001 From: MPC Date: Fri, 14 Dec 2018 15:49:32 -0300 Subject: [PATCH 23/61] 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 53ecc82e0..6e6a6d49d 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 ad87418a1e5bc0b55f2cfe7a0dd5a75cb446deb3 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 21:00:53 +0000 Subject: [PATCH 24/61] 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 95978c48f..8fec4f967 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 a0aa9bb466ee38d8fd335e45bee78b6bd5a09ded Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:19:38 -0500 Subject: [PATCH 25/61] 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 02e3dc78e..ff80d50bf 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 6588231a160f64731243c59668bb663fd160d3b1 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:21:07 -0500 Subject: [PATCH 26/61] 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 fbf75f26c..36cd16087 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 f2acd58af38fb294021466f67db77f0c8cf9a916 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 21:22:13 +0000 Subject: [PATCH 27/61] 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 8fec4f967..e0ab5b0da 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 a91e84c9ef18e4be143db70d39dcc35862ab3d2f Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:47:24 -0500 Subject: [PATCH 28/61] 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 e0ab5b0da..dc49908b9 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 c74abd05c904bbb29703e18104ad72cd7cb86182 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 14 Dec 2018 16:47:38 -0500 Subject: [PATCH 29/61] Revert "compiler SSE tweak for 32-bit" This reverts commit 6588231a160f64731243c59668bb663fd160d3b1. --- src/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 36cd16087..fbf75f26c 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 8ff705eff0463cb9652c729af96356f090cd950c Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 23:28:07 +0000 Subject: [PATCH 30/61] 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 dc49908b9..53602cc7f 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 62bd57e6333c2629210619616b69c82176d69218 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Fri, 14 Dec 2018 23:56:11 +0000 Subject: [PATCH 31/61] 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 a906758fd..dd1aaf4ea 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 261e1e623cd0c7ac4645ef1e0a3ace2c0f5e5fe9 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 14 Dec 2018 19:33:40 -0500 Subject: [PATCH 32/61] 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 cdd4c3c73..1238050b3 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 16f18749b..3183ba70b 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 a180697d5..98f10c950 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 75523f3d2..a2ebcb051 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 fb5e2a716..2c31c01e4 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 2d9f42192..773fe74a4 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 453ef69ec..abac871df 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 3f9b09f10..f43be8bc4 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 386f9d4e54f3ce209762cc37654a01b28f97b086 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 14 Dec 2018 20:42:37 -0500 Subject: [PATCH 33/61] 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 773fe74a4..b324fced9 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 facba6c04dc03885f7edaf690e6e86c80ca7cfe7 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Fri, 14 Dec 2018 21:31:00 -0500 Subject: [PATCH 34/61] 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 98f10c950..2348d71ae 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 abac871df..e0b9a8147 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 f43dc96d73881f17d9e13434183238696c00828d Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 16 Dec 2018 14:01:28 -0500 Subject: [PATCH 35/61] 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 a9dd097b3..cca7810b3 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 dde29e47c56318495887bd6dff40048ffc5b3299 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 15:58:47 -0500 Subject: [PATCH 36/61] 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 969987762..a178b17fb 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 efe9e6f4c..5eb6cb4a1 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 6b1746b67b10cb58232a833e23583d7563de20bc Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 16:05:18 -0500 Subject: [PATCH 37/61] 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 db1d6eed8..dd671fd72 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 edd3259cf4935cdc24633de8011b8f398f5f59d8 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 17:45:49 -0500 Subject: [PATCH 38/61] 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 8abfb8709..1879c0d93 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 5cc78d4b6..55730fa7d 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 891e7b3ee..e4d155eb5 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 1e1b1e696..0c549ead3 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 8a47cf93f68ecd2e6cfb621e682d4eb32ac08245 Mon Sep 17 00:00:00 2001 From: Alam Ed Arias Date: Sun, 16 Dec 2018 22:57:39 +0000 Subject: [PATCH 39/61] 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 a178b17fb..969987762 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 5eb6cb4a1..efe9e6f4c 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 fad18c421ebd2094a4067858c69c331e166cfcdb Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 18:18:59 -0500 Subject: [PATCH 40/61] 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 5cc78d4b6..8dcad940d 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 93eb75583..3601a5b04 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 906167548..c128efca1 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 672b948b92ff243cbd4a8c8c4820c1b9ba922791 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 18:19:53 -0500 Subject: [PATCH 41/61] 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 a178b17fb..e53ec2523 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 079c0ec709dc47f994f6fba5e03a5ebe4b228ef7 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 20:09:59 -0500 Subject: [PATCH 42/61] 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 db1d6eed8..4e243302a 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 7b4aa2644..d37ae440a 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 efe9e6f4c..68323a58c 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 93eb75583..4d9233a24 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 4d8fe70aa756094fce54261db1a54921d84ba147 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Sun, 16 Dec 2018 21:36:54 -0500 Subject: [PATCH 43/61] Undo 53dfb4c8 --- 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 e6efb40e4..e53ec2523 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 efe9e6f4c..5eb6cb4a1 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 4ad9801b21ce3d1450060ea29ec300ed4df52fe3 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 18 Dec 2018 12:55:05 -0500 Subject: [PATCH 44/61] 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 55730fa7d..9f63df424 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 3cecf00c83a0236440570b38cc276de1d05aac21 Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 18 Dec 2018 14:48:04 -0500 Subject: [PATCH 45/61] 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 969987762..5298c1e34 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 b5d86d7263409f648cdaf0d929adb4be471bd82d Mon Sep 17 00:00:00 2001 From: TehRealSalt Date: Tue, 18 Dec 2018 15:03:54 -0500 Subject: [PATCH 46/61] 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 5298c1e34..40ca19637 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 ae590779f9ba070e181facd9caf766be8e34d66f Mon Sep 17 00:00:00 2001 From: Azeonus Date: Tue, 18 Dec 2018 16:37:01 -0500 Subject: [PATCH 47/61] 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 fb5e2a716..d7ab4f39e 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 7c5e508f4090aa1ad520f25b11c78196ce196940 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Tue, 18 Dec 2018 16:59:59 -0500 Subject: [PATCH 48/61] 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 d7ab4f39e..db679223d 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 8fb14536338e817682b529dcd262ae9ba6ed2a5d Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 01:11:07 -0500 Subject: [PATCH 49/61] 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 93eb75583..2e5688003 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 119b7cb469a2e7af3883deb802581aa92d1605b3 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Mon, 17 Dec 2018 13:13:35 -0500 Subject: [PATCH 50/61] 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 44d9f2b28..833883f28 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 861805ca0f34fa49fe7e0c0cf6b62385ffdc773b Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 02:25:36 -0500 Subject: [PATCH 51/61] 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 8abfb8709..bc6417268 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 8a6031ba01d80d0b35dac126cd898e4c8be2166f Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 02:35:27 -0500 Subject: [PATCH 52/61] Update code versions to 2.1.22 --- CMakeLists.txt | 2 +- appveyor.yml | 2 +- debian/changelog | 4 ++-- debian/control | 4 ++-- src/doomdef.h | 8 ++++---- src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj | 4 ++-- src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec96b7030..f2c43d02c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0) project(SRB2 - VERSION 2.1.21 + VERSION 2.1.22 LANGUAGES C) if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR}) diff --git a/appveyor.yml b/appveyor.yml index 061613c4d..501aee5b0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.1.21.{branch}-{build} +version: 2.1.22.{branch}-{build} os: MinGW environment: diff --git a/debian/changelog b/debian/changelog index 855c1c1b3..49f4c8b6b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ -srb2 (2.1.21~9) trusty; urgency=high +srb2 (2.1.22~9) trusty; urgency=high - * SRB2 v2.1.21 release + * SRB2 v2.1.22 release -- Marco Zafra Mon, 27 Nov 2018 16:45:00 -0500 diff --git a/debian/control b/debian/control index ce3b33fbd..64b96d6b9 100644 --- a/debian/control +++ b/debian/control @@ -18,7 +18,7 @@ Homepage: http://www.srb2.org Package: srb2 Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (>= 2.1.15), srb2-data (<= 2.1.21) +Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (>= 2.1.15), srb2-data (<= 2.1.22) Description: A cross-platform 3D Sonic fangame Sonic Robo Blast 2 is a 3D open-source Sonic the Hedgehog fangame built using a modified version of the Doom Legacy @@ -31,7 +31,7 @@ Description: A cross-platform 3D Sonic fangame Package: srb2-dbg Architecture: any # FIXME: should be Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (= 2.1.14), srb2 but dh_shlibdeps is being an asshat -Depends: libc6, ${misc:Depends}, srb2-data (>= 2.1.15), srb2-data (<= 2.1.21), srb2 +Depends: libc6, ${misc:Depends}, srb2-data (>= 2.1.15), srb2-data (<= 2.1.22), srb2 Description: A cross-platform 3D Sonic fangame Sonic Robo Blast 2 is a 3D open-source Sonic the Hedgehog fangame built using a modified version of the Doom Legacy diff --git a/src/doomdef.h b/src/doomdef.h index 796221c91..a65d7d484 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -150,9 +150,9 @@ extern FILE *logstream; // we use comprevision and compbranch instead. #else #define VERSION 201 // Game version -#define SUBVERSION 21 // more precise version number -#define VERSIONSTRING "v2.1.21" -#define VERSIONSTRINGW L"v2.1.21" +#define SUBVERSION 22 // more precise version number +#define VERSIONSTRING "v2.1.22" +#define VERSIONSTRINGW L"v2.1.22" // Hey! If you change this, add 1 to the MODVERSION below! // Otherwise we can't force updates! #endif @@ -214,7 +214,7 @@ extern FILE *logstream; // it's only for detection of the version the player is using so the MS can alert them of an update. // Only set it higher, not lower, obviously. // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". -#define MODVERSION 26 +#define MODVERSION 27 // ========================================================================= diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj index 6eabee56b..6242e0a05 100644 --- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.21; + CURRENT_PROJECT_VERSION = 2.1.22; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.21; + CURRENT_PROJECT_VERSION = 2.1.22; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj index 93f63309c..081d04603 100644 --- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj +++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj @@ -1214,7 +1214,7 @@ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.21; + CURRENT_PROJECT_VERSION = 2.1.22; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", NORMALSRB2, @@ -1226,7 +1226,7 @@ C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CURRENT_PROJECT_VERSION = 2.1.21; + CURRENT_PROJECT_VERSION = 2.1.22; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( From e6954eae3002646654fabffef16ed370d9fbfcb0 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 10:56:36 -0500 Subject: [PATCH 53/61] 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 1a62f3922..4666394ed 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 f7698de3ea5fd07aa73bc4a0ba967a489f1d6bb2 Mon Sep 17 00:00:00 2001 From: Monster Iestyn Date: Thu, 20 Dec 2018 16:47:17 +0000 Subject: [PATCH 54/61] 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 ce4a1fe97..1f2414ba5 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 8207f126f422b1398aa87e32dc14cce2b5c879b1 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 16:37:49 -0500 Subject: [PATCH 55/61] 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 1e1b1e696..c7b1b24f3 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 e54086038f82cc3725c171e852319f850182769b Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 16:40:59 -0500 Subject: [PATCH 56/61] 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 833883f28..95664e2d1 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 fb3fbf64bde8848e14379018a7153aaab8207c69 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 16:46:40 -0500 Subject: [PATCH 57/61] 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 a3626970e..f7b7c7ba4 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 495ea70a74707aa926f31c510a8054f0c770a982 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 17:16:04 -0500 Subject: [PATCH 58/61] Hardcode define MAJOREXECVERSION to MODVERSION --- src/doomdef.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doomdef.h b/src/doomdef.h index 2b5c1ce3a..02b156d60 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -216,13 +216,13 @@ extern FILE *logstream; // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1". #define MODVERSION 27 -// To version config.cfg, set MAJOREXECVERSION equal to MODVERSION -// and increment SUBEXECVERSION whenever a config change is needed +// To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. +// Increment SUBEXECVERSION whenever a config change is needed // that does not correspond to an increment in MODVERSION. // If MAJOREXECVERSION increases, set MINOREXECVERSION to 0. -#define MAJOREXECVERSION 27 +#define MAJOREXECVERSION MODVERSION #define MINOREXECVERSION 0 -// (It would have been nice to use VERSION and SUBVERSION but those are different for DEVELOP builds) +// (It would have been nice to use VERSION and SUBVERSION but those are zero'd out for DEVELOP builds) // Macros #define GETMAJOREXECVERSION(v) (v & 0xFFFF) From a4ddad6824352857c3a7cdcaa1911afc181775ea Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 17:27:25 -0500 Subject: [PATCH 59/61] 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 484a0afe6..3aa400be2 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 4e055bd383aeac3fa02672f19398582ecbd85034 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Thu, 20 Dec 2018 17:56:51 -0500 Subject: [PATCH 60/61] Properly restrict EXECVERSION from cvar updates --- src/command.c | 15 ++++++++++++++- src/command.h | 1 + src/doomdef.h | 6 +++--- src/m_misc.c | 8 ++++---- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/command.c b/src/command.c index 3bd80e1ee..c7ce2bd3c 100644 --- a/src/command.c +++ b/src/command.c @@ -49,6 +49,7 @@ static void COM_Wait_f(void); static void COM_Help_f(void); static void COM_Toggle_f(void); +static void CV_EnforceExecVersion(void); static boolean CV_FilterVarByVersion(consvar_t *v, const char *valstr); static boolean CV_Command(void); static consvar_t *CV_FindVar(const char *name); @@ -66,7 +67,8 @@ CV_PossibleValue_t CV_Natural[] = {{1, "MIN"}, {999999999, "MAX"}, {0, NULL}}; // Filter consvars by EXECVERSION // First implementation is 26 (2.1.21), so earlier configs default at 25 (2.1.20) // Also set CV_HIDEN during runtime, after config is loaded -consvar_t cv_execversion = {"execversion","25",0,CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; +static boolean execversion_enabled = false; +consvar_t cv_execversion = {"execversion","25",CV_CALL,CV_Unsigned, CV_EnforceExecVersion, 0, NULL, NULL, 0, 0, NULL}; // for default joyaxis detection static boolean joyaxis_default = false; @@ -1586,6 +1588,17 @@ void CV_InitFilterVar(void) joyaxis_count = joyaxis2_count = 0; } +void CV_ToggleExecVersion(boolean enable) +{ + execversion_enabled = enable; +} + +static void CV_EnforceExecVersion(void) +{ + if (!execversion_enabled) + CV_StealthSetValue(&cv_execversion, EXECVERSION); +} + static boolean CV_FilterJoyAxisVars(consvar_t *v, const char *valstr) { // If ALL axis settings are previous defaults, set them to the new defaults diff --git a/src/command.h b/src/command.h index 8dee1174c..e6767825c 100644 --- a/src/command.h +++ b/src/command.h @@ -130,6 +130,7 @@ extern CV_PossibleValue_t CV_Natural[]; extern consvar_t cv_execversion; void CV_InitFilterVar(void); +void CV_ToggleExecVersion(boolean enable); // register a variable for use at the console void CV_RegisterVar(consvar_t *variable); diff --git a/src/doomdef.h b/src/doomdef.h index 02b156d60..1cbe97f2a 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -217,9 +217,9 @@ extern FILE *logstream; #define MODVERSION 27 // To version config.cfg, MAJOREXECVERSION is set equal to MODVERSION automatically. -// Increment SUBEXECVERSION whenever a config change is needed -// that does not correspond to an increment in MODVERSION. -// If MAJOREXECVERSION increases, set MINOREXECVERSION to 0. +// Increment MINOREXECVERSION whenever a config change is needed that does not correspond +// to an increment in MODVERSION. This might never happen in practice. +// If MODVERSION increases, set MINOREXECVERSION to 0. #define MAJOREXECVERSION MODVERSION #define MINOREXECVERSION 0 // (It would have been nice to use VERSION and SUBVERSION but those are zero'd out for DEVELOP builds) diff --git a/src/m_misc.c b/src/m_misc.c index 1b92a8c4f..1ef74dc7b 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -443,7 +443,7 @@ void Command_LoadConfig_f(void) FIL_ForceExtension(configfile, ".cfg"); // temporarily reset execversion to default - cv_execversion.flags = 0; + CV_ToggleExecVersion(true); COM_BufInsertText(va("%s \"%s\"\n", cv_execversion.name, cv_execversion.defaultvalue)); CV_InitFilterVar(); @@ -452,7 +452,7 @@ void Command_LoadConfig_f(void) // don't filter anymore vars and don't let this convsvar be changed COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, EXECVERSION)); - cv_execversion.flags = CV_HIDEN; + CV_ToggleExecVersion(false); } /** Saves the current configuration and loads another. @@ -494,7 +494,7 @@ void M_FirstLoadConfig(void) // temporarily reset execversion to default // we shouldn't need to do this, but JUST in case... - cv_execversion.flags = 0; + CV_ToggleExecVersion(true); COM_BufInsertText(va("%s \"%s\"\n", cv_execversion.name, cv_execversion.defaultvalue)); CV_InitFilterVar(); @@ -504,7 +504,7 @@ void M_FirstLoadConfig(void) // don't filter anymore vars and don't let this convsvar be changed COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, EXECVERSION)); - cv_execversion.flags = CV_HIDEN; + CV_ToggleExecVersion(false); // make sure I_Quit() will write back the correct config // (do not write back the config if it crash before) From 8e40bdb59d5aef16c949aae117974e53102a2077 Mon Sep 17 00:00:00 2001 From: mazmazz Date: Fri, 21 Dec 2018 11:40:35 -0500 Subject: [PATCH 61/61] 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 3aa400be2..fa6d6dbad 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",