diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index efaa8612c..a8e67a7f2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -29,6 +29,7 @@ jobs: with: packages: | b2sdk + PyNaCl - name: Prepare build run: .\ci\win-buildgen.ps1 - name: Turn on problem matcher @@ -37,6 +38,32 @@ jobs: run: cmake --build .\build\ --config RelWithDebInfo --parallel - name: Prepare artifact run: .\ci\win-artifact.ps1 + - name: Stage artifacts for testing + run: .\ci\win-prepare-demotest.ps1 + - name: Download OdaTests and Testing Resources + run: .\ci\win-get-demotester.ps1 + env: + DEMOTESTER_URL: ${{ vars.DEMOTESTER_DOWNLOAD_URL }} + DEMORESOURCES_URL: ${{ vars.DEMORESOURCES_DOWNLOAD_URL }} + continue-on-error: true + - name: Decrypt IWADs + run: | + python .\secret.py decrypt plutonia + python .\secret.py decrypt tnt + python .\secret.py decrypt doom + python .\secret.py decrypt doom1 + python .\secret.py decrypt doom2 + python .\secret.py decrypt hacx + env: + SECRET_KEY: ${{ secrets.DEMOTESTER_IWAD_KEY }} + working-directory: .\build\demotester + continue-on-error: true + - name: Run OdaTests + run: python .\odatestcases.py + env: + ODAMEX_BIN: ..\demotest\odamex.exe + working-directory: .\build\demotester + continue-on-error: true - name: Upload artifact to B2 run: python .\ci\upload-b2.py .\build\archive Win-x64 env: diff --git a/CMakeLists.txt b/CMakeLists.txt index ac0c606d5..94ba20658 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,11 @@ include(GNUInstallDirs OPTIONAL) add_definitions(-DINSTALL_BINDIR="${CMAKE_INSTALL_BINDIR}") add_definitions(-DINSTALL_DATADIR="${CMAKE_INSTALL_DATADIR}") +# Set up FHS installation path +if(NOT APPLE AND NOT WIN32) + add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") +endif() + if(WIN32) set(USE_INTERNAL_LIBS 1) else() @@ -49,7 +54,7 @@ cmake_dependent_option( ENABLE_PORTMIDI "Enable portmidi support" 1 BUILD_CLIENT cmake_dependent_option( USE_MINIUPNP "Build with UPnP support" 1 BUILD_SERVER 0 ) cmake_dependent_option( USE_INTERNAL_MINIUPNP "Use internal MiniUPnP" 1 USE_MINIUPNP 0 ) -set(PROJECT_COPYRIGHT "2006-2022") +set(PROJECT_COPYRIGHT "2006-2023") set(PROJECT_RC_VERSION "11,0,0,0") set(PROJECT_COMPANY "The Odamex Team") diff --git a/README.md b/README.md index 5fcaecfad..915689568 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,23 @@ Before submitting a pull request, please make sure it follows [our coding standa [3]: https://odamex.net/wiki/Coding_standard +**Note**: This project contains a demo testing utility that ensures vanilla compatibility by +running a specific set of demos after each commit. When forking this project to prepare a pull request, +this functionality will be unavailable by default to protect sensitive files. +You can restore this functionality by: + +1. Forking [OdaTest-Resources](https://github.com/odamex/odatests-resources) to get the PWADs. +2. Downloading [OdaTests](https://github.com/odamex/odatests) to get the encryption module. +3. Replacing the encrypted IWADs with your own set of encrypted IWADs. +Encrypt using `python .\secret.py encrypt doom2` with the environment variable +`SECRET_KEY` defined to encrypt the IWADs with. The following IWADs (latest version) are needed to run all tests: +`doom, doom1, doom2, tnt, plutonia, hacx` +4. Create a release for your forked OdaTest-Resources repo. +5. Enter the following Secrets / Repository Variables in GitHub: + - `secrets.DEMOTESTER_IWAD_KEY` - Encryption key for the IWADs + - `vars.DEMOTESTER_DOWNLOAD_URL` - Full URL to download the latest OdaTests release. + - `vars.DEMORESOURCES_DOWNLOAD_URL` - Full URL to download your personal demo resources + External Links -------------- diff --git a/ag-odalaunch/res/Info.plist b/ag-odalaunch/res/Info.plist index 1900c3f22..837a26fcc 100644 --- a/ag-odalaunch/res/Info.plist +++ b/ag-odalaunch/res/Info.plist @@ -23,11 +23,11 @@ CFBundleShortVersionString 11.0.0 CFBundleGetInfoString - Copyright © 2006-2022 The Odamex Team + Copyright © 2006-2023 The Odamex Team CFBundleLongVersionString 11.0.0 NSHumanReadableCopyright - Copyright © 2006-2022 The Odamex Team + Copyright © 2006-2023 The Odamex Team LSRequiresCarbon diff --git a/ci/win-get-demotester.ps1 b/ci/win-get-demotester.ps1 new file mode 100644 index 000000000..ed21c6e9d --- /dev/null +++ b/ci/win-get-demotester.ps1 @@ -0,0 +1,25 @@ +Set-PSDebug -Trace 1 + +if (!([String]::IsNullOrWhiteSpace($env:DEMOTESTER_URL)) -and !([String]::IsNullOrWhiteSpace($env:DEMORESOURCES_URL))) +{ + Write-Output "OdaTests Download URL: $env:DEMOTESTER_URL" + Write-Output "OdaTests WAD Resources Download URL: $env:DEMORESOURCES_URL" + + $DemoTesterPath = $env:DEMOTESTER_URL + $DemoResourcePath = $env:DEMORESOURCES_URL + + Set-Location "build" + New-Item -Name "demotester" -ItemType "directory" | Out-Null + + Invoke-WebRequest -Uri $DemoTesterPath -OutFile .\odatests.zip + Invoke-WebRequest -Uri $DemoResourcePath -OutFile .\odatests-resources.zip + + 7z.exe x odatests.zip -odemotester -y + 7z.exe x odatests-resources.zip -odemotester -y + + Set-Location .. +} +else +{ + Write-Output "OdaTests URL or OdaTests Resources URL missing, skipping..." +} diff --git a/ci/win-prepare-demotest.ps1 b/ci/win-prepare-demotest.ps1 new file mode 100644 index 000000000..a1f6d6c78 --- /dev/null +++ b/ci/win-prepare-demotest.ps1 @@ -0,0 +1,22 @@ +Set-PSDebug -Trace 1 + +Set-Location "build" +New-Item -Name "demotest" -ItemType "directory" | Out-Null + +# Copy all built files into artifact directory +Copy-Item -Path ` + ".\client\RelWithDebInfo\odamex.exe", ` + ".\client\RelWithDebInfo\odamex.pdb", ` + ".\client\RelWithDebInfo\*.dll", ` + ".\server\RelWithDebInfo\odasrv.exe", ` + ".\server\RelWithDebInfo\odasrv.pdb", ` + ".\odalaunch\RelWithDebInfo\odalaunch.exe", ` + ".\odalaunch\RelWithDebInfo\odalaunch.pdb", ` + ".\odalaunch\RelWithDebInfo\*.dll", ` + ".\wad\odamex.wad", ` + "C:\Windows\System32\msvcp140.dll", ` + "C:\Windows\System32\vcruntime140.dll", ` + "C:\Windows\System32\vcruntime140_1.dll" ` + -Destination "demotest" + +Set-Location .. diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 3644285f0..4e3c5903a 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -128,11 +128,6 @@ if(APPLE) ${AUDIOUNIT_LIBRARY}) endif() -# Set up FHS installation path -if(NOT APPLE AND NOT WIN32) - add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") -endif() - # Client target if(TARGET SDL2::SDL2 OR TARGET SDL::SDL) @@ -168,14 +163,17 @@ if(TARGET SDL2::SDL2 OR TARGET SDL::SDL) message(STATUS "Default SIMD flags not touched for AMD64") elseif(ODAMEX_TARGET_ARCH STREQUAL "i386") if(NOT MSVC) - # Pentium M has SSE2. - target_compile_definitions(odamex PRIVATE -march=pentium-m) + target_compile_options(odamex PRIVATE -msse2) else() - target_compile_definitions(odamex PRIVATE /arch:SSE2) + target_compile_options(odamex PRIVATE /arch:SSE2) endif() message(STATUS "Default SIMD flags set to SSE2") elseif(ODAMEX_TARGET_ARCH MATCHES "ppc") - target_compile_definitions(odamex PRIVATE -faltivec) + if(APPLE) + target_compile_options(odamex PRIVATE -faltivec) + else() + target_compile_options(odamex PRIVATE -maltivec) + endif() message(STATUS "Default SIMD flags set to AltiVec") endif() else() diff --git a/client/gui/gui_boot.cpp b/client/gui/gui_boot.cpp index 35cd3d8c9..a50bc0857 100644 --- a/client/gui/gui_boot.cpp +++ b/client/gui/gui_boot.cpp @@ -98,7 +98,7 @@ static void EraseSelected(scannedPWADPtrs_t& mut, scannedPWAD_t* pwad) const scannedIWAD_t* g_SelectedIWAD; scannedWADs_t g_SelectedWADs; -const int WINDOW_WIDTH = 320; +const int WINDOW_WIDTH = 425; const int WINDOW_HEIGHT = 240; class BootWindow : public Fl_Window @@ -112,13 +112,20 @@ class BootWindow : public Fl_Window Fl_Hold_Browser* m_IWADBrowser; Fl_Check_Browser* m_PWADSelectBrowser; Fl_Hold_Browser* m_PWADOrderBrowser; + Fl_Check_Browser* m_gameOptionsBrowser; StringTokens m_WADDirs; Fl_Hold_Browser* m_WADDirList; + // display strings for options tab and their corresponding command line arguments + std::vector > OPTIONS_LIST; public: BootWindow(int X, int Y, int W, int H, const char* L) : Fl_Window(X, Y, W, H, L), m_IWADs() { + OPTIONS_LIST.push_back(std::make_pair("No Monsters", "-nomonsters")); + OPTIONS_LIST.push_back(std::make_pair("Fast Monsters", "-fast")); + OPTIONS_LIST.push_back(std::make_pair("Respawn Monsters", "-respawn")); + OPTIONS_LIST.push_back(std::make_pair("Pistol Start", "-pistolstart")); { Fl_Tabs* tabs = new Fl_Tabs(0, 0, 425, 200); { @@ -132,6 +139,8 @@ class BootWindow : public Fl_Window } // Fl_Box* logo { m_IWADBrowser = new Fl_Hold_Browser(135, 35, 280, 155); + m_IWADBrowser->callback(BootWindow::doPlayCB, static_cast(this)); + m_IWADBrowser->when(FL_WHEN_ENTER_KEY); } // Fl_Browser* m_IWADBrowser m_tabIWAD->end(); } // Fl_Group* tabIWAD @@ -165,6 +174,26 @@ class BootWindow : public Fl_Window } // Fl_Button* doWADRemove m_tabPWADs->end(); } // Fl_Group* tabPWADs + { + Fl_Group* tabGameOptions = + new Fl_Group(0, 25, 425, 175, "Game Options"); + { + Fl_Box* o = new Fl_Box( + 10, 35, 405, 20, + "Set gameplay options to modify your experience."); + o->align(Fl_Align(132 | FL_ALIGN_INSIDE)); + } // Fl_Box* o + { + m_gameOptionsBrowser = new Fl_Check_Browser(10, 65, 405, 125); + for (std::vector >::const_iterator it = OPTIONS_LIST.begin(); + it != OPTIONS_LIST.end(); ++it) + { + m_gameOptionsBrowser->add((*it).first.c_str()); + } + } + tabGameOptions->end(); + + } // Fl_Group* tabGameOptions { Fl_Group* tabWADDirs = new Fl_Group(0, 25, 425, 175, "Resource Locations"); @@ -272,6 +301,7 @@ class BootWindow : public Fl_Window } boot->selectedWADs(); + boot->setOptions(); Fl::delete_widget(boot); } @@ -497,6 +527,14 @@ class BootWindow : public Fl_Window } } + void setOptions() + { + for (int i = 1; i <= m_gameOptionsBrowser->nitems(); i++) { + if (m_gameOptionsBrowser->checked(i)) + g_SelectedWADs.options.push_back(OPTIONS_LIST[i - 1].second); + } + } + /** * @brief Update the WAD dir browser widget from the vector. */ @@ -527,7 +565,7 @@ class BootWindow : public Fl_Window */ static BootWindow* MakeBootWindow() { - return new BootWindow(0, 0, 425, 240, "Odamex " DOTVERSIONSTR); + return new BootWindow(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, "Odamex " DOTVERSIONSTR); } /** diff --git a/client/gui/gui_boot.h b/client/gui/gui_boot.h index e70fede4e..0b39c2b3d 100644 --- a/client/gui/gui_boot.h +++ b/client/gui/gui_boot.h @@ -27,6 +27,7 @@ struct scannedWADs_t { std::string iwad; StringTokens pwads; + StringTokens options; }; scannedWADs_t GUI_BootWindow(); diff --git a/client/sdl/i_input_sdl20.cpp b/client/sdl/i_input_sdl20.cpp index e7283b165..d26d123d1 100644 --- a/client/sdl/i_input_sdl20.cpp +++ b/client/sdl/i_input_sdl20.cpp @@ -726,23 +726,56 @@ void ISDL20JoystickInputDevice::gatherEvents() } else { - float deadzone = (joy_deadzone * 32767); event_t motion_event(ev_joystick); motion_event.type = ev_joystick; motion_event.data2 = sdl_ev.caxis.axis; - if ((sdl_ev.caxis.value >= deadzone) || - (sdl_ev.caxis.value <= -deadzone)){ - motion_event.data3 = sdl_ev.caxis.value; - } - + motion_event.data3 = calcAxisValue(sdl_ev.caxis.value); mEvents.push(motion_event); } } } } + + // Flush all remaining joystick and game controller events. + SDL_FlushEvents(SDL_JOYAXISMOTION, SDL_CONTROLLERDEVICEREMAPPED); } +int ISDL20JoystickInputDevice::calcAxisValue(int raw_value) +{ + float value; + + // Normalize. + if (raw_value > 0) + { + value = (float)raw_value / (float)SDL_JOYSTICK_AXIS_MAX; + } + else if (raw_value < 0) + { + value = (float)raw_value / (float)abs(SDL_JOYSTICK_AXIS_MIN); + } + else + { + value = 0.0f; + } + + // Apply deadzone. + if (value > joy_deadzone) + { + value = (value - joy_deadzone) / (1.0f - joy_deadzone); + } + else if (value < -joy_deadzone) + { + value = (value + joy_deadzone) / (1.0f - joy_deadzone); + } + else + { + value = 0.0f; + } + + // Scale value to the range used for calculations in G_BuildTiccmd(). + return lroundf(value * 32767.0f); +} // // ISDL20JoystickInputDevice::getEvent @@ -788,6 +821,14 @@ ISDL20InputSubsystem::ISDL20InputSubsystem() : SDL_EventState(SDL_CONTROLLERBUTTONDOWN, SDL_IGNORE); SDL_EventState(SDL_CONTROLLERBUTTONUP, SDL_IGNORE); + // Ignore unsupported game controller events. +#if (SDL_MINOR_VERSION > 0 || SDL_PATCHLEVEL >= 14) + SDL_EventState(SDL_CONTROLLERTOUCHPADDOWN, SDL_IGNORE); + SDL_EventState(SDL_CONTROLLERTOUCHPADMOTION, SDL_IGNORE); + SDL_EventState(SDL_CONTROLLERTOUCHPADUP, SDL_IGNORE); + SDL_EventState(SDL_CONTROLLERSENSORUPDATE, SDL_IGNORE); +#endif + grabInput(); } diff --git a/client/sdl/i_input_sdl20.h b/client/sdl/i_input_sdl20.h index b3cdcf855..0d3d9012a 100644 --- a/client/sdl/i_input_sdl20.h +++ b/client/sdl/i_input_sdl20.h @@ -139,6 +139,8 @@ class ISDL20JoystickInputDevice : public IInputDevice virtual void flushEvents(); private: + int calcAxisValue(int raw_value); + static const int JOY_DEADZONE = 6000; bool mActive; diff --git a/client/sdl/i_musicsystem_au.cpp b/client/sdl/i_musicsystem_au.cpp index 9192939c2..3d84bb2f9 100644 --- a/client/sdl/i_musicsystem_au.cpp +++ b/client/sdl/i_musicsystem_au.cpp @@ -180,9 +180,12 @@ void AuMusicSystem::startSong(byte* data, size_t length, bool loop) return; } + MusicTimeStamp maxtime = 0; for (UInt32 i = 0; i < outNumberOfTracks; i++) { MusicTrack track; + MusicTimeStamp time; + UInt32 size = sizeof(time); if (MusicSequenceGetIndTrack(m_sequence, i, &track) != noErr) { @@ -190,31 +193,39 @@ void AuMusicSystem::startSong(byte* data, size_t length, bool loop) return; } - struct s_loopinfo - { - MusicTimeStamp time; - long loops; - } LoopInfo; - - UInt32 inLength = sizeof(LoopInfo); - - if (MusicTrackGetProperty(track, kSequenceTrackProperty_LoopInfo, &LoopInfo, - &inLength) != noErr) + if (MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &time, + &size) != noErr) { Printf(PRINT_HIGH, "I_PlaySong: MusicTrackGetProperty failed\n"); return; } - inLength = sizeof(LoopInfo.time); + if (time > maxtime) + { + maxtime = time; + } + } + + for (UInt32 i = 0; i < outNumberOfTracks; i++) + { + MusicTrack track; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 + typedef struct + { + MusicTimeStamp loopDuration; + SInt32 numberOfLoops; + } MusicTrackLoopInfo; +#endif + MusicTrackLoopInfo LoopInfo; - if (MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, - &LoopInfo.time, &inLength) != noErr) + if (MusicSequenceGetIndTrack(m_sequence, i, &track) != noErr) { - Printf(PRINT_HIGH, "I_PlaySong: MusicTrackGetProperty failed\n"); + Printf(PRINT_HIGH, "I_PlaySong: MusicSequenceGetIndTrack failed\n"); return; } - LoopInfo.loops = loop ? 0 : 1; + LoopInfo.loopDuration = maxtime; + LoopInfo.numberOfLoops = (loop ? 0 : 1); if (MusicTrackSetProperty(track, kSequenceTrackProperty_LoopInfo, &LoopInfo, sizeof(LoopInfo)) != noErr) diff --git a/client/src/cl_cvarlist.cpp b/client/src/cl_cvarlist.cpp index d7013c302..8ba00d710 100644 --- a/client/src/cl_cvarlist.cpp +++ b/client/src/cl_cvarlist.cpp @@ -309,7 +309,7 @@ CVAR (joy_fastsensitivity, "15.0", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR CVAR (joy_freelook, "0", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE) CVAR (joy_invert, "0", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE) -CVAR_RANGE (joy_deadzone, "0.34", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.0f, 1.0f) +CVAR_RANGE (joy_deadzone, "0.20", "", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.0f, 0.75f) CVAR_RANGE(joy_lefttrigger_deadzone, "0.2", "Sets the required pressure to trigger a press on the left trigger (Analog controllers only)", CVARTYPE_FLOAT, CVAR_CLIENTARCHIVE | CVAR_NOENABLEDISABLE, 0.01f, 1.0f) diff --git a/client/src/cl_parse.cpp b/client/src/cl_parse.cpp index cdadbbdf2..e15c45edc 100644 --- a/client/src/cl_parse.cpp +++ b/client/src/cl_parse.cpp @@ -2354,7 +2354,7 @@ static void CL_SectorProperties(const odaproto::svc::SectorProperties* msg) break; } case SPC_Gravity: - *(int*)§or->gravity = msg->sector().gravity(); + *§or->gravity = msg->sector().gravity(); break; case SPC_Panning: sector->ceiling_xoffs = msg->sector().ceiling_offs().x(); diff --git a/client/src/d_main.cpp b/client/src/d_main.cpp index d6d966b35..309553abf 100644 --- a/client/src/d_main.cpp +++ b/client/src/d_main.cpp @@ -801,6 +801,12 @@ void D_DoomMain() scannedWADs_t wads = GUI_BootWindow(); iwad = wads.iwad; pwads = wads.pwads; + + for (StringTokens::iterator it = wads.options.begin(); + it != wads.options.end(); ++it) + { + Args.AppendArg((*it).c_str()); + } } } @@ -858,7 +864,7 @@ void D_DoomMain() // set the default value for vid_ticker based on the presence of -devparm if (devparm) vid_ticker.SetDefault("1"); - + // Nomonsters sv_nomonsters = Args.CheckParm("-nomonsters"); diff --git a/client/src/m_menu.cpp b/client/src/m_menu.cpp index 6268e1819..f82cbf40d 100644 --- a/client/src/m_menu.cpp +++ b/client/src/m_menu.cpp @@ -25,6 +25,8 @@ #include "odamex.h" +#include + #include "gstrings.h" #include "c_console.h" #include "c_dispatch.h" diff --git a/client/src/m_options.cpp b/client/src/m_options.cpp index 9f55798dc..30c720ef2 100644 --- a/client/src/m_options.cpp +++ b/client/src/m_options.cpp @@ -1468,7 +1468,7 @@ void M_SwitchMenu(menu_t* menu) for (i = 0; i < menu->numitems; i++) { item = menu->items + i; - if (item->type != whitetext && item->type != redtext) + if (item->type != whitetext && item->type != redtext && item->type != orangetext) { thiswidth = V_StringWidth (item->label); if (thiswidth > widest) @@ -1932,6 +1932,7 @@ void M_OptResponder (event_t *ev) } while (CurrentMenu->items[CurrentItem].type == redtext || CurrentMenu->items[CurrentItem].type == whitetext || CurrentMenu->items[CurrentItem].type == yellowtext || + CurrentMenu->items[CurrentItem].type == orangetext || (CurrentMenu->items[CurrentItem].type == screenres && !CurrentMenu->items[CurrentItem].b.res1)); @@ -1972,6 +1973,7 @@ void M_OptResponder (event_t *ev) } while (CurrentMenu->items[CurrentItem].type == redtext || CurrentMenu->items[CurrentItem].type == whitetext || CurrentMenu->items[CurrentItem].type == yellowtext || + CurrentMenu->items[CurrentItem].type == orangetext || (CurrentMenu->items[CurrentItem].type == screenres && !CurrentMenu->items[CurrentItem].b.res1)); @@ -1993,6 +1995,7 @@ void M_OptResponder (event_t *ev) while (CurrentMenu->items[CurrentItem].type == redtext || CurrentMenu->items[CurrentItem].type == whitetext || CurrentMenu->items[CurrentItem].type == yellowtext || + CurrentMenu->items[CurrentItem].type == orangetext || (CurrentMenu->items[CurrentItem].type == screenres && !CurrentMenu->items[CurrentItem].b.res1)) { @@ -2015,6 +2018,7 @@ void M_OptResponder (event_t *ev) while (CurrentMenu->items[CurrentItem].type == redtext || CurrentMenu->items[CurrentItem].type == whitetext || CurrentMenu->items[CurrentItem].type == yellowtext || + CurrentMenu->items[CurrentItem].type == orangetext || (CurrentMenu->items[CurrentItem].type == screenres && !CurrentMenu->items[CurrentItem].b.res1)) { diff --git a/client/src/r_drawt_altivec.cpp b/client/src/r_drawt_altivec.cpp index eea758733..5a0cdf95e 100644 --- a/client/src/r_drawt_altivec.cpp +++ b/client/src/r_drawt_altivec.cpp @@ -36,9 +36,7 @@ #include "r_main.h" #include "i_video.h" -#if !defined(__APPLE_ALTIVEC__) #include -#endif #define ALTIVEC_ALIGNED(x) x __attribute__((aligned(16))) diff --git a/client/src/st_new.cpp b/client/src/st_new.cpp index 8e12ce198..a79bf1c28 100644 --- a/client/src/st_new.cpp +++ b/client/src/st_new.cpp @@ -1368,9 +1368,14 @@ void LevelStateHUD() break; } case LevelState::ENDROUND_COUNTDOWN: { - StrFormat(lines.title, - "Round " TEXTCOLOR_YELLOW "%d " TEXTCOLOR_GREY "complete\n", - ::levelstate.getRound()); + if (G_IsCoopGame() || G_IsHordeMode()) + StrFormat(lines.title, + "Attempt " TEXTCOLOR_YELLOW "%d " TEXTCOLOR_GREY "complete\n", + ::levelstate.getRound()); + else + StrFormat(lines.title, + "Round " TEXTCOLOR_YELLOW "%d " TEXTCOLOR_GREY "complete\n", + ::levelstate.getRound()); WinInfo win = ::levelstate.getWinInfo(); if (win.type == WinInfo::WIN_DRAW) @@ -1381,15 +1386,27 @@ void LevelStateHUD() else if (win.type == WinInfo::WIN_TEAM) StrFormat(lines.subtitle[0], "%s team wins the round", WinToColorString(win).c_str()); + else if (G_IsCoopGame() || G_IsHordeMode()) + StrFormat(lines.subtitle[0], "Next attempt in " TEXTCOLOR_GREEN "%d", + ::levelstate.getCountdown()); else StrFormat(lines.subtitle[0], "Next round in " TEXTCOLOR_GREEN "%d", ::levelstate.getCountdown()); break; } case LevelState::ENDGAME_COUNTDOWN: { - StrFormat(lines.title, "Match complete"); - WinInfo win = ::levelstate.getWinInfo(); + //Upper Text + if + (win.type == WinInfo::WIN_EVERYBODY) + StrFormat(lines.title, TEXTCOLOR_YELLOW "Mission Success!"); + else if + (win.type == WinInfo::WIN_NOBODY) + StrFormat(lines.title, TEXTCOLOR_RED "Mission Failed!"); + else + StrFormat(lines.title, "Match complete"); + + // Lower Text if (win.type == WinInfo::WIN_DRAW) StrFormat(lines.subtitle[0], "The game ends in a tie"); else if (win.type == WinInfo::WIN_PLAYER) diff --git a/client/src/v_screenshot.cpp b/client/src/v_screenshot.cpp index 2f24cb184..375de5b9d 100644 --- a/client/src/v_screenshot.cpp +++ b/client/src/v_screenshot.cpp @@ -24,6 +24,8 @@ #include "odamex.h" +#include + #include #include diff --git a/common/c_cvarlist.cpp b/common/c_cvarlist.cpp index 1e4f22145..312c042dc 100644 --- a/common/c_cvarlist.cpp +++ b/common/c_cvarlist.cpp @@ -245,12 +245,13 @@ CVAR(g_preroundreset, "0", "After preround is over, reset the map one last time. CVAR(g_postroundtime, "3", "Amount of time after a round before the next round/endgame", CVARTYPE_INT, CVAR_SERVERARCHIVE | CVAR_NOENABLEDISABLE) -CVAR_RANGE(g_coopthingfilter, "0", "Removes cooperative things of the map. Values are:\n" \ - "// 0 - All Coop things are retained (default).\n" \ +CVAR_RANGE(g_thingfilter, "0", "Removes some things from the map. Values are:\n" \ + "// 0 - All things are retained (default).\n" \ "// 1 - Only Coop weapons are removed.\n" \ - "// 2 - All Coop things are removed.", + "// 2 - All Coop things are removed.\n" \ + "// 3 - All pickupable things are removed.", CVARTYPE_BYTE, CVAR_SERVERARCHIVE | CVAR_SERVERINFO | CVAR_NOENABLEDISABLE | CVAR_LATCH, - 0.0f, 2.0f) + 0.0f, 3.0f) CVAR(g_resetinvonexit, "0", "Always reset players to their starting inventory on level exit", CVARTYPE_BOOL, diff --git a/common/c_dispatch.cpp b/common/c_dispatch.cpp index 0a409deaf..523c113ac 100644 --- a/common/c_dispatch.cpp +++ b/common/c_dispatch.cpp @@ -26,6 +26,7 @@ #include #include +#include #include "cmdlib.h" #include "c_console.h" diff --git a/common/cmdlib.h b/common/cmdlib.h index c7041837b..a20be7c4c 100644 --- a/common/cmdlib.h +++ b/common/cmdlib.h @@ -24,6 +24,7 @@ #pragma once #include +#include #ifdef _MSC_VER #pragma warning(disable : 4244) // MIPS diff --git a/common/d_dehacked.cpp b/common/d_dehacked.cpp index b63e1e10d..ec697cbbb 100644 --- a/common/d_dehacked.cpp +++ b/common/d_dehacked.cpp @@ -1244,19 +1244,14 @@ static int PatchThing(int thingy) info->flags3 |= MF3_E4M8BOSS; } - if (tempval & MF3_FULLVOLSOUNDS) - { - info->flags3 |= MF3_FULLVOLSOUNDS; - } - - if (tempval & MF2_NODMGTHRUST) + if (tempval & BIT(17)) // MBF21 RIP is 1 << 17 { - info->flags2 |= MF2_NODMGTHRUST; + info->flags2 |= MF2_RIP; } - if (tempval & MF2_RIP) + if (tempval & MF3_FULLVOLSOUNDS) { - info->flags2 |= MF2_RIP; + info->flags3 |= MF3_FULLVOLSOUNDS; } value[3] |= atoi(strval); diff --git a/common/d_player.h b/common/d_player.h index c16f1f904..7240e95cb 100644 --- a/common/d_player.h +++ b/common/d_player.h @@ -134,7 +134,6 @@ class player_s struct ticcmd_t cmd; // the ticcmd currently being processed std::queue cmdqueue; // all received ticcmds - int missingticcmdcount; // number of gametics without processing a ticcmd for this player // [RH] who is this? UserInfo userinfo; diff --git a/common/doomdata.h b/common/doomdata.h index 367616ef5..2bbe997eb 100644 --- a/common/doomdata.h +++ b/common/doomdata.h @@ -269,7 +269,7 @@ typedef struct MapThing #define MTF_DEATHMATCH 0x0400 // Thing appears in deathmatch games // Custom MapThing Flags -#define MTF_FILTER_COOPWPN 0x0800 // Weapon thing is filtered with g_coopthingfilter 1. +#define MTF_FILTER_COOPWPN 0x0800 // Weapon thing is filtered with g_thingfilter 1. // (Hate this method but it works...) diff --git a/common/g_mapinfo.cpp b/common/g_mapinfo.cpp index b311b99dc..36184ba23 100644 --- a/common/g_mapinfo.cpp +++ b/common/g_mapinfo.cpp @@ -1479,70 +1479,74 @@ struct MapInfoDataSetter MapInfoDataSetter(level_pwad_info_t& ref) { - mapInfoDataContainer = { - { "levelnum", &MIType_Int, &ref.levelnum}, - { "next", &MIType_MapName, &ref.nextmap}, - { "secretnext", &MIType_MapName, &ref.secretmap}, - { "secret", &MIType_MapName, &ref.secretmap }, - { "cluster", &MIType_Cluster, &ref.cluster }, - { "sky1", &MIType_Sky, &ref.skypic }, - { "sky2", &MIType_Sky, &ref.skypic2 }, - { "fade", &MIType_Color, &ref.fadeto_color }, - { "outsidefog", &MIType_Color, &ref.outsidefog_color }, - { "titlepatch", &MIType_LumpName, &ref.pname }, - { "par", &MIType_Int, &ref.partime }, - { "music", &MIType_MusicLumpName, &ref.music }, - { "nointermission", &MIType_SetFlag, &ref.flags, LEVEL_NOINTERMISSION }, - { "doublesky", &MIType_SetFlag, &ref.flags, LEVEL_DOUBLESKY }, - { "nosoundclipping", &MIType_SetFlag, &ref.flags, LEVEL_NOSOUNDCLIPPING }, - { "allowmonstertelefrags", &MIType_SetFlag, &ref.flags, - LEVEL_MONSTERSTELEFRAG }, - { "map07special", &MIType_Map07Special, &ref.bossactions }, - { "baronspecial", &MIType_BaronSpecial, &ref.bossactions }, - { "cyberdemonspecial", &MIType_CyberdemonSpecial, &ref.bossactions }, - { "spidermastermindspecial", &MIType_SpiderMastermindSpecial, &ref.bossactions }, - { "specialaction_exitlevel", &MIType_SpecialAction_ExitLevel, &ref.bossactions }, - { "specialaction_opendoor", &MIType_SpecialAction_OpenDoor, &ref.bossactions }, - { "specialaction_lowerfloor", &MIType_SpecialAction_LowerFloor, &ref.bossactions }, - { "lightning" }, - { "fadetable", &MIType_LumpName, &ref.fadetable }, - { "evenlighting", &MIType_SetFlag, &ref.flags, LEVEL_EVENLIGHTING }, - { "noautosequences", &MIType_SetFlag, &ref.flags, LEVEL_SNDSEQTOTALCTRL }, - { "forcenoskystretch", &MIType_SetFlag, &ref.flags, LEVEL_FORCENOSKYSTRETCH }, - { "allowfreelook", &MIType_SCFlags, &ref.flags, LEVEL_FREELOOK_YES, - ~LEVEL_FREELOOK_NO }, - { "nofreelook", &MIType_SCFlags, &ref.flags, LEVEL_FREELOOK_NO, - ~LEVEL_FREELOOK_YES }, - { "allowjump", &MIType_SCFlags, &ref.flags, LEVEL_JUMP_YES, ~LEVEL_JUMP_NO }, - { "nojump", &MIType_SCFlags, &ref.flags, LEVEL_JUMP_NO, ~LEVEL_JUMP_YES }, - { "cdtrack", &MIType_EatNext }, - { "cd_start_track", &MIType_EatNext }, - { "cd_end1_track", &MIType_EatNext }, - { "cd_end2_track", &MIType_EatNext }, - { "cd_end3_track", &MIType_EatNext }, - { "cd_intermission_track", &MIType_EatNext }, - { "cd_title_track", &MIType_EatNext }, - { "warptrans", &MIType_EatNext }, - { "gravity", &MIType_Float, &ref.gravity }, - { "aircontrol", &MIType_Float, &ref.aircontrol }, - { "islobby", &MIType_SetFlag, &ref.flags, LEVEL_LOBBYSPECIAL }, - { "lobby", &MIType_SetFlag, &ref.flags, LEVEL_LOBBYSPECIAL }, - { "nocrouch" }, - { "intermusic", &MIType_EatNext }, - { "par", &MIType_Int, &ref.partime }, - { "sucktime", &MIType_EatNext }, - { "enterpic", &MIType_InterLumpName, &ref.enterpic }, // todo: add intermission script support - { "exitpic", &MIType_InterLumpName, &ref.exitpic }, // todo: add intermission script support - { "interpic", &MIType_EatNext }, - { "translator", &MIType_EatNext }, - { "compat_shorttex", &MIType_CompatFlag, &ref.flags }, // todo: not implemented - { "compat_limitpain", &MIType_CompatFlag, &ref.flags }, // todo: not implemented - { "compat_dropoff", &MIType_CompatFlag, &ref.flags, LEVEL_COMPAT_DROPOFF }, - { "compat_trace", &MIType_CompatFlag, &ref.flags }, // todo: not implemented - { "compat_boomscroll", &MIType_CompatFlag, &ref.flags }, // todo: not implemented - { "compat_sectorsounds", &MIType_CompatFlag, &ref.flags }, // todo: not implemented - { "compat_nopassover", &MIType_CompatFlag, &ref.flags, LEVEL_COMPAT_NOPASSOVER } - }; + mapInfoDataContainer.reserve( + 70); // [DE] some random number, i'm not counting all these + + ENTRY3("levelnum", &MIType_Int, &ref.levelnum) + ENTRY3("next", &MIType_MapName, &ref.nextmap) + ENTRY3("secretnext", &MIType_MapName, &ref.secretmap) + ENTRY3("secret", &MIType_MapName, &ref.secretmap) + ENTRY3("cluster", &MIType_Cluster, &ref.cluster) + ENTRY3("sky1", &MIType_Sky, &ref.skypic) + ENTRY3("sky2", &MIType_Sky, &ref.skypic2) + ENTRY3("fade", &MIType_Color, &ref.fadeto_color) + ENTRY3("outsidefog", &MIType_Color, &ref.outsidefog_color) + ENTRY3("titlepatch", &MIType_LumpName, &ref.pname) + ENTRY3("par", &MIType_Int, &ref.partime) + ENTRY3("music", &MIType_MusicLumpName, &ref.music) + ENTRY4("nointermission", &MIType_SetFlag, &ref.flags, LEVEL_NOINTERMISSION) + ENTRY4("doublesky", &MIType_SetFlag, &ref.flags, LEVEL_DOUBLESKY) + ENTRY4("nosoundclipping", &MIType_SetFlag, &ref.flags, LEVEL_NOSOUNDCLIPPING) + ENTRY4("allowmonstertelefrags", &MIType_SetFlag, &ref.flags, + LEVEL_MONSTERSTELEFRAG) + ENTRY3("map07special", &MIType_Map07Special, &ref.bossactions) + ENTRY3("baronspecial", &MIType_BaronSpecial, &ref.bossactions) + ENTRY3("cyberdemonspecial", &MIType_CyberdemonSpecial, &ref.bossactions) + ENTRY3("spidermastermindspecial", &MIType_SpiderMastermindSpecial, &ref.bossactions) + ENTRY3("specialaction_exitlevel", &MIType_SpecialAction_ExitLevel, &ref.bossactions) + ENTRY3("specialaction_opendoor", &MIType_SpecialAction_OpenDoor, &ref.bossactions) + ENTRY3("specialaction_lowerfloor", &MIType_SpecialAction_LowerFloor, &ref.bossactions) + ENTRY1("lightning") + ENTRY3("fadetable", &MIType_LumpName, &ref.fadetable) + ENTRY4("evenlighting", &MIType_SetFlag, &ref.flags, LEVEL_EVENLIGHTING) + ENTRY4("noautosequences", &MIType_SetFlag, &ref.flags, LEVEL_SNDSEQTOTALCTRL) + ENTRY4("forcenoskystretch", &MIType_SetFlag, &ref.flags, LEVEL_FORCENOSKYSTRETCH) + ENTRY5("allowfreelook", &MIType_SCFlags, &ref.flags, LEVEL_FREELOOK_YES, + ~LEVEL_FREELOOK_NO) + ENTRY5("nofreelook", &MIType_SCFlags, &ref.flags, LEVEL_FREELOOK_NO, + ~LEVEL_FREELOOK_YES) + ENTRY5("allowjump", &MIType_SCFlags, &ref.flags, LEVEL_JUMP_YES, ~LEVEL_JUMP_NO) + ENTRY5("nojump", &MIType_SCFlags, &ref.flags, LEVEL_JUMP_NO, ~LEVEL_JUMP_YES) + ENTRY2("cdtrack", &MIType_EatNext) + ENTRY2("cd_start_track", &MIType_EatNext) + ENTRY2("cd_end1_track", &MIType_EatNext) + ENTRY2("cd_end2_track", &MIType_EatNext) + ENTRY2("cd_end3_track", &MIType_EatNext) + ENTRY2("cd_intermission_track", &MIType_EatNext) + ENTRY2("cd_title_track", &MIType_EatNext) + ENTRY2("warptrans", &MIType_EatNext) + ENTRY3("gravity", &MIType_Float, &ref.gravity) + ENTRY3("aircontrol", &MIType_Float, &ref.aircontrol) + ENTRY4("islobby", &MIType_SetFlag, &ref.flags, LEVEL_LOBBYSPECIAL) + ENTRY4("lobby", &MIType_SetFlag, &ref.flags, LEVEL_LOBBYSPECIAL) + ENTRY1("nocrouch") + ENTRY2("intermusic", &MIType_EatNext) + ENTRY3("par", &MIType_Int, &ref.partime) + ENTRY2("sucktime", &MIType_EatNext) + ENTRY3("enterpic", &MIType_InterLumpName, + &ref.enterpic) // todo: add intermission script support + ENTRY3("exitpic", &MIType_InterLumpName, + &ref.exitpic) // todo: add intermission script support + ENTRY2("interpic", &MIType_EatNext) + ENTRY2("translator", &MIType_EatNext) + ENTRY3("compat_shorttex", &MIType_CompatFlag, &ref.flags) // todo: not implemented + ENTRY3("compat_limitpain", &MIType_CompatFlag, &ref.flags) // todo: not implemented + ENTRY4("compat_dropoff", &MIType_CompatFlag, &ref.flags, LEVEL_COMPAT_DROPOFF) + ENTRY3("compat_trace", &MIType_CompatFlag, &ref.flags) // todo: not implemented + ENTRY3("compat_boomscroll", &MIType_CompatFlag, &ref.flags) // todo: not implemented + ENTRY3("compat_sectorsounds", &MIType_CompatFlag, &ref.flags) // todo: not implemented + ENTRY4("compat_nopassover", &MIType_CompatFlag, &ref.flags, LEVEL_COMPAT_NOPASSOVER) + ENTRY3("compat_invisibility", &MIType_CompatFlag, &ref.flags) // todo: not implemented } }; diff --git a/common/m_resfile.cpp b/common/m_resfile.cpp index cf77547bc..a278c769a 100644 --- a/common/m_resfile.cpp +++ b/common/m_resfile.cpp @@ -71,7 +71,7 @@ bool OResFile::make(OResFile& out, const std::string& file) out.m_fullpath = fullpath; out.m_md5 = hash; - out.m_basename = StdStringToUpper(basename); + out.m_basename = basename; return true; } @@ -111,7 +111,7 @@ bool OResFile::makeWithHash(OResFile& out, const std::string& file, const OMD5Ha out.m_fullpath = fullpath; out.m_md5 = hash; - out.m_basename = StdStringToUpper(basename); + out.m_basename = basename; return true; } @@ -136,8 +136,8 @@ bool OWantFile::make(OWantFile& out, const std::string& file, const ofile_t type out.m_wantedpath = file; out.m_wantedtype = type; - out.m_basename = StdStringToUpper(basename); - out.m_extension = std::string(".") + StdStringToUpper(extension); + out.m_basename = basename; + out.m_extension = std::string(".") + extension; return true; } @@ -165,8 +165,8 @@ bool OWantFile::makeWithHash(OWantFile& out, const std::string& file, const ofil out.m_wantedpath = file; out.m_wantedtype = type; out.m_wantedMD5 = hash; - out.m_basename = StdStringToUpper(basename); - out.m_extension = StdStringToUpper(extension); + out.m_basename = basename; + out.m_extension = extension; return true; } @@ -290,7 +290,7 @@ bool M_ResolveWantedFile(OResFile& out, const OWantFile& wanted) M_ExtractFileBase(path, basename); if (M_ExtractFileExtension(path, strext)) { - exts.push_back("." + StdStringToUpper(strext)); + exts.push_back("." + strext); } else { diff --git a/common/p_boomfspec.cpp b/common/p_boomfspec.cpp index 2307217ee..bed8da9f5 100644 --- a/common/p_boomfspec.cpp +++ b/common/p_boomfspec.cpp @@ -1304,17 +1304,20 @@ void P_PlayerInCompatibleSector(player_t* player) { switch ((sector->special & DAMAGE_MASK) >> DAMAGE_SHIFT) { - case 0: // Kill player unless invuln or rad suit - if (!player->powers[pw_invulnerability] && !player->powers[pw_ironfeet]) + case 0: // Kill player unless invuln or rad suit or IDDQD + if (!player->powers[pw_invulnerability] && !player->powers[pw_ironfeet] && !(player->cheats & CF_GODMODE)) { - P_DamageMobj(player->mo, NULL, NULL, 10000, MOD_UNKNOWN); + P_DamageMobj(player->mo, NULL, NULL, 999, MOD_UNKNOWN); // 999 so BUDDHA can survive } break; - case 1: // Kill player with no scruples - P_DamageMobj(player->mo, NULL, NULL, 10000, MOD_UNKNOWN); + case 1: // Kill player with no scruples unless IDDQD + if(!(player->cheats & CF_GODMODE)) + { + P_DamageMobj(player->mo, NULL, NULL, 10000, MOD_UNKNOWN); + } break; case 2: // Kill all players and exit. There's no delay here so it may confuse - // some players. + // some players. Do NOT kill players with IDDQD. if (serverside) { if (sv_allowexit) @@ -1322,14 +1325,14 @@ void P_PlayerInCompatibleSector(player_t* player) for (Players::iterator it = ::players.begin(); it != ::players.end(); ++it) { - if (player->ingame() && player->health > 0) + if (player->ingame() && player->health > 0 && !(player->cheats & CF_GODMODE)) { P_DamageMobj((*it).mo, NULL, NULL, 10000, MOD_EXIT); } } G_ExitLevel(0, 1); } - else + else if (!(player->cheats & CF_GODMODE)) // Do NOT kill players with IDDQD. { P_DamageMobj( player->mo, NULL, NULL, 10000, @@ -1339,7 +1342,7 @@ void P_PlayerInCompatibleSector(player_t* player) } break; case 3: // Kill all players and secret exit. There's no delay here so it may - // confuse some players. + // confuse some players. Do NOT kill players with IDDQD. if (serverside) { if (sv_allowexit) @@ -1347,14 +1350,14 @@ void P_PlayerInCompatibleSector(player_t* player) for (Players::iterator it = ::players.begin(); it != ::players.end(); ++it) { - if (player->ingame() && player->health > 0) + if (player->ingame() && player->health > 0 && !(player->cheats & CF_GODMODE)) { P_DamageMobj((*it).mo, NULL, NULL, 10000, MOD_EXIT); } } G_SecretExitLevel(0, 1); } - else + else if (!(player->cheats & CF_GODMODE)) // Do NOT kill players with IDDQD. { P_DamageMobj( player->mo, NULL, NULL, 10000, @@ -1365,7 +1368,7 @@ void P_PlayerInCompatibleSector(player_t* player) break; } } - else + else if (!(player->cheats & CF_GODMODE)) // Do NOT damage players with IDDQD. { P_ApplyGeneralizedSectorDamage(player, (sector->special & DAMAGE_MASK) >> DAMAGE_SHIFT); diff --git a/common/p_map.cpp b/common/p_map.cpp index bde33b11f..a3b3ddf44 100644 --- a/common/p_map.cpp +++ b/common/p_map.cpp @@ -651,7 +651,7 @@ static BOOL PIT_CheckThing (AActor *thing) if (tmthing->info->ripsound) S_Sound(tmthing, CHAN_VOICE, tmthing->info->ripsound, 1, ATTN_NORM); - P_DamageMobj(thing, tmthing, tmthing->target, damage); + P_DamageMobj(thing, tmthing, tmthing->target, damage, MOD_UNKNOWN); if (thing->flags2 & MF2_PUSHABLE && !(tmthing->flags2 & MF2_CANNOTPUSH)) { // Push thing thing->momx += tmthing->momx >> 2; @@ -680,8 +680,16 @@ static BOOL PIT_CheckThing (AActor *thing) mod = MOD_BFG_BOOM; break; // [AM] Monster fireballs get a special MOD. + // Unless they're from players default: - mod = MOD_FIREBALL; + if ((tmthing->target && tmthing->target->player) || !tmthing->target) + { + mod = MOD_UNKNOWN; + } + else + { + mod = MOD_FIREBALL; + } break; } P_DamageMobj (thing, tmthing, tmthing->target, damage, mod); @@ -697,12 +705,35 @@ static BOOL PIT_CheckThing (AActor *thing) // [SL] Work-around the additional height added to players // in P_CheckPosition. Don't let players grab items above // their real height! - if (!P_AllowPassover() || !tmthing->player || - thing->z < tmthing->z + tmthing->height - 24*FRACUNIT) + + fixed_t max_z = tmthing->z + tmthing->height; + + if (tmthing->player) + max_z -= 24 * FRACUNIT; + + if (!P_AllowPassover() || thing->z < max_z) P_TouchSpecialThing (thing, tmthing); // can remove thing + + return !solid; } - return !solid; + // killough 3/16/98: Allow non-solid moving objects to move through solid + // ones, by allowing the moving thing (tmthing) to move if it's non-solid, + // despite another solid thing being in the way. + // killough 4/11/98: Treat no-clipping things as not blocking + // ...but not in demo_compatibility mode + + // e6y + // Correction of wrong return value with demo_compatibility. + // There is no more synch on http://www.doomworld.com/sda/dwdemo/w303-115.zip + // (with correction in setMobjInfoValue) + if (demoplayback || !co_boomphys + //&& !prboom_comp[PC_TREAT_NO_CLIPPING_THINGS_AS_NOT_BLOCKING].state + ) + return !(thing->flags & MF_SOLID); + else + return !((thing->flags & MF_SOLID && !(thing->flags & MF_NOCLIP)) && + (tmthing->flags & MF_SOLID || (demoplayback || !co_boomphys))); } // This routine checks for Lost Souls trying to be spawned // phares diff --git a/common/p_maputl.cpp b/common/p_maputl.cpp index 8278c557d..6805465c3 100644 --- a/common/p_maputl.cpp +++ b/common/p_maputl.cpp @@ -1231,6 +1231,13 @@ static AActor* RoughBlockCheck(AActor* mo, int index, angle_t fov) continue; } + // [Blair] Don't target spectators + if (link->player && link->player->spectator) + { + link = link->snext; + continue; + } + // [Blair] Don't target teammates if (mo->target->player && link->player && P_AreTeammates((player_t&)mo->target->player, (player_t&)link->player)) diff --git a/common/p_mobj.cpp b/common/p_mobj.cpp index e9ad3efd6..aee30e6ba 100644 --- a/common/p_mobj.cpp +++ b/common/p_mobj.cpp @@ -85,6 +85,7 @@ EXTERN_CVAR(co_fixweaponimpacts) EXTERN_CVAR(co_fineautoaim) EXTERN_CVAR(sv_allowshowspawns) EXTERN_CVAR(sv_teamsinplay) +EXTERN_CVAR(g_thingfilter) mapthing2_t itemrespawnque[ITEMQUESIZE]; int itemrespawntime[ITEMQUESIZE]; @@ -127,8 +128,8 @@ AActor::AActor() prevangle(0), sprite(SPR_UNKN), frame(0), pitch(0), prevpitch(0), effects(0), subsector(NULL), floorz(0), ceilingz(0), dropoffz(0), floorsector(NULL), radius(0), height(0), momx(0), momy(0), momz(0), validcount(0), type(MT_UNKNOWNTHING), - info(NULL), tics(0), state(NULL), damage(0), flags(0), flags2(0), flags3(0), oflags(0), - special1(0), special2(0), health(0), movedir(0), movecount(0), visdir(0), + info(NULL), tics(0), state(NULL), damage(0), flags(0), flags2(0), + flags3(0), oflags(0), special1(0), special2(0), health(0), movedir(0), movecount(0), visdir(0), reactiontime(0), threshold(0), player(NULL), lastlook(0), special(0), inext(NULL), iprev(NULL), translation(translationref_t()), translucency(0), waterlevel(0), gear(0), onground(false), touching_sectorlist(NULL), deadtic(0), oldframe(0), @@ -148,8 +149,9 @@ AActor::AActor(const AActor& other) dropoffz(other.dropoffz), floorsector(other.floorsector), radius(other.radius), height(other.height), momx(other.momx), momy(other.momy), momz(other.momz), validcount(other.validcount), type(other.type), info(other.info), tics(other.tics), - state(other.state), damage(other.damage), flags(other.flags), flags2(other.flags2), - flags3(other.flags3), oflags(other.oflags), special1(other.special1), special2(other.special2), + state(other.state), damage(other.damage), + flags(other.flags), flags2(other.flags2), flags3(other.flags3), oflags(other.oflags), + special1(other.special1), special2(other.special2), health(other.health), movedir(other.movedir), movecount(other.movecount), visdir(other.visdir), reactiontime(other.reactiontime), threshold(other.threshold), player(other.player), lastlook(other.lastlook), special(other.special), @@ -675,18 +677,19 @@ void AActor::RunThink () prevx = x; prevy = y; prevz = z; + if (!player) { prevangle = angle; prevpitch = pitch; } - // server removal of corpses only - if (!clientside && serverside) - { - if (type == MT_PLAYER && health <= 0) - deadtic++; - } + // server removal of corpses only + if (!clientside && serverside) + { + if (type == MT_PLAYER && health <= 0) + deadtic++; + } // GhostlyDeath -- Was a spectator but now it's nothing! if ((this->oflags & MFO_SPECTATOR ) && !player) @@ -2630,9 +2633,9 @@ void P_ExplodeMissile (AActor* mo) case MT_BFG: mod = MOD_BFG_BOOM; break; - // [AM] Monster fireballs get a special MOD. + // Blair: Unknown player projectiles get an unknown mod default: - mod = MOD_FIREBALL; + mod = MOD_UNKNOWN; break; } @@ -2693,6 +2696,16 @@ size_t P_GetMapThingPlayerNumber(mapthing2_t *mthing) (mthing->type - 4001 + 4) % MAXPLAYERSTARTS; } +int P_IsPickupableThing(short type) +{ + return (type == 82 // SSG + || (type >= 2000 && type <= 2050) // weapons, ammo, health, armor, special items + || type == 17 // cell pack + || type == 83 // megasphere + || type == 8 // backpack + ); +} + // // P_SpawnMapThing // The fields of the mapthing should @@ -2834,6 +2847,9 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position) return; } + if (g_thingfilter == 3 && P_IsPickupableThing(mthing->type)) + return; + // check for appropriate skill level if (!(mthing->flags & G_GetCurrentSkill().spawn_filter)) return; diff --git a/common/p_setup.cpp b/common/p_setup.cpp index 0c639b680..cb76b8e6a 100644 --- a/common/p_setup.cpp +++ b/common/p_setup.cpp @@ -70,7 +70,7 @@ int P_TranslateSectorSpecial(int special); extern dyncolormap_t NormalLight; extern AActor* shootthing; -EXTERN_CVAR(g_coopthingfilter) +EXTERN_CVAR(g_thingfilter) bool g_ValidLevel = false; @@ -629,9 +629,9 @@ void P_LoadThings (int lump) #ifdef SERVER_APP if (G_IsCoopGame()) { - if (g_coopthingfilter == 1) + if (g_thingfilter == 1) mt2.flags |= MTF_FILTER_COOPWPN; - else if (g_coopthingfilter == 2) + else if (g_thingfilter == 2) mt2.flags &= ~MTF_COOPERATIVE; } else diff --git a/common/p_spec.cpp b/common/p_spec.cpp index 4fdcf4407..eb04c2db1 100644 --- a/common/p_spec.cpp +++ b/common/p_spec.cpp @@ -465,7 +465,7 @@ void DPusher::Serialize (FArchive &arc) else { arc >> m_Type; - arc.ReadObject((DObject*&)m_Source, DPusher::StaticType()); + arc.ReadObject((DObject*&)*m_Source, DPusher::StaticType()); arc >> m_Xmag >> m_Ymag >> m_Magnitude >> m_Radius >> m_X >> m_Y >> m_Affectee; } } diff --git a/common/p_user.cpp b/common/p_user.cpp index 0296f7993..461a3ef03 100644 --- a/common/p_user.cpp +++ b/common/p_user.cpp @@ -26,6 +26,8 @@ #include "odamex.h" +#include + #include #include "cmdlib.h" @@ -1321,7 +1323,6 @@ player_s::player_s() : ping(0), last_received(0), tic(0), - missingticcmdcount(0), snapshots(PlayerSnapshotManager()), spying(0), spectator(false), @@ -1441,8 +1442,6 @@ player_s &player_s::operator =(const player_s &other) last_received = other.last_received; tic = other.tic; - missingticcmdcount = other.missingticcmdcount; - spying = other.spying; spectator = other.spectator; // deadspectator = other.deadspectator; diff --git a/common/version.h b/common/version.h index 7873b4570..982b040d5 100644 --- a/common/version.h +++ b/common/version.h @@ -77,7 +77,7 @@ #define DOTVERSIONSTR "11.0.0" #define GAMEVER (MAKEVER(11, 0, 0)) -#define COPYRIGHTSTR "Copyright (C) 2006-2022 The Odamex Team" +#define COPYRIGHTSTR "Copyright (C) 2006-2023 The Odamex Team" #define SERVERMAJ (VERMAJ(gameversion)) #define SERVERMIN (VERMIN(gameversion)) diff --git a/odalaunch/res/Info.plist b/odalaunch/res/Info.plist index 76a11a5d5..6dc73d25d 100644 --- a/odalaunch/res/Info.plist +++ b/odalaunch/res/Info.plist @@ -23,11 +23,11 @@ CFBundleShortVersionString 11.0.0 CFBundleGetInfoString - Copyright © 2006-2022 The Odamex Team + Copyright © 2006-2023 The Odamex Team CFBundleLongVersionString 11.0.0 NSHumanReadableCopyright - Copyright © 2006-2022 The Odamex Team + Copyright © 2006-2023 The Odamex Team LSRequiresCarbon diff --git a/odalaunch/res/gui_project.fbp b/odalaunch/res/gui_project.fbp index 77c1130ea..2345bf017 100644 --- a/odalaunch/res/gui_project.fbp +++ b/odalaunch/res/gui_project.fbp @@ -10315,7 +10315,7 @@ 0 0 wxID_ANY - Copyright (C) 2006-2022 The Odamex Team + Copyright (C) 2006-2023 The Odamex Team 0 diff --git a/odalaunch/src/dlg_about.cpp b/odalaunch/src/dlg_about.cpp index 3f7da287d..2e0991890 100644 --- a/odalaunch/src/dlg_about.cpp +++ b/odalaunch/src/dlg_about.cpp @@ -30,7 +30,7 @@ #include #include -#define _ODA_COPYRIGHT_ "Copyright (C) 2006-2022 The Odamex Team" +#define _ODA_COPYRIGHT_ "Copyright (C) 2006-2023 The Odamex Team" BEGIN_EVENT_TABLE(dlgAbout, wxDialog) EVT_TEXT_URL(XRCID("Id_TxtCtrlDevelopers"), dlgAbout::OnTxtCtrlUrlClick) diff --git a/odalpapi/net_io.cpp b/odalpapi/net_io.cpp index d6dd666fe..16f136374 100644 --- a/odalpapi/net_io.cpp +++ b/odalpapi/net_io.cpp @@ -194,7 +194,7 @@ void BufferedSocket::SetRemoteAddress(const string& Address, const uint16_t& Por m_RemoteAddress.sin_family = PF_INET; m_RemoteAddress.sin_port = htons(Port); - m_RemoteAddress.sin_addr.s_addr = *((unsigned long*)&(((sockaddr_in*)result->ai_addr)->sin_addr)); + m_RemoteAddress.sin_addr = ((sockaddr_in*)result->ai_addr)->sin_addr; memset(m_RemoteAddress.sin_zero, '\0', sizeof m_RemoteAddress.sin_zero); freeaddrinfo(result); diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 567b890fb..8820723aa 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -37,11 +37,6 @@ if(WIN32 AND NOT MSVC) add_definitions(-DWINVER=0x0500) endif() -# Set up FHS installation path -if(NOT APPLE AND NOT WIN32) - add_definitions(-DINSTALL_PREFIX="${CMAKE_INSTALL_PREFIX}") -endif() - add_executable(odasrv ${COMMON_SOURCES} ${SERVER_SOURCES} ${SERVER_WIN32_SOURCES}) odamex_target_settings(odasrv) diff --git a/server/src/c_console.cpp b/server/src/c_console.cpp index 66116ee6b..159bb986a 100644 --- a/server/src/c_console.cpp +++ b/server/src/c_console.cpp @@ -24,6 +24,8 @@ #include "odamex.h" +#include + #include #include "m_fileio.h" diff --git a/server/src/sv_banlist.cpp b/server/src/sv_banlist.cpp index c271fe68c..36cdf9b63 100644 --- a/server/src/sv_banlist.cpp +++ b/server/src/sv_banlist.cpp @@ -24,6 +24,7 @@ #include "odamex.h" +#include #include #include "win32inc.h" diff --git a/server/src/sv_banlist.h b/server/src/sv_banlist.h index 6096f73fc..f4d686071 100644 --- a/server/src/sv_banlist.h +++ b/server/src/sv_banlist.h @@ -23,6 +23,7 @@ #pragma once +#include #include #include "json/json.h" diff --git a/server/src/sv_main.cpp b/server/src/sv_main.cpp index c718dc010..ffa61a676 100644 --- a/server/src/sv_main.cpp +++ b/server/src/sv_main.cpp @@ -127,6 +127,7 @@ void P_PlayerLeavesGame(player_s* player); bool P_LineSpecialMovesSector(short special); void SV_UpdateShareKeys(player_t& player); +std::string SV_BuildKillsDeathsStatusString(player_t& player); std::string V_GetTeamColor(UserInfo userinfo); CVAR_FUNC_IMPL (sv_maxclients) @@ -183,7 +184,10 @@ CVAR_FUNC_IMPL (sv_maxplayers) SVC_PlayerMembers(*it, SVC_PM_SPECTATOR)); } - SV_BroadcastPrintf ("%s became a spectator.\n", it->userinfo.netname.c_str()); + std::string status = SV_BuildKillsDeathsStatusString(*it); + SV_BroadcastPrintf(PRINT_HIGH, "%s became a spectator.(%s)\n", + it->userinfo.netname.c_str(), status.c_str()); + MSG_WriteSVC( &it->client.reliablebuf, SVC_Print(PRINT_CHAT, @@ -1166,6 +1170,7 @@ bool SV_AwarenessUpdate(player_t &player, AActor *mo) return true; } + return false; } @@ -1930,6 +1935,50 @@ void SV_ConnectClient2(player_t& player) SV_MidPrint((char*)sv_motd.cstring(), &player, 6); } + +// +// SV_BuildKillsDeathsStatusString +// +std::string SV_BuildKillsDeathsStatusString(player_t& player) +{ + std::string status; + char temp_str[100]; + + if (player.playerstate == PST_DOWNLOAD) + status = "downloading"; + else if (player.playerstate == PST_DISCONNECT && player.spectator) + status = "SPECTATOR"; + else + { + if (G_IsTeamGame()) + { + sprintf(temp_str, "%s TEAM, ", GetTeamInfo(player.userinfo.team)->ColorStringUpper.c_str()); + status += temp_str; + } + + // Points (CTF). + if (sv_gametype == GM_CTF) + { + sprintf(temp_str, "%d POINTS, ", player.points); + status += temp_str; + } + + // Frags (DM/TDM/CTF) or Kills (Coop). + if (G_IsCoopGame()) + sprintf(temp_str, "%d KILLS, ", player.killcount); + else + sprintf(temp_str, "%d FRAGS, ", player.fragcount); + + status += temp_str; + + // Deaths. + sprintf(temp_str, "%d DEATHS", player.deathcount); + status += temp_str; + } + return status; +} + + // // SV_DisconnectClient // @@ -1952,43 +2001,12 @@ void SV_DisconnectClient(player_t &who) Maplist_Disconnect(who); Vote_Disconnect(who); + who.playerstate = PST_DISCONNECT; + if (who.client.displaydisconnect) { // print some final stats for the disconnected player - std::string status; - if (who.playerstate == PST_DOWNLOAD) - status = "downloading"; - else if (who.spectator) - status = "SPECTATOR"; - else - { - if (G_IsTeamGame()) - { - sprintf(str, "%s TEAM, ", GetTeamInfo(who.userinfo.team)->ColorStringUpper.c_str()); - status += str; - } - - // Points (CTF). - if (sv_gametype == GM_CTF) - { - sprintf(str, "%d POINTS, ", who.points); - status += str; - } - - // Frags (DM/TDM/CTF) or Kills (Coop). - if (G_IsCoopGame()) - sprintf(str, "%d KILLS, ", who.killcount); - else - sprintf(str, "%d FRAGS, ", who.fragcount); - - status += str; - - // Deaths. - sprintf(str, "%d DEATHS", who.deathcount); - status += str; - } - - // Name and reason for disconnect. + std::string status = SV_BuildKillsDeathsStatusString(who); if (gametic - who.client.last_received == CLIENT_TIMEOUT*35) SV_BroadcastPrintf("%s timed out. (%s)\n", who.userinfo.netname.c_str(), status.c_str()); @@ -1997,7 +2015,6 @@ void SV_DisconnectClient(player_t &who) who.userinfo.netname.c_str(), status.c_str()); } - who.playerstate = PST_DISCONNECT; SV_UpdatePlayerQueuePositions(G_CanJoinGame, &who); } @@ -3204,39 +3221,35 @@ int SV_CalculateNumTiccmds(player_t &player) static const size_t maximum_queue_size = TICRATE / 4; - if (!sv_ticbuffer || gamestate != GS_LEVEL || player.spectator || player.playerstate == PST_DEAD) + if (!sv_ticbuffer || player.spectator || player.playerstate == PST_DEAD) { // Process all queued ticcmds. return maximum_queue_size; } - if (player.missingticcmdcount > 0) + if (player.mo->momx == 0 && player.mo->momy == 0 && player.mo->momz == 0) { - if (player.mo->momx == 0 && player.mo->momy == 0 && player.mo->momz == 0) - { - // Player is not moving - return 2; - } - if (player.cmdqueue.size() > 2 && gametic % (2*TICRATE) == player.id % (2*TICRATE)) - { - // Process an extra ticcmd once every 2 seconds to reduce the - // queue size. Use player id to stagger the timing to prevent everyone - // from running an extra ticcmd at the same time. - return 2; - } - if (player.cmdqueue.size() > maximum_queue_size) - { - // The player experienced a large latency spike so try to catch up by - // processing more than one ticcmd at the expense of appearing perfectly - // smooth. - return 2; - } + // Player is not moving + return 2; + } + if (player.cmdqueue.size() > 2 && gametic % 2*TICRATE == player.id % 2*TICRATE) + { + // Process an extra ticcmd once every 2 seconds to reduce the + // queue size. Use player id to stagger the timing to prevent everyone + // from running an extra ticcmd at the same time. + return 2; + } + if (player.cmdqueue.size() > maximum_queue_size) + { + // The player experienced a large latency spike so try to catch up by + // processing more than one ticcmd at the expense of appearing perfectly + // smooth + return 2; } // always run at least 1 ticcmd if possible return 1; } - // // SV_ProcessPlayerCmd // @@ -3266,9 +3279,6 @@ void SV_ProcessPlayerCmd(player_t &player) player.userinfo.netname, player.cmdqueue.size()); #endif // _TICCMD_QUEUE_DEBUG_ - if (player.cmdqueue.empty()) - player.missingticcmdcount++; - int num_cmds = SV_CalculateNumTiccmds(player); for (int i = 0; i < num_cmds && !player.cmdqueue.empty(); i++) @@ -3310,7 +3320,6 @@ void SV_ProcessPlayerCmd(player_t &player) } player.cmdqueue.pop(); // remove this tic from the queue after being processed - player.missingticcmdcount--; } } @@ -3579,7 +3588,11 @@ void SV_SpecPlayer(player_t &player, bool silent) P_SetSpectatorFlags(player); if (!silent) - SV_BroadcastPrintf(PRINT_HIGH, "%s became a spectator.\n", player.userinfo.netname.c_str()); + { + std::string status = SV_BuildKillsDeathsStatusString(player); + SV_BroadcastPrintf(PRINT_HIGH, "%s became a spectator.(%s)\n", + player.userinfo.netname.c_str(), status.c_str()); + } P_PlayerLeavesGame(&player); SV_UpdatePlayerQueuePositions(G_CanJoinGame, &player); diff --git a/server/src/sv_maplist.cpp b/server/src/sv_maplist.cpp index 06b63a5cc..e1baa2180 100644 --- a/server/src/sv_maplist.cpp +++ b/server/src/sv_maplist.cpp @@ -129,13 +129,9 @@ bool Maplist::insert(const size_t &position, maplist_entry_t &maplist_entry) { } } - // capitalize the map name and WAD file names + // capitalize the map names maplist_entry.map = StdStringToUpper(maplist_entry.map); - for (std::vector::iterator it = maplist_entry.wads.begin(); - it != maplist_entry.wads.end(); ++it) - *it = StdStringToUpper(*it); - // Puts the map into its proper place this->maplist.insert(this->maplist.begin() + position, maplist_entry); diff --git a/tools/upversion/upversion.ini b/tools/upversion/upversion.ini index b02d8018a..3bfa85d94 100644 --- a/tools/upversion/upversion.ini +++ b/tools/upversion/upversion.ini @@ -5,15 +5,15 @@ ; Existing and new versions of Odamex, in dotted-number format. ; Middle number only goes up to 25, last number only goes up to 9. -old_version=10.3.0 +old_version=10.4.0 new_version=11.0.0 ; Existing and new year ranges. Note that if these are the same, year ; replacement will be skipped entirely. Year ranges will not be updated ; in code comments. -old_year=2006-2022 -new_year=2006-2022 +old_year=2006-2023 +new_year=2006-2023 [files] diff --git a/wad/graphics/net.gif b/wad/graphics/net.gif index a89b51ac0..834705dbf 100644 Binary files a/wad/graphics/net.gif and b/wad/graphics/net.gif differ diff --git a/wad/lumps/_chexnfo.lmp b/wad/lumps/_chexnfo.lmp index 3817fc76a..e5e58109c 100644 --- a/wad/lumps/_chexnfo.lmp +++ b/wad/lumps/_chexnfo.lmp @@ -21,7 +21,7 @@ map E1M1 lookup "CHUSTR_E1M1" secretnext = "E1M9" sky1 = "SKY1" cluster = 1 - par = 30 + par = 120 music = "$MUSIC_E1M1" } @@ -33,7 +33,7 @@ map E1M2 lookup "CHUSTR_E1M2" secretnext = "E1M9" sky1 = "SKY1" cluster = 1 - par = 75 + par = 360 music = "$MUSIC_E1M2" } @@ -45,7 +45,7 @@ map E1M3 lookup "CHUSTR_E1M3" secretnext = "E1M9" sky1 = "SKY1" cluster = 1 - par = 120 + par = 480 music = "$MUSIC_E1M3" } @@ -57,7 +57,7 @@ map E1M4 lookup "CHUSTR_E1M4" secretnext = "E1M9" sky1 = "SKY1" cluster = 1 - par = 90 + par = 200 music = "$MUSIC_E1M4" } @@ -69,7 +69,7 @@ map E1M5 lookup "CHUSTR_E1M5" secretnext = "E1M9" sky1 = "SKY1" cluster = 1 - par = 165 + par = 360 music = "$MUSIC_E1M5" nointermission }