diff --git a/bin/windows/zmusic/arm64/zmusiclite.dll b/bin/windows/zmusic/arm64/zmusiclite.dll deleted file mode 100644 index 0d51f124035..00000000000 Binary files a/bin/windows/zmusic/arm64/zmusiclite.dll and /dev/null differ diff --git a/bin/windows/zmusic/include/zmusic.h b/bin/windows/zmusic/include/zmusic.h index 06c7ee39b66..90cb80e25ce 100644 --- a/bin/windows/zmusic/include/zmusic.h +++ b/bin/windows/zmusic/include/zmusic.h @@ -148,9 +148,10 @@ typedef enum EIntConfigKey_ zmusic_mod_autochip_scan_threshold, zmusic_snd_streambuffersize, - + zmusic_snd_mididevice, zmusic_snd_outputrate, + zmusic_mod_preferredplayer, NUM_ZMUSIC_INT_CONFIGS } EIntConfigKey; @@ -226,7 +227,7 @@ typedef struct ZMusicCallbacks_ { // Callbacks the client can install to capture messages from the backends // or to provide sound font data. - + void (*MessageFunc)(int severity, const char* msg); // The message callbacks are optional, without them the output goes to stdout. diff --git a/libraries/ZVulkan/src/glslang/glslang/Include/Common.h b/libraries/ZVulkan/src/glslang/glslang/Include/Common.h index 4f888ae1661..87ec92f279e 100644 --- a/libraries/ZVulkan/src/glslang/glslang/Include/Common.h +++ b/libraries/ZVulkan/src/glslang/glslang/Include/Common.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/ZWidget/CMakeLists.txt b/libraries/ZWidget/CMakeLists.txt index dd836cd6de4..68c048e22ee 100644 --- a/libraries/ZWidget/CMakeLists.txt +++ b/libraries/ZWidget/CMakeLists.txt @@ -120,6 +120,9 @@ include_directories(include include/zwidget src) if(WIN32) set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_WIN32_SOURCES}) add_definitions(-DUNICODE -D_UNICODE) + if(MINGW) + add_definitions(-DMINGW) + endif() elseif(APPLE) set(ZWIDGET_SOURCES ${ZWIDGET_SOURCES} ${ZWIDGET_COCOA_SOURCES}) set(ZWIDGET_LIBS ${CMAKE_DL_LIBS} -ldl) diff --git a/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp index 5c90e68e191..9065ccde4b6 100644 --- a/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp +++ b/libraries/ZWidget/src/widgets/lineedit/lineedit.cpp @@ -18,6 +18,8 @@ LineEdit::LineEdit(Widget* parent) : Widget(parent) LineEdit::~LineEdit() { + delete timer; + delete scroll_timer; } bool LineEdit::IsReadOnly() const diff --git a/libraries/ZWidget/src/window/win32/win32window.cpp b/libraries/ZWidget/src/window/win32/win32window.cpp index 3ba21698ab8..6ad09ef6041 100644 --- a/libraries/ZWidget/src/window/win32/win32window.cpp +++ b/libraries/ZWidget/src/window/win32/win32window.cpp @@ -28,6 +28,26 @@ #define RIDEV_INPUTSINK (0x100) #endif +#ifdef MINGW +// MinGW's library doesn't contain a thunk for DwmDefWindowProc, so we need to create our own + +BOOL DwmDefWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult ) +{ + typedef BOOL(* dwmdwp)(HWND, UINT, WPARAM, LPARAM, LRESULT* ); + BOOL result(FALSE); + HMODULE module = LoadLibrary( _T( "dwmapi.dll" ) ); + if( module ) { + dwmdwp proc = reinterpret_cast( GetProcAddress( module, "DwmDefWindowProc" ) ); + if( proc ) { + result = proc( hWnd, msg, wParam, lParam, plResult ); + } + FreeLibrary(module); + } + return result; +} + +#endif + static std::string from_utf16(const std::wstring& str) { if (str.empty()) return {}; @@ -61,7 +81,7 @@ Win32Window::Win32Window(DisplayWindowHost* windowHost) : WindowHost(windowHost) Windows.push_front(this); WindowsIterator = Windows.begin(); - WNDCLASSEX classdesc = {}; + WNDCLASSEXW classdesc = {}; classdesc.cbSize = sizeof(WNDCLASSEX); classdesc.hInstance = GetModuleHandle(0); classdesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS; @@ -74,7 +94,7 @@ Win32Window::Win32Window(DisplayWindowHost* windowHost) : WindowHost(windowHost) // WS_CAPTION shows the caption (yay! actually a flag that does what it says it does!) // WS_SYSMENU shows the min/max/close buttons // WS_THICKFRAME makes the window resizable - CreateWindowEx(WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME, L"ZWidgetWindow", L"", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this); + CreateWindowExW(WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME, L"ZWidgetWindow", L"", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 100, 100, 0, 0, GetModuleHandle(0), this); /* RAWINPUTDEVICE rid; @@ -387,6 +407,7 @@ void Win32Window::PresentBitmap(int width, int height, const uint32_t* pixels) LRESULT Win32Window::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam) { LPARAM result = 0; + if (DwmDefWindowProc(WindowHandle, msg, wparam, lparam, &result)) return result; diff --git a/libraries/ZWidget/src/window/window.cpp b/libraries/ZWidget/src/window/window.cpp index 234be61e436..b67b1a29677 100644 --- a/libraries/ZWidget/src/window/window.cpp +++ b/libraries/ZWidget/src/window/window.cpp @@ -2,7 +2,7 @@ #include "window/window.h" #include -#ifdef WIN32 +#ifdef _WIN32 #include "win32/win32window.h" diff --git a/libraries/bzip2/CMakeLists.txt b/libraries/bzip2/CMakeLists.txt index 846db25c265..c42b46592c9 100644 --- a/libraries/bzip2/CMakeLists.txt +++ b/libraries/bzip2/CMakeLists.txt @@ -13,4 +13,5 @@ add_library( bz2 STATIC decompress.c huffman.c randtable.c ) +link_libraries("-static") target_link_libraries( bz2 ) diff --git a/source/common/2d/v_2ddrawer.cpp b/source/common/2d/v_2ddrawer.cpp index 717d607c67c..10f4869b928 100644 --- a/source/common/2d/v_2ddrawer.cpp +++ b/source/common/2d/v_2ddrawer.cpp @@ -592,6 +592,10 @@ void DShape2D::OnDestroy() { void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms) { + // bail if shape is null (shouldn't happen but it might) + if (!shape) + ThrowAbortException(X_OTHER, "shape is null"); + // [MK] bail out if vertex/coord array sizes are mismatched if ( shape->mVertices.Size() != shape->mCoords.Size() ) ThrowAbortException(X_OTHER, "Mismatch in vertex/coord count: %u != %u", shape->mVertices.Size(), shape->mCoords.Size()); diff --git a/source/common/2d/v_drawtext.cpp b/source/common/2d/v_drawtext.cpp index 22cfb476ed8..56415a84fd2 100644 --- a/source/common/2d/v_drawtext.cpp +++ b/source/common/2d/v_drawtext.cpp @@ -380,7 +380,7 @@ void DrawText(F2DDrawer *drawer, FFont* font, int normalcolor, double x, double { return; } - const char *txt = (parms.localize && string[0] == '$') ? GStrings(&string[1]) : string; + const char *txt = (parms.localize && string[0] == '$') ? GStrings.GetString(&string[1]) : string; DrawTextCommon(drawer, font, normalcolor, x, y, (const uint8_t*)string, parms); } @@ -419,7 +419,7 @@ void DrawText(F2DDrawer *drawer, FFont *font, int normalcolor, double x, double { return; } - const char *txt = (parms.localize && string[0] == '$') ? GStrings(&string[1]) : string.GetChars(); + const char *txt = (parms.localize && string[0] == '$') ? GStrings.GetString(&string[1]) : string.GetChars(); DrawTextCommon(drawer, font, normalcolor, x, y, (uint8_t*)txt, parms); } diff --git a/source/common/audio/music/music.cpp b/source/common/audio/music/music.cpp index 13837e93e71..9664c54585c 100644 --- a/source/common/audio/music/music.cpp +++ b/source/common/audio/music/music.cpp @@ -74,6 +74,7 @@ float relative_volume = 1.f; float saved_relative_volume = 1.0f; // this could be used to implement an ACS FadeMusic function MusicVolumeMap MusicVolumes; MidiDeviceMap MidiDevices; +TMap ModPlayers; static int DefaultFindMusic(const char* fn) { @@ -93,6 +94,7 @@ EXTERN_CVAR(Float, fluid_gain) CVAR(Bool, mus_calcgain, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song. CVAR(Bool, mus_usereplaygain, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // changing this will only take effect for the next song. +CVAR(Int, mod_preferred_player, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)// toggle between libXMP and Dumb. Unlike other sound CVARs this is not directly mapped to ZMusic's config. // CODE -------------------------------------------------------------------- @@ -130,6 +132,24 @@ static FileReader OpenMusic(const char* musicname) return reader; } +bool MusicExists(const char* music_name) +{ + if (music_name == nullptr) + return false; + + if (FileExists(music_name)) + return true; + else + { + int lumpnum; + lumpnum = mus_cb.FindMusic(music_name); + if (lumpnum == -1) lumpnum = fileSystem.CheckNumForName(music_name, FileSys::ns_music); + if (lumpnum != -1 && fileSystem.FileLength(lumpnum) != 0) + return true; + } + return false; +} + void S_SetMusicCallbacks(MusicCallbacks* cb) { mus_cb = *cb; @@ -751,6 +771,7 @@ bool S_ChangeMusic(const char* musicname, int order, bool looping, bool force) { int lumpnum = mus_cb.FindMusic(musicname); MidiDeviceSetting* devp = MidiDevices.CheckKey(lumpnum); + int* mplay = ModPlayers.CheckKey(lumpnum); auto volp = MusicVolumes.CheckKey(lumpnum); if (volp) @@ -763,6 +784,12 @@ bool S_ChangeMusic(const char* musicname, int order, bool looping, bool force) CheckReplayGain(musicname, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : ""); } auto mreader = GetMusicReader(reader); // this passes the file reader to the newly created wrapper. + int mod_player = mplay? *mplay : *mod_preferred_player; + int scratch; + + // This config var is only effective when opening a music stream so there's no need for active synchronization. Setting it here is sufficient. + // Ideally this should have been a parameter to ZMusic_OpenSong, but that would have necessitated an API break. + ChangeMusicSettingInt(zmusic_mod_preferredplayer, mus_playing.handle, mod_player, &scratch); mus_playing.handle = ZMusic_OpenSong(mreader, devp ? (EMidiDevice)devp->device : MDEV_DEFAULT, devp ? devp->args.GetChars() : ""); if (mus_playing.handle == nullptr) { diff --git a/source/common/audio/music/s_music.h b/source/common/audio/music/s_music.h index cddfd36d626..3c5a092ccbf 100644 --- a/source/common/audio/music/s_music.h +++ b/source/common/audio/music/s_music.h @@ -45,6 +45,9 @@ bool S_StartMusic (const char *music_name); // Start music using , and set whether looping bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false); +// Check if exists +bool MusicExists(const char* music_name); + void S_RestartMusic (); void S_MIDIDeviceChanged(int newdev); @@ -71,6 +74,7 @@ struct MidiDeviceSetting typedef TMap MidiDeviceMap; typedef TMap MusicVolumeMap; +extern TMap ModPlayers; extern MidiDeviceMap MidiDevices; extern MusicVolumeMap MusicVolumes; extern MusicCallbacks mus_cb; diff --git a/source/common/audio/sound/oalsound.cpp b/source/common/audio/sound/oalsound.cpp index 511a89fbd0e..8b20fb9c100 100644 --- a/source/common/audio/sound/oalsound.cpp +++ b/source/common/audio/sound/oalsound.cpp @@ -598,6 +598,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); ALC.SOFT_HRTF = !!alcIsExtensionPresent(Device, "ALC_SOFT_HRTF"); ALC.SOFT_pause_device = !!alcIsExtensionPresent(Device, "ALC_SOFT_pause_device"); + ALC.SOFT_output_limiter = !!alcIsExtensionPresent(Device, "ALC_SOFT_output_limiter"); const ALCchar *current = NULL; if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) @@ -634,6 +635,11 @@ OpenALSoundRenderer::OpenALSoundRenderer() else attribs.Push(ALC_DONT_CARE_SOFT); } + if(ALC.SOFT_output_limiter) + { + attribs.Push(ALC_OUTPUT_LIMITER_SOFT); + attribs.Push(ALC_TRUE); + } // Other attribs..? attribs.Push(0); diff --git a/source/common/console/c_enginecmds.cpp b/source/common/console/c_enginecmds.cpp index 38e64ab46a5..d6a2e027e24 100644 --- a/source/common/console/c_enginecmds.cpp +++ b/source/common/console/c_enginecmds.cpp @@ -80,7 +80,7 @@ CCMD (print) Printf ("print : Print a string from the string table\n"); return; } - const char *str = GStrings[argv[1]]; + const char *str = GStrings.CheckString(argv[1]); if (str == NULL) { Printf ("%s unknown\n", argv[1]); @@ -304,7 +304,7 @@ CCMD(printlocalized) return; } } - Printf("%s\n", GStrings(argv[1])); + Printf("%s\n", GStrings.GetString(argv[1])); } } diff --git a/source/common/engine/i_interface.cpp b/source/common/engine/i_interface.cpp index 580dde407c2..dfedbe8eecd 100644 --- a/source/common/engine/i_interface.cpp +++ b/source/common/engine/i_interface.cpp @@ -4,8 +4,15 @@ #include "startupinfo.h" #include "c_cvars.h" #include "gstrings.h" +#include "version.h" -static_assert(sizeof(void*) == 8, "32 builds are not supported"); +static_assert(sizeof(void*) == 8, + "Only LP64/LLP64 builds are officially supported. " + "Please do not attempt to build for other platforms; " + "even if the program succeeds in a MAP01 smoke test, " + "there are e.g. known visual artifacts " + " " + "that lead to a bad user experience."); // Some global engine variables taken out of the backend code. FStartupScreen* StartWindow; @@ -23,7 +30,7 @@ bool pauseext; FStartupInfo GameStartupInfo; -CVAR(Bool, queryiwad, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, queryiwad, QUERYIWADDEFAULT, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR(String, defaultiwad, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG); CVAR(Bool, vid_fps, false, 0) diff --git a/source/common/engine/i_interface.h b/source/common/engine/i_interface.h index ff35d62866e..4289bfeab77 100644 --- a/source/common/engine/i_interface.h +++ b/source/common/engine/i_interface.h @@ -31,7 +31,6 @@ struct SystemCallbacks FString(*GetPlayerName)(int i); bool (*DispatchEvent)(event_t* ev); bool (*CheckGame)(const char* nm); - int (*GetGender)(); void (*MenuClosed)(); bool (*CheckMenudefOption)(const char* opt); void (*ConsoleToggled)(int state); diff --git a/source/common/engine/i_net.cpp b/source/common/engine/i_net.cpp index 65dc60cb1a5..33b4c126711 100644 --- a/source/common/engine/i_net.cpp +++ b/source/common/engine/i_net.cpp @@ -903,11 +903,11 @@ bool JoinGame (int i) static int PrivateNetOf(in_addr in) { int addr = ntohl(in.s_addr); - if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0 + if ((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0 { return 0xC0A80000; } - else if ((addr & 0xFFF00000) == 0xAC100000) // 172.16.0.0 + else if ((addr & 0xFFFF0000) >= 0xAC100000 && (addr & 0xFFFF0000) <= 0xAC1F0000) // 172.16.0.0 - 172.31.0.0 { return 0xAC100000; } diff --git a/source/common/engine/m_joy.cpp b/source/common/engine/m_joy.cpp index a2ab71103cd..1e4b2f3e0ed 100644 --- a/source/common/engine/m_joy.cpp +++ b/source/common/engine/m_joy.cpp @@ -120,16 +120,30 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy) { return false; } + + assert(GameConfig); + value = GameConfig->GetValueForKey("Enabled"); - if (value != NULL) + if (value) { joy->SetEnabled((bool)atoi(value)); } + + if(joy->AllowsEnabledInBackground()) + { + value = GameConfig->GetValueForKey("EnabledInBackground"); + if (value) + { + joy->SetEnabledInBackground((bool)atoi(value)); + } + } + value = GameConfig->GetValueForKey("Sensitivity"); - if (value != NULL) + if (value) { joy->SetSensitivity((float)atof(value)); } + numaxes = joy->GetNumAxes(); for (int i = 0; i < numaxes; ++i) { @@ -137,21 +151,21 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy) mysnprintf(key + axislen, countof(key) - axislen, "deadzone"); value = GameConfig->GetValueForKey(key); - if (value != NULL) + if (value) { joy->SetAxisDeadZone(i, (float)atof(value)); } mysnprintf(key + axislen, countof(key) - axislen, "scale"); value = GameConfig->GetValueForKey(key); - if (value != NULL) + if (value) { joy->SetAxisScale(i, (float)atof(value)); } mysnprintf(key + axislen, countof(key) - axislen, "map"); value = GameConfig->GetValueForKey(key); - if (value != NULL) + if (value) { EJoyAxis gameaxis = (EJoyAxis)atoi(value); if (gameaxis < JOYAXIS_None || gameaxis >= NUM_JOYAXIS) @@ -185,6 +199,12 @@ void M_SaveJoystickConfig(IJoystickConfig *joy) { GameConfig->SetValueForKey("Enabled", "0"); } + + if (!joy->AllowsEnabledInBackground() && joy->GetEnabledInBackground()) + { + GameConfig->SetValueForKey("EnabledInBackground", "1"); + } + if (!joy->IsSensitivityDefault()) { mysnprintf(value, countof(value), "%g", joy->GetSensitivity()); diff --git a/source/common/engine/m_joy.h b/source/common/engine/m_joy.h index 088d5bd6d3c..e8d9d3b1372 100644 --- a/source/common/engine/m_joy.h +++ b/source/common/engine/m_joy.h @@ -39,6 +39,10 @@ struct IJoystickConfig virtual bool GetEnabled() = 0; virtual void SetEnabled(bool enabled) = 0; + virtual bool AllowsEnabledInBackground() = 0; + virtual bool GetEnabledInBackground() = 0; + virtual void SetEnabledInBackground(bool enabled) = 0; + // Used by the saver to not save properties that are at their defaults. virtual bool IsSensitivityDefault() = 0; virtual bool IsAxisDeadZoneDefault(int axis) = 0; diff --git a/source/common/engine/namedef.h b/source/common/engine/namedef.h index 7f98beba083..13827382c0c 100644 --- a/source/common/engine/namedef.h +++ b/source/common/engine/namedef.h @@ -278,6 +278,8 @@ xx(BuiltinNameToClass) xx(BuiltinClassCast) xx(BuiltinFunctionPtrCast) xx(BuiltinFindTranslation) +xx(HandleDeprecatedFlags) +xx(CheckDeprecatedFlags) xx(ScreenJobRunner) xx(Action) diff --git a/source/common/engine/serializer.cpp b/source/common/engine/serializer.cpp index dcf93084287..97ded1adf8a 100644 --- a/source/common/engine/serializer.cpp +++ b/source/common/engine/serializer.cpp @@ -197,7 +197,10 @@ void FSerializer::Close() } if (mErrors > 0) { - I_Error("%d errors parsing JSON", mErrors); + if (mLumpName.IsNotEmpty()) + I_Error("%d errors parsing JSON lump %s", mErrors, mLumpName.GetChars()); + else + I_Error("%d errors parsing JSON", mErrors); } } @@ -331,6 +334,28 @@ bool FSerializer::HasObject(const char* name) // //========================================================================== +bool FSerializer::IsKeyNull(const char* name) +{ + if (isReading()) + { + auto val = r->FindKey(name); + if (val != nullptr) + { + if (val->IsNull()) + { + return true; + } + } + } + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + void FSerializer::EndObject() { if (isWriting()) diff --git a/source/common/engine/serializer.h b/source/common/engine/serializer.h index ae25853d948..40b6ab7062a 100644 --- a/source/common/engine/serializer.h +++ b/source/common/engine/serializer.h @@ -9,6 +9,7 @@ #include "palentry.h" #include "name.h" #include "dictionary.h" +#include "bonecomponents.h" extern bool save_full; @@ -93,6 +94,7 @@ class FSerializer void EndObject(); bool HasKey(const char* name); bool HasObject(const char* name); + bool IsKeyNull(const char* name); bool BeginArray(const char *name); void EndArray(); unsigned GetSize(const char *group); @@ -224,6 +226,7 @@ class FSerializer int mErrors = 0; int mObjectErrors = 0; + FString mLumpName; }; FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval); @@ -247,7 +250,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def); FSerializer &Serialize(FSerializer &arc, const char *key, struct ModelOverride &mo, struct ModelOverride *def); FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimModelOverride &mo, struct AnimModelOverride *def); -FSerializer &Serialize(FSerializer &arc, const char *key, struct AnimOverride &ao, struct AnimOverride *def); +FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnim &ao, ModelAnim *def); +FSerializer &Serialize(FSerializer &arc, const char *key, ModelAnimFrame &ao, ModelAnimFrame *def); FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, FTranslationID* defval); void SerializeFunctionPointer(FSerializer &arc, const char *key, FunctionPointerValue *&p); diff --git a/source/common/engine/stringtable.cpp b/source/common/engine/stringtable.cpp index 52d1f35437c..d9d739b57aa 100644 --- a/source/common/engine/stringtable.cpp +++ b/source/common/engine/stringtable.cpp @@ -47,29 +47,29 @@ // //========================================================================== -void FStringTable::LoadStrings (FileSys::FileSystem& fileSystem_, const char *language) +void FStringTable::LoadStrings (FileSys::FileSystem& fileSystem, const char *language) { int lastlump, lump; - fileSystem = &fileSystem_; allStrings.Clear(); lastlump = 0; - while ((lump = fileSystem->FindLump("LMACROS", &lastlump)) != -1) + while ((lump = fileSystem.FindLump("LMACROS", &lastlump)) != -1) { - readMacros(lump); + auto lumpdata = fileSystem.ReadFile(lump); + readMacros(lumpdata.string(), lumpdata.size()); } lastlump = 0; - while ((lump = fileSystem->FindLump ("LANGUAGE", &lastlump)) != -1) + while ((lump = fileSystem.FindLump ("LANGUAGE", &lastlump)) != -1) { - auto lumpdata = fileSystem->ReadFile(lump); + auto lumpdata = fileSystem.ReadFile(lump); + auto filenum = fileSystem.GetFileContainer(lump); - if (!ParseLanguageCSV(lump, lumpdata.string(), lumpdata.size())) - LoadLanguage (lump, lumpdata.string(), lumpdata.size()); + if (!ParseLanguageCSV(filenum, lumpdata.string(), lumpdata.size())) + LoadLanguage (filenum, lumpdata.string(), lumpdata.size()); } UpdateLanguage(language); allMacros.Clear(); - fileSystem = nullptr; } @@ -159,10 +159,9 @@ TArray> FStringTable::parseCSV(const char* buffer, size_t size) // //========================================================================== -bool FStringTable::readMacros(int lumpnum) +bool FStringTable::readMacros(const char* buffer, size_t size) { - auto lumpdata = fileSystem->ReadFile(lumpnum); - auto data = parseCSV(lumpdata.string(), lumpdata.size()); + auto data = parseCSV(buffer, size); allMacros.Clear(); for (unsigned i = 1; i < data.Size(); i++) @@ -187,7 +186,7 @@ bool FStringTable::readMacros(int lumpnum) // //========================================================================== -bool FStringTable::ParseLanguageCSV(int lumpnum, const char* buffer, size_t size) +bool FStringTable::ParseLanguageCSV(int filenum, const char* buffer, size_t size) { if (size < 11) return false; if (strnicmp(buffer, "default,", 8) && strnicmp(buffer, "identifier,", 11 )) return false; @@ -255,17 +254,18 @@ bool FStringTable::ParseLanguageCSV(int lumpnum, const char* buffer, size_t size } } + row[labelcol].StripLeftRight(); FName strName = row[labelcol].GetChars(); if (hasDefaultEntry) { - DeleteForLabel(lumpnum, strName); + DeleteForLabel(filenum, strName); } for (auto &langentry : langrows) { auto str = row[langentry.first]; if (str.Len() > 0) { - InsertString(lumpnum, langentry.second, strName, str); + InsertString(filenum, langentry.second, strName, str); } else { @@ -409,11 +409,10 @@ void FStringTable::DeleteString(int langid, FName label) // //========================================================================== -void FStringTable::DeleteForLabel(int lumpnum, FName label) +void FStringTable::DeleteForLabel(int filenum, FName label) { decltype(allStrings)::Iterator it(allStrings); decltype(allStrings)::Pair *pair; - auto filenum = fileSystem->GetFileContainer(lumpnum); while (it.NextPair(pair)) { @@ -432,10 +431,10 @@ void FStringTable::DeleteForLabel(int lumpnum, FName label) // //========================================================================== -void FStringTable::InsertString(int lumpnum, int langid, FName label, const FString &string) +void FStringTable::InsertString(int filenum, int langid, FName label, const FString &string) { const char *strlangid = (const char *)&langid; - TableElement te = { fileSystem->GetFileContainer(lumpnum), { string, string, string, string } }; + TableElement te = { filenum, { string, string, string, string } }; ptrdiff_t index; while ((index = te.strings[0].IndexOf("@[")) >= 0) { @@ -579,26 +578,33 @@ bool FStringTable::exists(const char *name) // //========================================================================== -const char *FStringTable::GetString(const char *name, uint32_t *langtable, int gender) const +const char *FStringTable::CheckString(const char *name, uint32_t *langtable, int gender) const { if (name == nullptr || *name == 0) { return nullptr; } - if (gender == -1 && sysCallbacks.GetGender) gender = sysCallbacks.GetGender(); + if (gender == -1) gender = defaultgender; if (gender < 0 || gender > 3) gender = 0; FName nm(name, true); if (nm != NAME_None) { + TableElement* bestItem = nullptr; for (auto map : currentLanguageSet) { auto item = map.second->CheckKey(nm); if (item) { + if (bestItem && bestItem->filenum > item->filenum) + { + // prioritize content from later files, even if the language doesn't fully match. + // This is mainly for Dehacked content. + continue; + } if (langtable) *langtable = map.first; auto c = item->strings[gender].GetChars(); if (c && *c == '$' && c[1] == '$') - return GetString(c + 2, langtable, gender); + c = CheckString(c + 2, langtable, gender); return c; } } @@ -608,7 +614,7 @@ const char *FStringTable::GetString(const char *name, uint32_t *langtable, int g //========================================================================== // -// Finds a string by name in a given language +// Finds a string by name in a given language without attempting any substitution // //========================================================================== @@ -618,7 +624,7 @@ const char *FStringTable::GetLanguageString(const char *name, uint32_t langtable { return nullptr; } - if (gender == -1 && sysCallbacks.GetGender) gender = sysCallbacks.GetGender(); + if (gender == -1) gender = defaultgender; if (gender < 0 || gender > 3) gender = 0; FName nm(name, true); if (nm != NAME_None) @@ -655,9 +661,9 @@ bool FStringTable::MatchDefaultString(const char *name, const char *content) con // //========================================================================== -const char *FStringTable::operator() (const char *name) const +const char *FStringTable::GetString(const char *name) const { - const char *str = operator[] (name); + const char *str = CheckString(name, nullptr); return str ? str : name; } diff --git a/source/common/engine/stringtable.h b/source/common/engine/stringtable.h index 0e0476353bb..181d8c7f399 100644 --- a/source/common/engine/stringtable.h +++ b/source/common/engine/stringtable.h @@ -95,32 +95,29 @@ class FStringTable const char *GetLanguageString(const char *name, uint32_t langtable, int gender = -1) const; bool MatchDefaultString(const char *name, const char *content) const; - const char *GetString(const char *name, uint32_t *langtable, int gender = -1) const; - const char *operator() (const char *name) const; // Never returns NULL - const char* operator() (const FString& name) const { return operator()(name.GetChars()); } - const char *operator[] (const char *name) const - { - return GetString(name, nullptr); - } + const char *CheckString(const char *name, uint32_t *langtable = nullptr, int gender = -1) const; + const char* GetString(const char* name) const; + const char* GetString(const FString& name) const { return GetString(name.GetChars()); } bool exists(const char *name); - void InsertString(int lumpnum, int langid, FName label, const FString& string); + void InsertString(int filenum, int langid, FName label, const FString& string); + void SetDefaultGender(int gender) { defaultgender = gender; } private: - FileSys::FileSystem* fileSystem; FString activeLanguage; StringMacroMap allMacros; LangMap allStrings; TArray> currentLanguageSet; + int defaultgender = 0; void LoadLanguage (int lumpnum, const char* buffer, size_t size); TArray> parseCSV(const char* buffer, size_t size); - bool ParseLanguageCSV(int lumpnum, const char* buffer, size_t size); + bool ParseLanguageCSV(int filenum, const char* buffer, size_t size); - bool readMacros(int lumpnum); + bool readMacros(const char* buffer, size_t size); void DeleteString(int langid, FName label); - void DeleteForLabel(int lumpnum, FName label); + void DeleteForLabel(int filenum, FName label); static size_t ProcessEscapes (char *str); public: @@ -138,7 +135,7 @@ class FStringTable const char* localize(const char* str) { - return *str == '$' ? operator()(str + 1) : str; + return *str == '$' ? GetString(str + 1) : str; } }; diff --git a/source/common/filesystem/source/critsec.cpp b/source/common/filesystem/source/critsec.cpp index 874ade79f9d..b8b8c552207 100644 --- a/source/common/filesystem/source/critsec.cpp +++ b/source/common/filesystem/source/critsec.cpp @@ -31,8 +31,6 @@ ** */ -namespace FileSys { - #ifdef _WIN32 #ifndef _WINNT_ @@ -40,6 +38,8 @@ namespace FileSys { #include #endif +namespace FileSys { + class FInternalCriticalSection { public: @@ -82,6 +82,8 @@ void LeaveCriticalSection(FInternalCriticalSection *c) #include +namespace FileSys { + class FInternalCriticalSection { public: diff --git a/source/common/filesystem/source/file_directory.cpp b/source/common/filesystem/source/file_directory.cpp index 0b9b7cd45ed..ca87fd9ea00 100644 --- a/source/common/filesystem/source/file_directory.cpp +++ b/source/common/filesystem/source/file_directory.cpp @@ -106,7 +106,7 @@ int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSy if (mBasePath == nullptr) { // extract the base path from the first entry to cover changes made in ScanDirectory. - auto full = entry.FilePath.find(entry.FilePathRel); + auto full = entry.FilePath.rfind(entry.FilePathRel); std::string path(entry.FilePath, 0, full); mBasePath = stringpool->Strdup(path.c_str()); } diff --git a/source/common/filesystem/source/fs_findfile.cpp b/source/common/filesystem/source/fs_findfile.cpp index 9bc32e75e81..e3d515ab160 100644 --- a/source/common/filesystem/source/fs_findfile.cpp +++ b/source/common/filesystem/source/fs_findfile.cpp @@ -35,6 +35,7 @@ #include "fs_findfile.h" #include #include +#include #ifndef _WIN32 @@ -45,8 +46,6 @@ #endif #include #include -#include - #include #endif diff --git a/source/common/fonts/v_text.cpp b/source/common/fonts/v_text.cpp index 7fd9bfb535e..267b412bdfe 100644 --- a/source/common/fonts/v_text.cpp +++ b/source/common/fonts/v_text.cpp @@ -271,12 +271,12 @@ bool CheckFontComplete(FFont* font) { // Also check if the SmallFont contains all characters this language needs. // If not, switch back to the original one. - return font->CanPrint(GStrings["REQUIRED_CHARACTERS"]); + return font->CanPrint(GStrings.CheckString("REQUIRED_CHARACTERS")); } void UpdateGenericUI(bool cvar) { - auto switchstr = GStrings["USE_GENERIC_FONT"]; + auto switchstr = GStrings.CheckString("USE_GENERIC_FONT"); generic_ui = (cvar || (switchstr && strtoll(switchstr, nullptr, 0))); if (!generic_ui) { @@ -311,7 +311,7 @@ void UpdateGenericUI(bool cvar) } } // Turkish i crap. What a mess, just to save two code points... :( - switchstr = GStrings["REQUIRED_CHARACTERS"]; + switchstr = GStrings.CheckString("REQUIRED_CHARACTERS"); special_i = switchstr && strstr(switchstr, "\xc4\xb0") != nullptr; // capital dotted i (İ). if (special_i) { diff --git a/source/common/menu/joystickmenu.cpp b/source/common/menu/joystickmenu.cpp index ae152b5f0ea..3d3e881b165 100644 --- a/source/common/menu/joystickmenu.cpp +++ b/source/common/menu/joystickmenu.cpp @@ -133,6 +133,26 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, SetEnabled) return 0; } +DEFINE_ACTION_FUNCTION(IJoystickConfig, AllowsEnabledInBackground) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_BOOL(self->AllowsEnabledInBackground()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, GetEnabledInBackground) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_BOOL(self->GetEnabledInBackground()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, SetEnabledInBackground) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + PARAM_BOOL(enabled); + self->SetEnabledInBackground(enabled); + return 0; +} + void UpdateJoystickMenu(IJoystickConfig *selected) { diff --git a/source/common/menu/savegamemanager.cpp b/source/common/menu/savegamemanager.cpp index 3f2243a870c..1350930210c 100644 --- a/source/common/menu/savegamemanager.cpp +++ b/source/common/menu/savegamemanager.cpp @@ -84,7 +84,7 @@ int FSavegameManagerBase::RemoveSaveSlot(int index) int listindex = SaveGames[0]->bNoDelete ? index - 1 : index; if (listindex < 0) return index; - remove(SaveGames[index]->Filename.GetChars()); + RemoveFile(SaveGames[index]->Filename.GetChars()); UnloadSaveData(); FSaveGameNode *file = SaveGames[index]; @@ -274,7 +274,7 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave) unsigned FSavegameManagerBase::ExtractSaveData(int index) { - FResourceFile *resf; + std::unique_ptr resf; FSaveGameNode *node; if (index == -1) @@ -295,7 +295,7 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index) (node = SaveGames[index]) && !node->Filename.IsEmpty() && !node->bOldVersion && - (resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr) + ( (resf.reset(FResourceFile::OpenResourceFile(node->Filename.GetChars(), true))), resf != nullptr)) { auto info = resf->FindEntry("info.json"); if (info < 0) @@ -316,7 +316,8 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index) auto pic = resf->FindEntry("savepic.png"); if (pic >= 0) { - FileReader picreader = resf->GetEntryReader(pic, FileSys::READER_NEW, FileSys::READERFLAG_SEEKABLE); + // This must use READER_CACHED or it will lock the savegame file. + FileReader picreader = resf->GetEntryReader(pic, FileSys::READER_CACHED, FileSys::READERFLAG_SEEKABLE); PNGHandle *png = M_VerifyPNG(picreader); if (png != nullptr) { @@ -329,7 +330,6 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index) } } } - delete resf; } return index; } @@ -470,7 +470,7 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame) void FSavegameManagerBase::InsertNewSaveNode() { - NewSaveNode.SaveTitle = GStrings("NEWSAVE"); + NewSaveNode.SaveTitle = GStrings.GetString("NEWSAVE"); NewSaveNode.bNoDelete = true; SaveGames.Insert(0, &NewSaveNode); } diff --git a/source/common/models/bonecomponents.h b/source/common/models/bonecomponents.h index 1e65389ea08..313b0832ee6 100644 --- a/source/common/models/bonecomponents.h +++ b/source/common/models/bonecomponents.h @@ -4,6 +4,8 @@ #include "TRS.h" #include "matrix.h" +#include + class DBoneComponents : public DObject { @@ -14,3 +16,41 @@ class DBoneComponents : public DObject DBoneComponents() = default; }; + +struct ModelAnimFrameInterp +{ + float inter = -1.0f; + int frame1 = -1; + int frame2 = -1; +}; + +struct ModelAnimFramePrecalculatedIQM +{ + TArray precalcBones; +}; + +enum EModelAnimFlags +{ + MODELANIM_NONE = 1 << 0, // no animation + MODELANIM_LOOP = 1 << 1, // animation loops, otherwise it stays on the last frame once it ends +}; + +struct ModelAnim +{ + int firstFrame = 0; + int lastFrame = 0; + int loopFrame = 0; + float framerate = 0; + double startFrame = 0; + int flags = MODELANIM_NONE; + double startTic = 0; // when the current animation started (changing framerates counts as restarting) (or when animation starts if interpolating from previous animation) + double switchOffset = 0; // when the animation was changed -- where to interpolate the switch from +}; + +static_assert(sizeof(ModelAnim) == sizeof(double) * 6); + +using ModelAnimFrame = std::variant; + +double getCurrentFrame(const ModelAnim &anim, double tic, bool *looped); +void calcFrame(const ModelAnim &anim, double tic, ModelAnimFrameInterp &inter); +void calcFrames(const ModelAnim &curAnim, double tic, ModelAnimFrameInterp &to, float &inter); diff --git a/source/common/models/model.h b/source/common/models/model.h index 7d5746e3317..2be1f54cca7 100644 --- a/source/common/models/model.h +++ b/source/common/models/model.h @@ -9,6 +9,8 @@ #include "tarray.h" #include "name.h" +#include "bonecomponents.h" + class DBoneComponents; class FModelRenderer; class FGameTexture; @@ -94,7 +96,10 @@ class FModel virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) = 0; virtual float getAspectFactor(float vscale) { return 1.f; } virtual const TArray* AttachAnimationData() { return nullptr; }; - virtual const TArray CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* bones, int index) { return {}; }; + + virtual ModelAnimFrame PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray* animationData, DBoneComponents* bones, int index) { return nullptr; }; + + virtual const TArray CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray* animationData, DBoneComponents* bones, int index) { return {}; }; void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; } IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; } diff --git a/source/common/models/model_iqm.h b/source/common/models/model_iqm.h index 464f5c13ad9..c16e8372a6e 100644 --- a/source/common/models/model_iqm.h +++ b/source/common/models/model_iqm.h @@ -120,7 +120,12 @@ class IQMModel : public FModel void BuildVertexBuffer(FModelRenderer* renderer) override; void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override; const TArray* AttachAnimationData() override; - const TArray CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* bones, int index) override; + + ModelAnimFrame PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray* animationData, DBoneComponents* bones, int index) override; + const TArray CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray* animationData, DBoneComponents* bones, int index) override; + + ModelAnimFramePrecalculatedIQM CalculateFrameIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray* animationData, DBoneComponents* bones, int index); + const TArray CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray* animationData, DBoneComponents* bones, int index); private: void LoadGeometry(); diff --git a/source/common/models/models_iqm.cpp b/source/common/models/models_iqm.cpp index 891a19647e6..1384debce2a 100644 --- a/source/common/models/models_iqm.cpp +++ b/source/common/models/models_iqm.cpp @@ -560,7 +560,108 @@ static TRS InterpolateBone(const TRS &from, const TRS &to, float t, float invt) return bone; } -const TArray IQMModel::CalculateBones(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray* animationData, DBoneComponents* boneComponentData, int index) +#include "printf.h" + + +ModelAnimFrame IQMModel::PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray* animationData, DBoneComponents* bones, int index) +{ + if(inter <= 0) + { + return CalculateFrameIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index); + } + else if(std::holds_alternative(from)) + { + auto &from_interp = std::get(from); + + return CalculateFrameIQM(from_interp.frame2, to.frame2, inter, from_interp.frame1, from_interp.inter, to.frame1, to.inter, nullptr, animationData, bones, index); + } + else if(std::holds_alternative(from)) + { + return CalculateFrameIQM(0, to.frame2, inter, 0, -1.f, to.frame1, to.inter, &std::get(from), animationData, bones, index); + } + else + { + return CalculateFrameIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index); + } +} + +const TArray IQMModel::CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray* animationData, DBoneComponents* bones, int index) +{ + if(inter <= 0) + { + return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index); + } + else if(std::holds_alternative(from)) + { + auto &from_interp = std::get(from); + + return CalculateBonesIQM(from_interp.frame2, to.frame2, inter, from_interp.frame1, from_interp.inter, to.frame1, to.inter, nullptr, animationData, bones, index); + } + else if(std::holds_alternative(from)) + { + return CalculateBonesIQM(0, to.frame2, inter, 0, -1.f, to.frame1, to.inter, &std::get(from), animationData, bones, index); + } + else + { + return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index); + } +} + +ModelAnimFramePrecalculatedIQM IQMModel::CalculateFrameIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray* animationData, DBoneComponents* boneComponentData, int index) +{ + ModelAnimFramePrecalculatedIQM out; + const TArray& animationFrames = animationData ? *animationData : TRSData; + + out.precalcBones.Resize(Joints.Size()); + + if (Joints.Size() > 0) + { + int numbones = Joints.SSize(); + + int offset1 = frame1 * numbones; + int offset2 = frame2 * numbones; + + int offset1_1 = frame1_prev * numbones; + int offset2_1 = frame2_prev * numbones; + + float invt = 1.0f - inter; + float invt1 = 1.0f - inter1_prev; + float invt2 = 1.0f - inter2_prev; + + for (int i = 0; i < numbones; i++) + { + TRS prev; + + if(precalculated) + { + prev = precalculated->precalcBones[i]; + } + else + { + if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0)) + { + prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1); + } + } + + TRS next; + + if(frame2 >= 0 && (frame2_prev >= 0 || inter2_prev < 0)) + { + next = inter2_prev <= 0 ? animationFrames[offset2 + i] : InterpolateBone(animationFrames[offset2_1 + i], animationFrames[offset2 + i], inter2_prev, invt2); + } + + if(frame1 >= 0 || inter < 0) + { + out.precalcBones[i] = inter < 0 ? animationFrames[offset1 + i] : InterpolateBone(prev, next , inter, invt); + } + } + } + + return out; +} + +const TArray IQMModel::CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray* animationData, DBoneComponents* boneComponentData, int index) { const TArray& animationFrames = animationData ? *animationData : TRSData; if (Joints.Size() > 0) @@ -597,9 +698,16 @@ const TArray IQMModel::CalculateBones(int frame1, int frame2, float in { TRS prev; - if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0)) + if(precalculated) + { + prev = precalculated->precalcBones[i]; + } + else { - prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1); + if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0)) + { + prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1); + } } TRS next; diff --git a/source/common/models/voxels.h b/source/common/models/voxels.h index 52299434a9f..fe583fd936f 100644 --- a/source/common/models/voxels.h +++ b/source/common/models/voxels.h @@ -73,6 +73,9 @@ struct FVoxelDef int VoxeldefIndex; // Needed by GZDoom double Scale; DAngle AngleOffset;// added to actor's angle to compensate for wrong-facing voxels + double xoffset; + double yoffset; + double zoffset; bool PitchFromMomentum; bool UseActorPitch; bool UseActorRoll; diff --git a/source/common/objects/dobject.cpp b/source/common/objects/dobject.cpp index b66029a5355..e124a975c7c 100644 --- a/source/common/objects/dobject.cpp +++ b/source/common/objects/dobject.cpp @@ -330,6 +330,7 @@ void DObject::Destroy () } OnDestroy(); ObjectFlags = (ObjectFlags & ~OF_Fixed) | OF_EuthanizeMe; + GC::WriteBarrier(this); } DEFINE_ACTION_FUNCTION(DObject, Destroy) @@ -622,3 +623,165 @@ void *DObject::ScriptVar(FName field, PType *type) // This is only for internal use so I_Error is fine. I_Error("Variable %s not found in %s\n", field.GetChars(), cls->TypeName.GetChars()); } + + +//========================================================================== +// +// +// +//========================================================================== + +void NetworkEntityManager::InitializeNetworkEntities() +{ + if (!s_netEntities.Size()) + s_netEntities.AppendFill(nullptr, NetIDStart); // Allocate the first 0-8 slots for the world and clients. +} + +// Clients need special handling since they always go in slots 1 - MAXPLAYERS. +void NetworkEntityManager::SetClientNetworkEntity(DObject* mo, const unsigned int playNum) +{ + // If resurrecting, we need to swap the corpse's position with the new pawn's + // position so it's no longer considered the client's body. + const uint32_t id = ClientNetIDStart + playNum; + DObject* const oldBody = s_netEntities[id]; + if (oldBody != nullptr) + { + if (oldBody == mo) + return; + + const uint32_t curID = mo->GetNetworkID(); + + s_netEntities[curID] = oldBody; + oldBody->ClearNetworkID(); + oldBody->SetNetworkID(curID); + + mo->ClearNetworkID(); + } + else + { + RemoveNetworkEntity(mo); // Free up its current id. + } + + s_netEntities[id] = mo; + mo->SetNetworkID(id); +} + +void NetworkEntityManager::AddNetworkEntity(DObject* const ent) +{ + if (ent->IsNetworked()) + return; + + // Slot 0 is reserved for the world. + // Clients go in the first 1 - MAXPLAYERS slots + // Everything else is first come first serve. + uint32_t id = WorldNetID; + if (s_openNetIDs.Size()) + { + s_openNetIDs.Pop(id); + s_netEntities[id] = ent; + } + else + { + id = s_netEntities.Push(ent); + } + + ent->SetNetworkID(id); +} + +void NetworkEntityManager::RemoveNetworkEntity(DObject* const ent) +{ + if (!ent->IsNetworked()) + return; + + const uint32_t id = ent->GetNetworkID(); + if (id == WorldNetID) + return; + + assert(s_netEntities[id] == ent); + if (id >= NetIDStart) + s_openNetIDs.Push(id); + s_netEntities[id] = nullptr; + ent->ClearNetworkID(); +} + +DObject* NetworkEntityManager::GetNetworkEntity(const uint32_t id) +{ + if (id == WorldNetID || id >= s_netEntities.Size()) + return nullptr; + + return s_netEntities[id]; +} + +//========================================================================== +// +// +// +//========================================================================== + +void DObject::SetNetworkID(const uint32_t id) +{ + if (!IsNetworked()) + { + ObjectFlags |= OF_Networked; + _networkID = id; + } +} + +void DObject::ClearNetworkID() +{ + ObjectFlags &= ~OF_Networked; + _networkID = NetworkEntityManager::WorldNetID; +} + +void DObject::EnableNetworking(const bool enable) +{ + if (enable) + NetworkEntityManager::AddNetworkEntity(this); + else + NetworkEntityManager::RemoveNetworkEntity(this); +} + +void DObject::RemoveFromNetwork() +{ + NetworkEntityManager::RemoveNetworkEntity(this); +} + +static unsigned int GetNetworkID(DObject* const self) +{ + return self->GetNetworkID(); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, GetNetworkID, GetNetworkID) +{ + PARAM_SELF_PROLOGUE(DObject); + + ACTION_RETURN_INT(self->GetNetworkID()); +} + +static void EnableNetworking(DObject* const self, const bool enable) +{ + self->EnableNetworking(enable); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, EnableNetworking, EnableNetworking) +{ + PARAM_SELF_PROLOGUE(DObject); + PARAM_BOOL(enable); + + self->EnableNetworking(enable); + return 0; +} + +static DObject* GetNetworkEntity(const unsigned int id) +{ + return NetworkEntityManager::GetNetworkEntity(id); +} + +DEFINE_ACTION_FUNCTION_NATIVE(DObject, GetNetworkEntity, GetNetworkEntity) +{ + PARAM_PROLOGUE; + PARAM_UINT(id); + + ACTION_RETURN_OBJECT(NetworkEntityManager::GetNetworkEntity(id)); +} + diff --git a/source/common/objects/dobject.h b/source/common/objects/dobject.h index f193379c11d..c0b6aecb57a 100644 --- a/source/common/objects/dobject.h +++ b/source/common/objects/dobject.h @@ -487,4 +487,25 @@ inline T *&DObject::PointerVar(FName field) return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle. } + +class NetworkEntityManager +{ +private: + inline static TArray s_netEntities = {}; + inline static TArray s_openNetIDs = {}; + +public: + NetworkEntityManager() = delete; + + static constexpr uint32_t WorldNetID = 0u; + static constexpr uint32_t ClientNetIDStart = 1u; + inline static uint32_t NetIDStart;// = MAXPLAYERS + 1u; + + static void InitializeNetworkEntities(); + static void SetClientNetworkEntity(DObject* mo, const unsigned int playNum); + static void AddNetworkEntity(DObject* const ent); + static void RemoveNetworkEntity(DObject* const ent); + static DObject* GetNetworkEntity(const uint32_t id); +}; + #endif //__DOBJECT_H__ diff --git a/source/common/platform/posix/cocoa/i_joystick.cpp b/source/common/platform/posix/cocoa/i_joystick.cpp index a2a27eaff08..44d1fb961b3 100644 --- a/source/common/platform/posix/cocoa/i_joystick.cpp +++ b/source/common/platform/posix/cocoa/i_joystick.cpp @@ -107,6 +107,10 @@ class IOKitJoystick : public IJoystickConfig virtual bool GetEnabled(); virtual void SetEnabled(bool enabled); + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + virtual void SetDefaultConfig(); virtual FString GetIdentifier(); diff --git a/source/common/platform/posix/cocoa/i_system.mm b/source/common/platform/posix/cocoa/i_system.mm index cef2d177b62..267bac31d9d 100644 --- a/source/common/platform/posix/cocoa/i_system.mm +++ b/source/common/platform/posix/cocoa/i_system.mm @@ -122,7 +122,7 @@ void I_ShowFatalError(const char *message) } -int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad, int&) +int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad, int&, FString&) { if (!showwin) { diff --git a/source/common/platform/posix/i_system.h b/source/common/platform/posix/i_system.h index 02acf0e3e4f..4d800d53b3b 100644 --- a/source/common/platform/posix/i_system.h +++ b/source/common/platform/posix/i_system.h @@ -38,7 +38,7 @@ void I_PrintStr (const char *str); void I_SetIWADInfo (); // Pick from multiple IWADs to use -int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad, int&); +int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad, int&, FString &); // [RH] Checks the registry for Steam's install path, so we can scan its // directories for IWADs if the user purchased any through Steam. diff --git a/source/common/platform/posix/sdl/i_joystick.cpp b/source/common/platform/posix/sdl/i_joystick.cpp index a7eb59568bd..42837ecba64 100644 --- a/source/common/platform/posix/sdl/i_joystick.cpp +++ b/source/common/platform/posix/sdl/i_joystick.cpp @@ -167,6 +167,10 @@ class SDLInputJoystick: public IJoystickConfig Enabled = enabled; } + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + FString GetIdentifier() { char id[16]; diff --git a/source/common/platform/posix/sdl/i_system.cpp b/source/common/platform/posix/sdl/i_system.cpp index 7fa41b2bc78..2c28368b005 100644 --- a/source/common/platform/posix/sdl/i_system.cpp +++ b/source/common/platform/posix/sdl/i_system.cpp @@ -298,7 +298,7 @@ void I_PrintStr(const char *cp) if (StartWindow) RedrawProgressBar(ProgressBarCurPos,ProgressBarMaxPos); } -int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags) +int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags, FString &extraArgs) { if (!showwin) { @@ -308,7 +308,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& #ifdef __APPLE__ return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad); #else - return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags); + return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, &extraArgs); #endif } diff --git a/source/common/platform/win32/i_dijoy.cpp b/source/common/platform/win32/i_dijoy.cpp index 492cbda1486..33c4574c97b 100644 --- a/source/common/platform/win32/i_dijoy.cpp +++ b/source/common/platform/win32/i_dijoy.cpp @@ -183,6 +183,10 @@ class FDInputJoystick : public FInputDevice, IJoystickConfig bool GetEnabled(); void SetEnabled(bool enabled); + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + void SetDefaultConfig(); FString GetIdentifier(); diff --git a/source/common/platform/win32/i_input.cpp b/source/common/platform/win32/i_input.cpp index cb945d61e14..45a74fe0c11 100644 --- a/source/common/platform/win32/i_input.cpp +++ b/source/common/platform/win32/i_input.cpp @@ -124,6 +124,9 @@ int BlockMouseMove; static bool EventHandlerResultForNativeMouse; +EXTERN_CVAR(Bool, i_pauseinbackground); + + CVAR (Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) static void I_CheckGUICapture () @@ -481,8 +484,8 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_ACTIVATEAPP: - AppActive = wParam == TRUE; - if (wParam) + AppActive = (wParam == TRUE); + if (wParam || !i_pauseinbackground) { SetPriorityClass (GetCurrentProcess (), INGAME_PRIORITY_CLASS); } diff --git a/source/common/platform/win32/i_main.cpp b/source/common/platform/win32/i_main.cpp index 6977055b7fe..acadc2dc823 100644 --- a/source/common/platform/win32/i_main.cpp +++ b/source/common/platform/win32/i_main.cpp @@ -158,7 +158,7 @@ int DoMain (HINSTANCE hInstance) Args->AppendArg(FString(wargv[i])); } - if (Args->CheckParm("-stdout")) + if (Args->CheckParm("-stdout") || Args->CheckParm("-norun")) { // As a GUI application, we don't normally get a console when we start. // If we were run from the shell and are on XP+, we can attach to its diff --git a/source/common/platform/win32/i_mouse.cpp b/source/common/platform/win32/i_mouse.cpp index 72dc3f335c1..e0050cc3ab9 100644 --- a/source/common/platform/win32/i_mouse.cpp +++ b/source/common/platform/win32/i_mouse.cpp @@ -267,7 +267,7 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult) } else { - if ((GetForegroundWindow() != mainwindow.GetHandle()) || preferNative || !use_mouse) + if (preferNative || !use_mouse) { want_native = true; } @@ -286,6 +286,10 @@ void I_CheckNativeMouse(bool preferNative, bool eventhandlerresult) if (!want_native && eventhandlerresult) want_native = true; + // The application should *never* grab the mouse cursor if its window doesn't have the focus. + if (GetForegroundWindow() != mainwindow.GetHandle()) + want_native = true; + //Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse); if (want_native != NativeMouse) diff --git a/source/common/platform/win32/i_rawps2.cpp b/source/common/platform/win32/i_rawps2.cpp index d406d61ea8d..2f89739bd7d 100644 --- a/source/common/platform/win32/i_rawps2.cpp +++ b/source/common/platform/win32/i_rawps2.cpp @@ -117,6 +117,10 @@ class FRawPS2Controller : public IJoystickConfig bool GetEnabled(); void SetEnabled(bool enabled); + bool AllowsEnabledInBackground() { return false; } + bool GetEnabledInBackground() { return false; } + void SetEnabledInBackground(bool enabled) {} + void SetDefaultConfig(); FString GetIdentifier(); diff --git a/source/common/platform/win32/i_system.cpp b/source/common/platform/win32/i_system.cpp index fe5fada533c..2c7eed495f8 100644 --- a/source/common/platform/win32/i_system.cpp +++ b/source/common/platform/win32/i_system.cpp @@ -353,7 +353,7 @@ static void SetQueryIWad(HWND dialog) // //========================================================================== -int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags) +int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& autoloadflags, FString &extraArgs) { int vkey; if (stricmp(queryiwad_key, "shift") == 0) @@ -370,7 +370,7 @@ int I_PickIWad(WadStuff *wads, int numwads, bool showwin, int defaultiwad, int& } if (showwin || (vkey != 0 && GetAsyncKeyState(vkey))) { - return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags); + return LauncherWindow::ExecModal(wads, numwads, defaultiwad, &autoloadflags, extraArgs); } return defaultiwad; } diff --git a/source/common/platform/win32/i_system.h b/source/common/platform/win32/i_system.h index 9d360b55abc..b70efb78b53 100644 --- a/source/common/platform/win32/i_system.h +++ b/source/common/platform/win32/i_system.h @@ -38,7 +38,7 @@ void I_PrintStr (const char *cp); void I_SetIWADInfo (); // Pick from multiple IWADs to use -int I_PickIWad(WadStuff* wads, int numwads, bool queryiwad, int defaultiwad, int& autoloadflags); +int I_PickIWad(WadStuff* wads, int numwads, bool queryiwad, int defaultiwad, int& autoloadflags, FString &extraArgs); // The ini could not be saved at exit bool I_WriteIniFailed (const char* filename); diff --git a/source/common/platform/win32/i_xinput.cpp b/source/common/platform/win32/i_xinput.cpp index d1dc4364d80..0f3c1923782 100644 --- a/source/common/platform/win32/i_xinput.cpp +++ b/source/common/platform/win32/i_xinput.cpp @@ -65,6 +65,8 @@ #endif #endif +extern bool AppActive; + // TYPES ------------------------------------------------------------------- typedef DWORD (WINAPI *XInputGetStateType)(DWORD index, XINPUT_STATE *state); @@ -105,6 +107,10 @@ class FXInputController : public IJoystickConfig bool GetEnabled(); void SetEnabled(bool enabled); + bool AllowsEnabledInBackground() { return true; } + bool GetEnabledInBackground() { return EnabledInBackground; } + void SetEnabledInBackground(bool enabled) { EnabledInBackground = enabled; } + void SetDefaultConfig(); FString GetIdentifier(); @@ -142,6 +148,7 @@ class FXInputController : public IJoystickConfig int LastButtons; bool Connected; bool Enabled; + bool EnabledInBackground; void Attached(); void Detached(); @@ -744,7 +751,10 @@ void FXInputManager::ProcessInput() { for (int i = 0; i < XUSER_MAX_COUNT; ++i) { - Devices[i]->ProcessInput(); + if(AppActive || Devices[i]->GetEnabledInBackground()) + { + Devices[i]->ProcessInput(); + } } } diff --git a/source/common/rendering/gl_load/gl_load.c b/source/common/rendering/gl_load/gl_load.c index 14aba7a702d..d5ba4e49fef 100644 --- a/source/common/rendering/gl_load/gl_load.c +++ b/source/common/rendering/gl_load/gl_load.c @@ -76,7 +76,7 @@ static void CheckOpenGL(void) { if (opengl32dll == 0) { - opengl32dll = LoadLibrary(L"OpenGL32.DLL"); + opengl32dll = LoadLibraryA("OpenGL32.DLL"); if (opengl32dll != 0) { createcontext = (HGLRC(WINAPI*)(HDC)) GetProcAddress(opengl32dll, "wglCreateContext"); diff --git a/source/common/rendering/hwrenderer/data/hw_cvars.h b/source/common/rendering/hwrenderer/data/hw_cvars.h index cf23649799c..7f84ba09e26 100644 --- a/source/common/rendering/hwrenderer/data/hw_cvars.h +++ b/source/common/rendering/hwrenderer/data/hw_cvars.h @@ -54,3 +54,6 @@ EXTERN_CVAR(Int, gl_shadowmap_filter) EXTERN_CVAR(Bool, gl_brightfog) EXTERN_CVAR(Bool, gl_lightadditivesurfaces) EXTERN_CVAR(Bool, gl_notexturefill) + +EXTERN_CVAR(Bool, r_radarclipper) +EXTERN_CVAR(Bool, r_dithertransparency) diff --git a/source/common/rendering/hwrenderer/data/hw_renderstate.h b/source/common/rendering/hwrenderer/data/hw_renderstate.h index 05fd6bcbf1c..41e4b50a372 100644 --- a/source/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/source/common/rendering/hwrenderer/data/hw_renderstate.h @@ -25,7 +25,7 @@ enum ERenderEffect EFF_SPHEREMAP, EFF_BURN, EFF_STENCIL, - + EFF_DITHERTRANS, MAX_EFFECTS }; diff --git a/source/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp b/source/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp index 9049e5090ee..d32b09e2333 100644 --- a/source/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp +++ b/source/common/rendering/hwrenderer/data/hw_shaderpatcher.cpp @@ -299,6 +299,7 @@ const FEffectShader effectshaders[] = { "spheremap", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define SPHEREMAP\n#define NO_ALPHATEST\n" }, { "burn", "shaders/glsl/main.vp", "shaders/glsl/burn.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, { "stencil", "shaders/glsl/main.vp", "shaders/glsl/stencil.fp", nullptr, nullptr, "#define SIMPLE\n#define NO_ALPHATEST\n" }, + { "dithertrans", "shaders/glsl/main.vp", "shaders/glsl/main.fp", "shaders/glsl/func_normal.fp", "shaders/glsl/material_normal.fp", "#define NO_ALPHATEST\n#define DITHERTRANS\n" }, }; int DFrameBuffer::GetShaderCount() diff --git a/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp b/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp index c51ce2ee901..8cb3c94e5c0 100644 --- a/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp +++ b/source/common/rendering/hwrenderer/data/hw_vrmodes.cpp @@ -146,11 +146,27 @@ float VREyeInfo::getShift() const return vr_swap_eyes ? -res : res; } -VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio) const +VSMatrix VREyeInfo::GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const { VSMatrix result; - if (mShiftFactor == 0) + if (iso_ortho) // Orthographic projection for isometric viewpoint + { + double zNear = -3.0/fovRatio; // screen->GetZNear(); + double zFar = screen->GetZFar(); + + double fH = tan(DEG2RAD(fov) / 2) / fovRatio; + double fW = fH * aspectRatio * mScaleFactor; + double left = -fW; + double right = fW; + double bottom = -fH; + double top = fH; + + VSMatrix fmat(1); + fmat.ortho((float)left, (float)right, (float)bottom, (float)top, (float)zNear, (float)zFar); + return fmat; + } + else if (mShiftFactor == 0) { float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio))); result.perspective(fovy, aspectRatio, screen->GetZNear(), screen->GetZFar()); diff --git a/source/common/rendering/hwrenderer/data/hw_vrmodes.h b/source/common/rendering/hwrenderer/data/hw_vrmodes.h index 26c9fd211ee..98928152018 100644 --- a/source/common/rendering/hwrenderer/data/hw_vrmodes.h +++ b/source/common/rendering/hwrenderer/data/hw_vrmodes.h @@ -27,7 +27,7 @@ struct VREyeInfo float mShiftFactor; float mScaleFactor; - VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio) const; + VSMatrix GetProjection(float fov, float aspectRatio, float fovRatio, bool iso_ortho) const; DVector3 GetViewShift(float yaw) const; private: float getShift() const; diff --git a/source/common/scripting/backend/codegen.cpp b/source/common/scripting/backend/codegen.cpp index 8b3ee306a62..b14fb267cd6 100644 --- a/source/common/scripting/backend/codegen.cpp +++ b/source/common/scripting/backend/codegen.cpp @@ -2828,83 +2828,104 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) // Special case: Assignment to a bitfield. IsBitWrite = Base->GetBitValue(); + if (IsBitWrite >= 0x10000) + { + // internal flags - need more here + IsBitWrite &= 0xffff; + } return this; } ExpEmit FxAssign::Emit(VMFunctionBuilder *build) { - static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; - assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType()); + if (IsBitWrite < 64) + { + static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType()); - ExpEmit pointer = Base->Emit(build); - Address = pointer; + ExpEmit pointer = Base->Emit(build); + Address = pointer; - ExpEmit result; - bool intconst = false; - int intconstval = 0; + ExpEmit result; + bool intconst = false; + int intconstval = 0; - if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT) - { - intconst = true; - intconstval = static_cast(Right)->GetValue().GetInt(); - result.Konst = true; - result.RegType = REGT_INT; - } - else - { - result = Right->Emit(build); - } - assert(result.RegType <= REGT_TYPE); + if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT) + { + intconst = true; + intconstval = static_cast(Right)->GetValue().GetInt(); + result.Konst = true; + result.RegType = REGT_INT; + } + else + { + result = Right->Emit(build); + } + assert(result.RegType <= REGT_TYPE); - if (pointer.Target) - { - if (result.Konst) + if (pointer.Target) { - if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval); - else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); + if (result.Konst) + { + if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval); + else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); + } + else + { + build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum); + } } else { - build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum); + if (result.Konst) + { + ExpEmit temp(build, result.RegType); + if (intconst) build->EmitLoadInt(temp.RegNum, intconstval); + else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); + result.Free(build); + result = temp; + } + + if (IsBitWrite == -1) + { + build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + } + else + { + build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite); + } } - } - else - { - if (result.Konst) + + if (AddressRequested) { - ExpEmit temp(build, result.RegType); - if (intconst) build->EmitLoadInt(temp.RegNum, intconstval); - else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); result.Free(build); - result = temp; + return pointer; } - if (IsBitWrite == -1) - { - build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + pointer.Free(build); + + if (intconst) + { //fix int constant return for assignment + return Right->Emit(build); } else { - build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite); + return result; } - } - - if (AddressRequested) + else { - result.Free(build); - return pointer; - } + VMFunction* callfunc; + auto sym = FindBuiltinFunction(NAME_HandleDeprecatedFlags); - pointer.Free(build); + assert(sym); + callfunc = sym->Variants[0].Implementation; - if(intconst) - { //fix int constant return for assignment - return Right->Emit(build); - } - else - { - return result; + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, Base); + emitters.AddParameter(build, Right); + emitters.AddParameterIntConst(IsBitWrite - 64); + return emitters.EmitCall(build); } } @@ -2934,23 +2955,40 @@ FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx) ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) { - ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it - if (!pointer.Target) + if (Assignment->IsBitWrite < 64) { - ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount()); - if (Assignment->IsBitWrite != -1) + ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it + if (!pointer.Target) { - build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite); + ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount()); + if (Assignment->IsBitWrite == -1) + { + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + } + else + { + build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite); + } + return out; } else { - build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + return pointer; } - return out; } else { - return pointer; + VMFunction* callfunc; + auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags); + + assert(sym); + callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, Assignment->Base); + emitters.AddParameterIntConst(Assignment->IsBitWrite - 64); + emitters.AddReturn(REGT_INT); + return emitters.EmitCall(build); } } @@ -7728,56 +7766,73 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) { - ExpEmit obj = classx->Emit(build); - assert(obj.RegType == REGT_POINTER); - - if (obj.Konst) + if (membervar->BitValue < 64 || AddressRequested) { - // If the situation where we are dereferencing a constant - // pointer is common, then it would probably be worthwhile - // to add new opcodes for those. But as of right now, I - // don't expect it to be a particularly common case. - ExpEmit newobj(build, REGT_POINTER); - build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); - obj = newobj; - } + ExpEmit obj = classx->Emit(build); + assert(obj.RegType == REGT_POINTER); - if (membervar->Flags & VARF_Meta) - { - obj.Free(build); - ExpEmit meta(build, REGT_POINTER); - build->Emit(OP_META, meta.RegNum, obj.RegNum); - obj = meta; - } + if (obj.Konst) + { + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; + } - if (AddressRequested) - { - if (membervar->Offset == 0) + if (membervar->Flags & VARF_Meta) { - return obj; + obj.Free(build); + ExpEmit meta(build, REGT_POINTER); + build->Emit(OP_META, meta.RegNum, obj.RegNum); + obj = meta; } - obj.Free(build); - ExpEmit out(build, REGT_POINTER); - build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); - return out; - } - int offsetreg = build->GetConstantInt((int)membervar->Offset); - ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); + if (AddressRequested) + { + if (membervar->Offset == 0) + { + return obj; + } + obj.Free(build); + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset)); + return out; + } - if (membervar->BitValue == -1) - { - build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); + int offsetreg = build->GetConstantInt((int)membervar->Offset); + ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); + + if (membervar->BitValue == -1) + { + build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); + } + else + { + ExpEmit out(build, REGT_POINTER); + build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg); + build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue); + out.Free(build); + } + obj.Free(build); + return loc; } else { - ExpEmit out(build, REGT_POINTER); - build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg); - build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue); - out.Free(build); + VMFunction* callfunc; + auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags); + + assert(sym); + callfunc = sym->Variants[0].Implementation; + + FunctionCallEmitter emitters(callfunc); + emitters.AddParameter(build, classx); + emitters.AddParameterIntConst(membervar->BitValue - 64); + emitters.AddReturn(REGT_INT); + return emitters.EmitCall(build); } - obj.Free(build); - return loc; } @@ -9544,7 +9599,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) if(FnPtrCall) static_cast(ctx.Function->Variants[0].Implementation)->blockJit = true; - int implicit = Function->GetImplicitArgs(); + unsigned implicit = Function->GetImplicitArgs(); + + bool relaxed_named_arugments = (ctx.Version >= MakeVersion(4, 13)); if (!CheckAccessibility(ctx.Version)) { @@ -9576,21 +9633,128 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) CallingFunction = ctx.Function; if (ArgList.Size() > 0) { - if (argtypes.Size() == 0) + if ((argtypes.Size() == 0) || (argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size())) { ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); delete this; return nullptr; } + bool isvararg = (argtypes.Last() == nullptr); + + { + TDeletingArray OrderedArgs; + const unsigned count = (argtypes.Size() - implicit) - isvararg; + + OrderedArgs.Resize(count); + memset(OrderedArgs.Data(), 0, sizeof(FxExpression*) * count); + + unsigned index = 0; + unsigned n = ArgList.Size(); + + for(unsigned i = 0; i < n; i++) + { + if(ArgList[i]->ExprType == EFX_NamedNode) + { + if(FnPtrCall) + { + ScriptPosition.Message(MSG_ERROR, "Named arguments not supported in function pointer calls"); + delete this; + return nullptr; + } + else if((index >= count) && isvararg) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list."); + delete this; + return nullptr; + } + else + { + FName name = static_cast(ArgList[i])->name; + if(argnames[index + implicit] != name) + { + unsigned j; + + for (j = 0; j < count; j++) + { + if (argnames[j + implicit] == name) + { + if(!relaxed_named_arugments && !(argflags[j + implicit] & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); + } + else if(!relaxed_named_arugments && j < index) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars()); + } + + // i don't think this needs any further optimization? + // O(N^2) complexity technically but N isn't likely to be large, + // and the check itself is just an int comparison, so it should be fine + index = j; + + break; + } + } + + if(j == count) + { + ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars()); + delete this; + return nullptr; + } + } + else if(!relaxed_named_arugments && !(argflags[index + implicit] & VARF_Optional)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); + } + } + } + + if(index >= count) + { + if(isvararg) + { + OrderedArgs.Push(ArgList[i]); + ArgList[i] = nullptr; + index++; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + } + else + { + if(ArgList[i]->ExprType == EFX_NamedNode) + { + auto * node = static_cast(ArgList[i]); + OrderedArgs[index] = node->value; + node->value = nullptr; + } + else + { + OrderedArgs[index] = ArgList[i]; + } + ArgList[i] = nullptr; + index++; + } + } + + ArgList = std::move(OrderedArgs); + } + bool foundvarargs = false; PType * type = nullptr; int flag = 0; - if (argtypes.Size() > 0 && argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size()) + + int defaults_index = 0; + + for(unsigned i = 0; i < implicit; i++) { - ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars()); - delete this; - return nullptr; + defaults_index += argtypes[i]->GetRegCount(); } for (unsigned i = 0; i < ArgList.Size(); i++) @@ -9608,94 +9772,45 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) } assert(type != nullptr); - if (ArgList[i]->ExprType == EFX_NamedNode) + if(!foundvarargs) { - if(FnPtrCall) - { - ScriptPosition.Message(MSG_ERROR, "Named arguments not supported in function pointer calls"); - delete this; - return nullptr; - } - if (!(flag & VARF_Optional)) - { - ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument here - not all required arguments have been passed."); - delete this; - return nullptr; - } - if (foundvarargs) - { - ScriptPosition.Message(MSG_ERROR, "Cannot use a named argument in the varargs part of the parameter list."); - delete this; - return nullptr; - } - unsigned j; - bool done = false; - FName name = static_cast(ArgList[i])->name; - for (j = 0; j < argnames.Size() - implicit; j++) + if(ArgList[i] == nullptr) { - if (argnames[j + implicit] == name) + if(!(flag & VARF_Optional)) { - if (j < i) - { - ScriptPosition.Message(MSG_ERROR, "Named argument %s comes before current position in argument list.", name.GetChars()); - delete this; - return nullptr; - } - // copy the original argument into the list - auto old = static_cast(ArgList[i]); - ArgList[i] = old->value; - old->value = nullptr; - delete old; - // now fill the gap with constants created from the default list so that we got a full list of arguments. - int insert = j - i; - int skipdefs = 0; - // Defaults contain multiple entries for pointers so we need to calculate how much additional defaults we need to skip - for (unsigned k = 0; k < i + implicit; k++) - { - skipdefs += argtypes[k]->GetRegCount() - 1; - } - for (int k = 0; k < insert; k++) + ScriptPosition.Message(MSG_ERROR, "Required argument %s has not been passed in call to %s", argnames[i + implicit].GetChars(), Function->SymbolName.GetChars()); + delete this; + return nullptr; + } + + auto ntype = argtypes[i + implicit]; + // If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type. + if (argflags[i + implicit] & VARF_Ref) + { + assert(ntype->isPointer()); + ntype = TypeNullPtr; // the default of a reference type can only be a null pointer + } + if (ntype->GetRegCount() == 1) + { + ArgList[i] = new FxConstant(ntype, (*defaults)[defaults_index], ScriptPosition); + } + else + { + // Vectors need special treatment because they are not normal constants + FxConstant *cs[4] = { nullptr }; + for (int l = 0; l < ntype->GetRegCount(); l++) { - auto ntype = argtypes[i + k + implicit]; - // If this is a reference argument, the pointer type must be undone because the code below expects the pointed type as value type. - if (argflags[i + k + implicit] & VARF_Ref) - { - assert(ntype->isPointer()); - ntype = TypeNullPtr; // the default of a reference type can only be a null pointer - } - if (ntype->GetRegCount() == 1) - { - auto x = new FxConstant(ntype, (*defaults)[i + k + skipdefs + implicit], ScriptPosition); - ArgList.Insert(i + k, x); - } - else - { - // Vectors need special treatment because they are not normal constants - FxConstant *cs[4] = { nullptr }; - for (int l = 0; l < ntype->GetRegCount(); l++) - { - cs[l] = new FxConstant(TypeFloat64, (*defaults)[l + i + k + skipdefs + implicit], ScriptPosition); - } - FxExpression *x = new FxVectorValue(cs[0], cs[1], cs[2], cs[3], ScriptPosition); - ArgList.Insert(i + k, x); - skipdefs += ntype->GetRegCount() - 1; - } + cs[l] = new FxConstant(TypeFloat64, (*defaults)[l + defaults_index], ScriptPosition); } - done = true; - break; + ArgList[i] = new FxVectorValue(cs[0], cs[1], cs[2], cs[3], ScriptPosition); } } - if (!done) - { - ScriptPosition.Message(MSG_ERROR, "Named argument %s not found.", name.GetChars()); - delete this; - return nullptr; - } - // re-get the proper info for the inserted node. - type = argtypes[i + implicit]; - flag = argflags[i + implicit]; + + defaults_index += argtypes[i + implicit]->GetRegCount(); } + assert(ArgList[i]); + FxExpression *x = nullptr; if (foundvarargs && (Function->Variants[0].Flags & VARF_VarArg)) { diff --git a/source/common/scripting/core/types.cpp b/source/common/scripting/core/types.cpp index 8e13dcc521b..b70783f3e1e 100644 --- a/source/common/scripting/core/types.cpp +++ b/source/common/scripting/core/types.cpp @@ -330,7 +330,8 @@ void PType::StaticInit() TypeVoidPtr = NewPointer(TypeVoid, false); TypeRawFunction = new PPointer; - TypeRawFunction->mDescriptiveName = "Raw Function Pointer"; + TypeRawFunction->mDescriptiveName = "Raw Function Pointer"; + TypeTable.AddType(TypeRawFunction, NAME_None); TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true)); TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value. TypeStringStruct = NewStruct("Stringstruct", nullptr, true); diff --git a/source/common/scripting/interface/stringformat.cpp b/source/common/scripting/interface/stringformat.cpp index e43c1ae24e6..3d7a3c428e7 100644 --- a/source/common/scripting/interface/stringformat.cpp +++ b/source/common/scripting/interface/stringformat.cpp @@ -282,9 +282,9 @@ DEFINE_ACTION_FUNCTION(FStringStruct, DeleteLastCharacter) static void LocalizeString(const FString &label, bool prefixed, FString *result) { - if (!prefixed) *result = GStrings(label); + if (!prefixed) *result = GStrings.GetString(label); else if (label[0] != '$') *result = label; - else *result = GStrings(&label[1]); + else *result = GStrings.GetString(&label[1]); } DEFINE_ACTION_FUNCTION_NATIVE(FStringTable, Localize, LocalizeString) diff --git a/source/common/scripting/interface/vmnatives.cpp b/source/common/scripting/interface/vmnatives.cpp index 48425f64eba..2b57ceb25a3 100644 --- a/source/common/scripting/interface/vmnatives.cpp +++ b/source/common/scripting/interface/vmnatives.cpp @@ -670,7 +670,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetBottomAlignOffset, GetBottomAlignOffset) static int StringWidth(FFont *font, const FString &str, int localize) { - const char *txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars(); + const char *txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars(); return font->StringWidth(txt); } @@ -684,7 +684,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, StringWidth, StringWidth) static int GetMaxAscender(FFont* font, const FString& str, int localize) { - const char* txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars(); + const char* txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars(); return font->GetMaxAscender(txt); } @@ -698,7 +698,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetMaxAscender, GetMaxAscender) static int CanPrint(FFont *font, const FString &str, int localize) { - const char *txt = (localize && str[0] == '$') ? GStrings(&str[1]) : str.GetChars(); + const char *txt = (localize && str[0] == '$') ? GStrings.GetString(&str[1]) : str.GetChars(); return font->CanPrint(txt); } @@ -770,6 +770,26 @@ DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetDisplayTopOffset, GetDisplayTopOffset) ACTION_RETURN_FLOAT(GetDisplayTopOffset(self, code)); } +static int GetChar(FFont* font, int c) +{ + int texc = 0; + auto getch = font->GetChar(c, CR_UNDEFINED, nullptr); + if (getch) + texc = getch->GetID().GetIndex(); + return texc; +} + +DEFINE_ACTION_FUNCTION_NATIVE(FFont, GetChar, ::GetChar) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_INT(mchar); + + if (numret > 0) ret[0].SetInt(::GetChar(self, mchar)); + if (numret > 1) ret[1].SetInt(self->GetCharWidth(mchar)); + return min(2, numret); +} + + //========================================================================== // // file system @@ -1142,6 +1162,17 @@ DEFINE_ACTION_FUNCTION(_Console, PrintfEx) return 0; } +DEFINE_ACTION_FUNCTION(_Console, DebugPrintf) +{ + PARAM_PROLOGUE; + PARAM_INT(debugLevel); + PARAM_VA_POINTER(va_reginfo); + + FString s = FStringFormat(VM_ARGS_NAMES, 1); + DPrintf(debugLevel, "%s\n", s.GetChars()); + return 0; +} + static void StopAllSounds() { soundEngine->StopAllChannels(); diff --git a/source/common/startscreen/endoom.cpp b/source/common/startscreen/endoom.cpp index 4a7565dbc6b..6e8e7af353d 100644 --- a/source/common/startscreen/endoom.cpp +++ b/source/common/startscreen/endoom.cpp @@ -111,7 +111,7 @@ FEndoomScreen::FEndoomScreen(int loading_lump) StartupBitmap.Create(80 * 8, 26 * 16); // line 26 is for our own 'press any key to quit' message. DrawTextScreen(StartupBitmap, endoom_screen); ClearBlock(StartupBitmap, {0, 0, 0, 255}, 0, 25*16, 640, 16); - DrawString(StartupBitmap, 0, 25, GStrings("TXT_QUITENDOOM"), { 128, 128, 128 ,255}, { 0, 0, 0, 255}); + DrawString(StartupBitmap, 0, 25, GStrings.GetString("TXT_QUITENDOOM"), { 128, 128, 128 ,255}, { 0, 0, 0, 255}); lastUpdateTime = I_msTime(); // Does this screen need blinking? diff --git a/source/common/startscreen/startscreen.cpp b/source/common/startscreen/startscreen.cpp index 65d279bec00..ccca6d9069c 100644 --- a/source/common/startscreen/startscreen.cpp +++ b/source/common/startscreen/startscreen.cpp @@ -372,6 +372,13 @@ FStartScreen* GetGameStartScreen(int max_progress) return nullptr; } +FStartScreen::~FStartScreen() +{ + if (StartupTexture) delete StartupTexture; + if (HeaderTexture) delete HeaderTexture; + if (NetTexture) delete NetTexture; +} + //========================================================================== // // ST_Util_ClearBlock @@ -607,7 +614,7 @@ bool FStartScreen::NetInit(const char* message, int numplayers) { NetMaxPos = numplayers; NetCurPos = 0; - NetMessageString.Format("%s %s", message, GStrings("TXT_NET_PRESSESC")); + NetMessageString.Format("%s %s", message, GStrings.GetString("TXT_NET_PRESSESC")); NetProgress(1); // You always know about yourself return true; } diff --git a/source/common/startscreen/startscreen.h b/source/common/startscreen/startscreen.h index afac6c7594e..c90d092f954 100644 --- a/source/common/startscreen/startscreen.h +++ b/source/common/startscreen/startscreen.h @@ -70,7 +70,7 @@ class FStartScreen FGameTexture* NetTexture = nullptr; public: FStartScreen(int maxp) { MaxPos = maxp; } - virtual ~FStartScreen() = default; + virtual ~FStartScreen(); void Render(bool force = false); bool Progress(int); void NetProgress(int count); diff --git a/source/common/textures/firetexture.cpp b/source/common/textures/firetexture.cpp new file mode 100644 index 00000000000..4a89622f7f2 --- /dev/null +++ b/source/common/textures/firetexture.cpp @@ -0,0 +1,139 @@ +/* +** firetexture.cpp +** PSX/N64-style fire texture implementation +** +**--------------------------------------------------------------------------- +** Copyright Cacodemon345 2024 +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +/* Algorithm based on https://github.com/fabiensanglard/DoomFirePSX */ + +#include "bitmap.h" +#include "firetexture.h" +#include "m_random.h" +#include "imagehelpers.h" + +#include "engineerrors.h" + +static constexpr int32_t FIRESKY_W = 64; +static constexpr int32_t FIRESKY_H = 128; + +FireTexture::FireTexture() +{ + SetSize(FIRESKY_W, FIRESKY_H); + Image.Clear(); + Image.AppendFill(0, Width * Height); +} + +void FireTexture::SetPalette(TArray& colors) +{ + Palette.Clear(); + Palette.Append(colors); + + /* This shouldn't happen in any circumstances. */ + if (Palette.Size() > 256) + { + I_FatalError("Fire palette too big!"); + } + + for (unsigned int i = 0; i < Width; i++) { + Image[(Height - 1) * Width + i] = (uint8_t)(Palette.Size() - 1); + } +} + +void FireTexture::Update() +{ + for (unsigned int y = 1; y < Height; y++) + { + for (unsigned int x = 0; x < Width; x++) + { + uint8_t srcPixel = Image[y * Width + x]; + + if (srcPixel == 0) + { + Image[(y - 1) * Width + x] = 0; + } + else + { + int XRand = M_Random() & 3; + int destRand = M_Random() & 1; + + Image[(y - 1) * Width + ((x + 1 - XRand) % Width)] = srcPixel - destRand; + } + } + } +} + +FBitmap FireTexture::GetBgraBitmap(const PalEntry* remap, int* trans) +{ + FBitmap bitmap; + bitmap.Create(Width, Height); + uint32_t* pixels = (uint32_t*)bitmap.GetPixels(); + + for (unsigned int y = 0; y < Height; y++) + { + for (unsigned int x = 0; x < Width; x++) + { + pixels[y * Width + x] = Palette[Image[y * Width + x]]; + } + } + + return bitmap; +} + +TArray FireTexture::Get8BitPixels(bool alphatex) +{ + FBitmap bitmap = GetBgraBitmap(nullptr, nullptr); + const uint8_t* data = bitmap.GetPixels(); + + uint8_t* dest_p; + int dest_adv = Height; + int dest_rew = Width * Height - 1; + + TArray Pixels(Width * Height); + dest_p = Pixels.Data(); + + bool doalpha = alphatex; + // Convert the source image from row-major to column-major format and remap it + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + int b = *data++; + int g = *data++; + int r = *data++; + int a = *data++; + if (a < 128) *dest_p = 0; + else *dest_p = ImageHelpers::RGBToPalette(doalpha, r, g, b); + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + return Pixels; +} diff --git a/source/common/textures/firetexture.h b/source/common/textures/firetexture.h new file mode 100644 index 00000000000..3ea6d967d13 --- /dev/null +++ b/source/common/textures/firetexture.h @@ -0,0 +1,17 @@ +#pragma once + +#include "textures.h" + + +class FireTexture : public FTexture +{ + TArray Image; + TArray Palette; + +public: + FireTexture(); + void SetPalette(TArray& colors); + void Update(); + virtual FBitmap GetBgraBitmap(const PalEntry* remap, int* trans) override; + virtual TArray Get8BitPixels(bool alphatex) override; +}; \ No newline at end of file diff --git a/source/common/textures/image.cpp b/source/common/textures/image.cpp index 83f7450ebec..95ee7d23cc4 100644 --- a/source/common/textures/image.cpp +++ b/source/common/textures/image.cpp @@ -306,7 +306,8 @@ void FImageSource::EndPrecaching() void FImageSource::RegisterForPrecache(FImageSource *img, bool requiretruecolor) { - img->CollectForPrecache(precacheInfo, requiretruecolor); + if (img) + img->CollectForPrecache(precacheInfo, requiretruecolor); } //========================================================================== diff --git a/source/common/textures/texturemanager.cpp b/source/common/textures/texturemanager.cpp index 10a3d3367de..1173f61be05 100644 --- a/source/common/textures/texturemanager.cpp +++ b/source/common/textures/texturemanager.cpp @@ -378,7 +378,7 @@ FGameTexture *FTextureManager::FindGameTexture(const char *texname, ETextureType bool FTextureManager::OkForLocalization(FTextureID texnum, const char *substitute, int locmode) { uint32_t langtable = 0; - if (*substitute == '$') substitute = GStrings.GetString(substitute+1, &langtable); + if (*substitute == '$') substitute = GStrings.CheckString(substitute+1, &langtable); else return true; // String literals from the source data should never override graphics from the same definition. if (substitute == nullptr) return true; // The text does not exist. diff --git a/source/common/utility/cmdlib.cpp b/source/common/utility/cmdlib.cpp index 5933a91d558..3b8dc9981fb 100644 --- a/source/common/utility/cmdlib.cpp +++ b/source/common/utility/cmdlib.cpp @@ -593,6 +593,26 @@ void CreatePath(const char *fn) } #endif +void RemoveFile(const char* file) +{ +#ifndef _WIN32 + remove(file); +#else + auto wpath = WideString(file); + _wremove(wpath.c_str()); +#endif +} + +int RemoveDir(const char* file) +{ +#ifndef _WIN32 + return rmdir(file); +#else + auto wpath = WideString(file); + return _wrmdir(wpath.c_str()); +#endif +} + //========================================================================== // // strbin -- In-place version diff --git a/source/common/utility/cmdlib.h b/source/common/utility/cmdlib.h index df779a975a2..88027c1565a 100644 --- a/source/common/utility/cmdlib.h +++ b/source/common/utility/cmdlib.h @@ -71,6 +71,8 @@ int strbin (char *str); FString strbin1 (const char *start); void CreatePath(const char * fn); +void RemoveFile(const char* file); +int RemoveDir(const char* file); FString ExpandEnvVars(const char *searchpathstring); FString NicePath(const char *path); diff --git a/source/common/utility/m_argv.cpp b/source/common/utility/m_argv.cpp index b9b05c3e9b8..0e8946058dc 100644 --- a/source/common/utility/m_argv.cpp +++ b/source/common/utility/m_argv.cpp @@ -189,7 +189,7 @@ int FArgs::CheckParmList(const char *check, FString **strings, int start) const } for (i = ++parmat; i < Argv.Size(); ++i) { - if (Argv[i][0] == '-' || Argv[i][1] == '+') + if (Argv[i][0] == '-' || Argv[i][0] == '+') { break; } @@ -345,6 +345,114 @@ void FArgs::AppendArgs(int argc, const FString *argv) } } +//=========================================================================== +// +// FArgs :: AppendArgsString +// +// Adds extra args as a space-separated string, supporting simple quoting, and inserting -file args into the right place +// +//=========================================================================== + + +void FArgs::AppendArgsString(FString argv) +{ + auto file_index = Argv.Find("-file"); + auto files_end = file_index + 1; + + for (; files_end < Argv.Size() && Argv[files_end][0] != '-' && Argv[files_end][0] != '+'; ++files_end); + + if(file_index == Argv.Size()) + { + Argv.Push("-file"); + } + + bool inserting_file = true; + + argv.StripLeftRight(); + + size_t i = 0; + size_t lastSection = 0; + size_t lastStart = 0; + char lastQuoteType = 0; + + FString tmp; + bool has_tmp = false; + + for(i = 0; i < argv.Len(); i++) + { + if(argv[i] == ' ') + { + FString arg = tmp + argv.Mid(lastSection, i - lastSection); + + if(arg[0] == '-' || arg[0] == '+') inserting_file = false; + + if(inserting_file) + { + Argv.Insert(files_end++, arg); + } + else if(arg.Compare("-file") == 0) + { + inserting_file = true; + } + else + { + files_end++; + Argv.Insert(file_index++, arg); + } + + lastSection = i + 1; + tmp = ""; + has_tmp = false; + for(;(i + 1) < argv.Len() && argv[i + 1] == ' '; i++, lastSection++); + lastStart = i + 1; + } + else if(argv[i] == '\'' || argv[i] == '"') + { + lastQuoteType = argv[i]; + tmp += argv.Mid(lastSection, i - lastSection); + has_tmp = true; + bool wasSlash = false; + + for(i++; (argv[i] != lastQuoteType || wasSlash) && i < argv.Len(); i++) + { + if(i == '\\' && !wasSlash) + { + wasSlash = true; + } + else + { + tmp += argv[i]; + wasSlash = false; + } + } + lastSection = i + 1; + } + } + + if(lastSection != i) + { // ended on an unquoted section + FString arg = tmp + argv.Mid(lastSection); + if(inserting_file) + { + Argv.Insert(files_end, arg); + } + else if(arg.Compare("-file") != 0) + { + Argv.Insert(file_index, arg); + } + } + else if(has_tmp) + { // ended on a quote + if(inserting_file) + { + Argv.Insert(files_end, tmp); + } + else if(tmp.Compare("-file") != 0) + { + Argv.Insert(file_index, tmp); + } + } +} //=========================================================================== // // FArgs :: RemoveArg diff --git a/source/common/utility/m_argv.h b/source/common/utility/m_argv.h index 9537697038b..d12da9a5fc8 100644 --- a/source/common/utility/m_argv.h +++ b/source/common/utility/m_argv.h @@ -85,6 +85,7 @@ class FArgs void AppendArg(FString arg); void AppendArgs(int argc, const FString *argv); + void AppendArgsString(FString argv); void RemoveArg(int argindex); void RemoveArgs(const char *check); void SetArgs(int argc, char **argv); diff --git a/source/common/utility/m_bbox.h b/source/common/utility/m_bbox.h index f117c290b92..7f622a6ba9f 100644 --- a/source/common/utility/m_bbox.h +++ b/source/common/utility/m_bbox.h @@ -72,6 +72,13 @@ class FBoundingBox m_Box[BOXTOP] = pos.Y; } + bool CheckOverlap(const FBoundingBox &box2) + { + bool hori = (Left() > box2.Right()) || (Right() < box2.Left()); + bool vert = (Bottom() > box2.Top()) || (Top() < box2.Bottom()); + return !(hori || vert); // [DVR] For alternative space partition + } + inline double Top () const { return m_Box[BOXTOP]; } inline double Bottom () const { return m_Box[BOXBOTTOM]; } inline double Left () const { return m_Box[BOXLEFT]; } diff --git a/source/common/utility/tarray.h b/source/common/utility/tarray.h index bce3ba3ea1c..3445bd48409 100644 --- a/source/common/utility/tarray.h +++ b/source/common/utility/tarray.h @@ -919,6 +919,7 @@ class TDeletingArray : public TArray TDeletingArray(TDeletingArray &&other) : TArray(std::move(other)) {} TDeletingArray &operator=(TDeletingArray &&other) { + DeleteAndClear(); TArray::operator=(std::move(other)); return *this; } diff --git a/source/common/utility/vectors.h b/source/common/utility/vectors.h index 77e41d2a9e4..47eb597938f 100644 --- a/source/common/utility/vectors.h +++ b/source/common/utility/vectors.h @@ -1019,6 +1019,45 @@ struct TVector4 } }; +inline void ZeroSubnormalsF(double& num) +{ + if (fabs(num) < FLT_MIN) num = 0; +} + +inline void ZeroSubnormals(double& num) +{ + if (fabs(num) < DBL_MIN) num = 0; +} + +inline void ZeroSubnormals(float& num) +{ + if (fabsf(num) < FLT_MIN) num = 0; +} + +template +inline void ZeroSubnormals(TVector2& vec) +{ + ZeroSubnormals(vec.X); + ZeroSubnormals(vec.Y); +} + +template +inline void ZeroSubnormals(TVector3& vec) +{ + ZeroSubnormals(vec.X); + ZeroSubnormals(vec.Y); + ZeroSubnormals(vec.Z); +} + +template +inline void ZeroSubnormals(TVector4& vec) +{ + ZeroSubnormals(vec.X); + ZeroSubnormals(vec.Y); + ZeroSubnormals(vec.Z); + ZeroSubnormals(vec.W); +} + template struct TMatrix3x3 { diff --git a/source/common/utility/writezip.cpp b/source/common/utility/writezip.cpp index 2f3507e6f03..de89779c074 100644 --- a/source/common/utility/writezip.cpp +++ b/source/common/utility/writezip.cpp @@ -40,6 +40,7 @@ #include "m_swap.h" #include "w_zip.h" #include "fs_decompress.h" +#include "cmdlib.h" using FileSys::FCompressedBuffer; @@ -201,7 +202,7 @@ bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t con if (pos == -1) { delete f; - remove(filename); + RemoveFile(filename); return false; } positions.Push(pos); @@ -213,7 +214,7 @@ bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t con if (AppendCentralDirectory(f, content[i], dostime, positions[i]) < 0) { delete f; - remove(filename); + RemoveFile(filename); return false; } } @@ -230,7 +231,7 @@ bool WriteZip(const char* filename, const FCompressedBuffer* content, size_t con if (f->Write(&dirend, sizeof(dirend)) != sizeof(dirend)) { delete f; - remove(filename); + RemoveFile(filename); return false; } delete f; diff --git a/source/common/utility/zstring.cpp b/source/common/utility/zstring.cpp index ecd0dc7e63e..488c09eb6e8 100644 --- a/source/common/utility/zstring.cpp +++ b/source/common/utility/zstring.cpp @@ -1089,6 +1089,12 @@ octdigits = [0-7]; ("0" octdigits+ | "0" [xX] hexdigits+ | (digits \ '0') digits*) { return true; } [\000-\377] { return false; }*/ + + //FIX for "0" returning false, doesn't fix 0 with whitespace, but that isn't necessary for savegame loading, so it'll need to be fixed later + if(Len() == 1 && Chars[0] == '0') return true; + + + const char *YYCURSOR = Chars; char yych; diff --git a/source/common/utility/zstring.h b/source/common/utility/zstring.h index 93d67902152..28402771233 100644 --- a/source/common/utility/zstring.h +++ b/source/common/utility/zstring.h @@ -128,6 +128,7 @@ class FString FString (FString &&other) noexcept : Chars(other.Chars) { other.ResetToNull(); } FString (const char *copyStr); FString (const char *copyStr, size_t copyLen); + FString (const std::string &s) : FString(s.c_str(), s.length()) {} FString (char oneChar); FString(const TArray & source) : FString(source.Data(), source.Size()) {} FString(const TArray & source) : FString((char*)source.Data(), source.Size()) {} diff --git a/source/common/widgets/widgetresourcedata.cpp b/source/common/widgets/widgetresourcedata.cpp index 85ee3e2498e..13f1519324c 100644 --- a/source/common/widgets/widgetresourcedata.cpp +++ b/source/common/widgets/widgetresourcedata.cpp @@ -21,6 +21,7 @@ void InitWidgetResources(const char* filename) void CloseWidgetResources() { if (WidgetResources) delete WidgetResources; + WidgetResources = nullptr; } static std::vector LoadFile(const char* name) diff --git a/source/core/automap.cpp b/source/core/automap.cpp index 524c30d0a46..a60accd6c3c 100644 --- a/source/core/automap.cpp +++ b/source/core/automap.cpp @@ -87,7 +87,7 @@ CCMD(allmap) if (!CheckCheatmode(true, false)) { gFullMap = !gFullMap; - Printf("%s\n", GStrings(gFullMap ? "SHOW MAP: ON" : "SHOW MAP: OFF")); + Printf("%s\n", GStrings.GetString(gFullMap ? "SHOW MAP: ON" : "SHOW MAP: OFF")); } } @@ -105,7 +105,7 @@ CCMD(togglefollow) { am_followplayer = !am_followplayer; auto msg = quoteMgr.GetQuote(am_followplayer ? 84 : 83); - if (!msg || !*msg) msg = am_followplayer ? GStrings("FOLLOW MODE ON") : GStrings("FOLLOW MODE Off"); + if (!msg || !*msg) msg = am_followplayer ? GStrings.GetString("FOLLOW MODE ON") : GStrings.GetString("FOLLOW MODE Off"); Printf(PRINT_NOTIFY, "%s\n", msg); if (am_followplayer) follow.X = INT_MAX; } @@ -113,7 +113,7 @@ CCMD(togglefollow) CCMD(togglerotate) { am_rotate = !am_rotate; - auto msg = am_rotate ? GStrings("TXT_ROTATE_ON") : GStrings("TXT_ROTATE_OFF"); + auto msg = am_rotate ? GStrings.GetString("TXT_ROTATE_ON") : GStrings.GetString("TXT_ROTATE_OFF"); Printf(PRINT_NOTIFY, "%s\n", msg); } diff --git a/source/core/cheats.cpp b/source/core/cheats.cpp index 55173f29607..9c7e710ad8f 100644 --- a/source/core/cheats.cpp +++ b/source/core/cheats.cpp @@ -103,7 +103,7 @@ void genericCheat(int player, uint8_t** stream, bool skip) Printf(PRINT_NOTIFY, "%s\n", msg); else { - FString message = GStrings("TXT_X_CHEATS"); + FString message = GStrings.GetString("TXT_X_CHEATS"); //message.Substitute("%s", player->userinfo.GetName()); // fixme - make globally accessible Printf(PRINT_NOTIFY, "%s: %s\n", message.GetChars(), msg); } diff --git a/source/core/console/c_notifybuffer.cpp b/source/core/console/c_notifybuffer.cpp index 2b084c6f0b6..90528f42ad4 100644 --- a/source/core/console/c_notifybuffer.cpp +++ b/source/core/console/c_notifybuffer.cpp @@ -175,7 +175,7 @@ static bool printNative() // Blood originally uses its tiny font for the notify display which does not play along well with localization because it is too small, so for non-English switch to the text font. if (con_notify_advanced) return false; if (!isBlood()) return true; - auto p = GStrings["REQUIRED_CHARACTERS"]; + auto p = GStrings.CheckString("REQUIRED_CHARACTERS"); if (p && *p) return false; return true; } diff --git a/source/core/ct_chat.cpp b/source/core/ct_chat.cpp index 87833f24d86..396b154656e 100644 --- a/source/core/ct_chat.cpp +++ b/source/core/ct_chat.cpp @@ -226,7 +226,7 @@ void CT_Drawer (void) if (chatmodeon) { - FStringf prompt("%s ", GStrings("TXT_SAY")); + FStringf prompt("%s ", GStrings.GetString("TXT_SAY")); int x, scalex, y, promptwidth; @@ -356,7 +356,7 @@ static void ShoveChatStr (const char *str, uint8_t who) Net_WriteString(MakeUTF8(substBuff)); } #else - Printf("%s %s\n", GStrings("TXT_SAY"), str); + Printf("%s %s\n", GStrings.GetString("TXT_SAY"), str); #endif } } diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index 6f9c1792d2d..485f5a3f4da 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -194,11 +194,6 @@ CUSTOM_CVAR(Int, cl_gender, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) if (self < 0 || self > 3) self = 0; } -int StrTable_GetGender() -{ - return cl_gender; -} - bool validFilter(const char* str); extern int chatmodeon; @@ -600,7 +595,6 @@ int GameMain() nullptr, System_DispatchEvent, validFilter, - StrTable_GetGender, System_MenuClosed, nullptr, nullptr, @@ -829,7 +823,8 @@ static TArray SetupGame() if (autoloadbrightmaps) flags |= 4; if (autoloadwidescreen) flags |= 8; - pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick, flags); + FString extraArgs; + pick = I_PickIWad(&wads[0], (int)wads.Size(), queryiwad, pick, flags, extraArgs); if (pick >= 0) { disableautoload = !!(flags & 1); @@ -1620,7 +1615,7 @@ void TITLE_InformName(const char* newname) { LevelName = newname; if (newname[0] == '$') - LevelName = GStrings(newname + 1); + LevelName = GStrings.GetString(newname + 1); I_UpdateWindowTitle(); } diff --git a/source/core/gamecvars.cpp b/source/core/gamecvars.cpp index 737860d7d46..f0e0f4ed17b 100644 --- a/source/core/gamecvars.cpp +++ b/source/core/gamecvars.cpp @@ -235,7 +235,7 @@ CCMD(togglemouseaim) in_mousemode = !in_mousemode; if (!silentmouseaimtoggle) { - Printf(PRINT_MEDIUM|PRINT_NOTIFY, "%s\n", in_mousemode? GStrings("TXT_MOUSEAIMON") : GStrings("TXT_MOUSEAIMOFF")); + Printf(PRINT_MEDIUM|PRINT_NOTIFY, "%s\n", in_mousemode? GStrings.GetString("TXT_MOUSEAIMON") : GStrings.GetString("TXT_MOUSEAIMOFF")); } } diff --git a/source/core/mapinfo.h b/source/core/mapinfo.h index 27a7f06e334..67a4867c42e 100644 --- a/source/core/mapinfo.h +++ b/source/core/mapinfo.h @@ -157,7 +157,7 @@ struct MapRecord const char* LabelName() const { - if (flags & MI_USERMAP) return GStrings("MNU_USERMAP"); + if (flags & MI_USERMAP) return GStrings.GetString("MNU_USERMAP"); return labelName.GetChars(); } const char *DisplayName() const @@ -181,7 +181,7 @@ struct MapRecord const char* GetMessage(int num) { if (num < 0 || num>= MAX_MESSAGES) return ""; - return GStrings(messages[num]); + return GStrings.GetString(messages[num]); } void AddMessage(int num, const FString &msg) diff --git a/source/core/menu/razemenu.cpp b/source/core/menu/razemenu.cpp index 790e610580d..911653c7f91 100644 --- a/source/core/menu/razemenu.cpp +++ b/source/core/menu/razemenu.cpp @@ -98,7 +98,7 @@ static bool DoStartGame(FNewGameStartup& gs) if (isShareware() && (vol->flags & VF_SHAREWARELOCK)) { - M_StartMessage(GStrings("SHAREWARELOCK"), 1, NAME_None); + M_StartMessage(GStrings.GetString("SHAREWARELOCK"), 1, NAME_None); return false; } @@ -164,7 +164,7 @@ bool M_SetSpecialMenu(FName& menu, int param) if (!gi->CanSave()) { // cannot save outside the game. - M_StartMessage(GStrings("SAVEDEAD"), 1, NAME_None); + M_StartMessage(GStrings.GetString("SAVEDEAD"), 1, NAME_None); return true; } break; @@ -234,7 +234,7 @@ CCMD(menu_quit) M_StartControlPanel(true); FString EndString; - EndString << GStrings("CONFIRM_QUITMSG") << "\n\n" << GStrings("PRESSYN"); + EndString << GStrings.GetString("CONFIRM_QUITMSG") << "\n\n" << GStrings.GetString("PRESSYN"); DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, EndString.GetChars(), 0, false, NAME_None, []() { @@ -260,7 +260,7 @@ CCMD(menu_endgame) M_StartControlPanel(true); FString tempstring; - tempstring << GStrings("ENDGAME") << "\n\n" << GStrings("PRESSYN"); + tempstring << GStrings.GetString("ENDGAME") << "\n\n" << GStrings.GetString("PRESSYN"); DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring.GetChars(), 0, false, NAME_None, []() { STAT_Cancel(); @@ -305,7 +305,7 @@ CCMD(quicksave) return; } - FString tempstring = GStrings("QSPROMPT"); + FString tempstring = GStrings.GetString("QSPROMPT"); tempstring.Substitute("%s", slot->SaveTitle.GetChars()); M_StartControlPanel(true); @@ -329,7 +329,7 @@ CCMD(quickload) if (netgame) { M_StartControlPanel(true); - M_StartMessage(GStrings("QLOADNET"), 1); + M_StartMessage(GStrings.GetString("QLOADNET"), 1); return; } @@ -348,7 +348,7 @@ CCMD(quickload) G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); return; } - FString tempstring = GStrings("QLPROMPT"); + FString tempstring = GStrings.GetString("QLPROMPT"); tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars()); M_StartControlPanel(true); diff --git a/source/core/quotes.cpp b/source/core/quotes.cpp index 395914ee4ee..8014a8a650e 100644 --- a/source/core/quotes.cpp +++ b/source/core/quotes.cpp @@ -44,7 +44,7 @@ void Quotes::MakeStringLabel(FString "e) { // Only prepend a quote if the string is localizable. - if (quote.Len() > 0 && quote[0] != '$' && GStrings[quote.GetChars()]) quote.Insert(0, "$"); + if (quote.Len() > 0 && quote[0] != '$' && GStrings.CheckString(quote.GetChars())) quote.Insert(0, "$"); } void Quotes::InitializeQuote(int num, const char *text, bool fromscript) diff --git a/source/core/razefont.cpp b/source/core/razefont.cpp index 7d3421e6554..605a65816dc 100644 --- a/source/core/razefont.cpp +++ b/source/core/razefont.cpp @@ -189,8 +189,8 @@ FFont* PickBigFont(const char* txt) { if (generic_ui) return NewSmallFont; // Note: Support is incomplete. Translations do not exist anyway for most content. if (!OriginalBigFont || OriginalBigFont == BigFont) return BigFont; - if (txt && *txt == '$') txt = GStrings[txt + 1]; - if (!txt || !*txt) txt = GStrings["REQUIRED_CHARACTERS"]; + if (txt && *txt == '$') txt = GStrings.CheckString(txt + 1); + if (!txt || !*txt) txt = GStrings.CheckString("REQUIRED_CHARACTERS"); if (!txt || !*txt || BigFont->CanPrint(txt)) return BigFont; return OriginalBigFont; } @@ -212,8 +212,8 @@ FFont* PickSmallFont(const char* txt) { if (generic_ui) return NewSmallFont; // Note: Support is incomplete. Translations do not exist anyway for most content. if (!OriginalSmallFont || OriginalSmallFont == SmallFont) return SmallFont; - if (txt && *txt == '$') txt = GStrings[txt + 1]; - if (!txt || !*txt) txt = GStrings["REQUIRED_CHARACTERS"]; + if (txt && *txt == '$') txt = GStrings.CheckString(txt + 1); + if (!txt || !*txt) txt = GStrings.CheckString("REQUIRED_CHARACTERS"); if (!txt || !*txt || SmallFont->CanPrint(txt)) return SmallFont; return OriginalSmallFont; } diff --git a/source/core/rendering/hw_entrypoint.cpp b/source/core/rendering/hw_entrypoint.cpp index 4a456756609..42b740306d5 100644 --- a/source/core/rendering/hw_entrypoint.cpp +++ b/source/core/rendering/hw_entrypoint.cpp @@ -153,7 +153,7 @@ void RenderViewpoint(FRenderViewpoint& mainvp, IntRect* bounds, float fov, float di->Viewpoint.FieldOfView = FAngle::fromDeg(fov); // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) // Stereo mode specific perspective projection - di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); + di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio, false); // Stereo mode specific viewpoint adjustment if (eye.mShiftFactor != 0) diff --git a/source/core/savegamehelp.cpp b/source/core/savegamehelp.cpp index f7363d3ee98..a05952a6a32 100644 --- a/source/core/savegamehelp.cpp +++ b/source/core/savegamehelp.cpp @@ -291,7 +291,7 @@ static bool CheckSingleFile (const char *name, bool &printRequires, bool printwa { if (!printRequires) { - Printf ("%s:\n%s", GStrings("TXT_SAVEGAMENEEDS"), name); + Printf ("%s:\n%s", GStrings.GetString("TXT_SAVEGAMENEEDS"), name); } else { @@ -790,15 +790,15 @@ void G_SaveGame(const char* filename, const char* description) { if (sendsave || gameaction == ga_savegame) { - Printf("%s\n", GStrings("TXT_SAVEPENDING")); + Printf("%s\n", GStrings.GetString("TXT_SAVEPENDING")); } else if (gamestate != GS_LEVEL) { - Printf("%s\n", GStrings("TXT_NOTINLEVEL")); + Printf("%s\n", GStrings.GetString("TXT_NOTINLEVEL")); } else if (!gi->CanSave()) { - Printf("%s\n", GStrings("TXT_SPPLAYERDEAD")); + Printf("%s\n", GStrings.GetString("TXT_SPPLAYERDEAD")); } else { @@ -844,7 +844,7 @@ void G_DoSaveGame(bool ok4q, bool forceq, const char* fn, const char* desc) if (WriteSavegame(fn, desc)) { savegameManager.NotifyNewSave(fn, desc, ok4q, forceq); - Printf(PRINT_NOTIFY, "%s\n", GStrings("GGSAVED")); + Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("GGSAVED")); BackupSaveGame = fn; } } diff --git a/source/core/secrets.cpp b/source/core/secrets.cpp index 1bbebf0acd6..b440bfb1dfa 100644 --- a/source/core/secrets.cpp +++ b/source/core/secrets.cpp @@ -91,7 +91,7 @@ CCMD(secret) { FString levelname; auto cc = currentLevel->name.GetChars(); - if (*cc == '$') cc = GStrings[cc + 1]; + if (*cc == '$') cc = GStrings.CheckString(cc + 1); if (thislevel) levelname.Format("%s - %s", mapname, cc); else levelname = mapname; Printf(TEXTCOLOR_YELLOW "%s\n", levelname.GetChars()); diff --git a/source/core/version.h b/source/core/version.h index 5a50b37b58f..61bf61244df 100644 --- a/source/core/version.h +++ b/source/core/version.h @@ -60,6 +60,7 @@ const char *GetVersionString(); #define GAMENAME "Raze" #define WGAMENAME L"Raze" #define GAMENAMELOWERCASE "raze" +#define QUERYIWADDEFAULT true #define FORUM_URL "http://forum.zdoom.org/" #define BUGS_FORUM_URL "http://forum.zdoom.org/viewforum.php?f=340" #define ENGINERES_FILE GAMENAMELOWERCASE ".pk3" diff --git a/source/core/vmstubs.cpp b/source/core/vmstubs.cpp index dbad66e7791..683504532f5 100644 --- a/source/core/vmstubs.cpp +++ b/source/core/vmstubs.cpp @@ -5,18 +5,3 @@ bool ShouldAllowGameSpecificVirtual(FName name, unsigned index, PType* arg, PTyp { return false; } - -void DObject::EnableNetworking(const bool enable) -{ - return; -} - -void DObject::RemoveFromNetwork(void) -{ - return; -} - -void DObject::ClearNetworkID() -{ - return; -} \ No newline at end of file diff --git a/source/games/blood/src/eventq.cpp b/source/games/blood/src/eventq.cpp index ed6fe4f207c..75a7f3fde61 100644 --- a/source/games/blood/src/eventq.cpp +++ b/source/games/blood/src/eventq.cpp @@ -257,7 +257,7 @@ void evSend(EventObject& eob, int rxId, COMMAND_ID command, DBloodActor* initiat if (gGameOptions.nGameType == 0) { - viewSetMessage(GStrings(FStringf("TXTB_SECRET%d", Random(2))), nullptr, MESSAGE_PRIORITY_SECRET); + viewSetMessage(GStrings.GetString(FStringf("TXTB_SECRET%d", Random(2))), nullptr, MESSAGE_PRIORITY_SECRET); } } } diff --git a/source/games/blood/src/messages.cpp b/source/games/blood/src/messages.cpp index bb5f138d9e9..5c1d2375ea2 100644 --- a/source/games/blood/src/messages.cpp +++ b/source/games/blood/src/messages.cpp @@ -50,14 +50,14 @@ const char* SetGodMode(DBloodPlayer* pPlayer, bool god) { playerSetGodMode(pPlayer, god); bPlayerCheated = true; - return pPlayer->godMode ? GStrings("TXTB_GODMODE") : GStrings("TXTB_NOTGODMODE"); + return pPlayer->godMode ? GStrings.GetString("TXTB_GODMODE") : GStrings.GetString("TXTB_NOTGODMODE"); } const char* SetClipMode(bool noclip) { gNoClip = noclip; bPlayerCheated = true; - return gNoClip ? GStrings("TXTB_NOCLIP") : GStrings("TXTB_NOCLIPOFF"); + return gNoClip ? GStrings.GetString("TXTB_NOCLIP") : GStrings.GetString("TXTB_NOCLIPOFF"); } void packStuff(DBloodPlayer* pPlayer) @@ -82,13 +82,13 @@ void SetAmmo(DBloodPlayer* pPlayer, bool stat) { for (int i = 0; i < 12; i++) pPlayer->ammoCount[i] = gAmmoInfo[i].max; - viewSetMessage(GStrings("TXTB_FULLAMMO")); + viewSetMessage(GStrings.GetString("TXTB_FULLAMMO")); } else { for (int i = 0; i < 12; i++) pPlayer->ammoCount[i] = 0; - viewSetMessage(GStrings("TXTB_NOAMMO")); + viewSetMessage(GStrings.GetString("TXTB_NOAMMO")); } } @@ -100,7 +100,7 @@ void SetWeapons(DBloodPlayer* pPlayer, bool stat) } SetAmmo(pPlayer, stat); if (stat) - viewSetMessage(GStrings("TXTB_ALLWEAP")); + viewSetMessage(GStrings.GetString("TXTB_ALLWEAP")); else { if (!VanillaMode()) @@ -110,7 +110,7 @@ void SetWeapons(DBloodPlayer* pPlayer, bool stat) pPlayer->curWeapon = kWeapNone; pPlayer->nextWeapon = kWeapPitchFork; } - viewSetMessage(GStrings("TXTB_NOWEAP")); + viewSetMessage(GStrings.GetString("TXTB_NOWEAP")); } } @@ -119,12 +119,12 @@ void SetToys(DBloodPlayer* pPlayer, bool stat) if (stat) { packStuff(pPlayer); - viewSetMessage(GStrings("TXTB_FULLINV")); + viewSetMessage(GStrings.GetString("TXTB_FULLINV")); } else { packClear(pPlayer); - viewSetMessage(GStrings("TXTB_NOINV")); + viewSetMessage(GStrings.GetString("TXTB_NOINV")); } } @@ -133,12 +133,12 @@ void SetArmor(DBloodPlayer* pPlayer, bool stat) int nAmount; if (stat) { - viewSetMessage(GStrings("TXTB_FULLARM")); + viewSetMessage(GStrings.GetString("TXTB_FULLARM")); nAmount = 3200; } else { - viewSetMessage(GStrings("TXTB_NOARM")); + viewSetMessage(GStrings.GetString("TXTB_NOARM")); nAmount = 0; } for (int i = 0; i < 3; i++) @@ -150,27 +150,27 @@ void SetKeys(DBloodPlayer* pPlayer, bool stat) for (int i = 1; i <= 7; i++) pPlayer->hasKey[i] = stat; if (stat) - viewSetMessage(GStrings("TXTB_ALLKEYS")); + viewSetMessage(GStrings.GetString("TXTB_ALLKEYS")); else - viewSetMessage(GStrings("TXTB_NOKEYS")); + viewSetMessage(GStrings.GetString("TXTB_NOKEYS")); } void SetInfiniteAmmo(bool stat) { gInfiniteAmmo = stat; if (gInfiniteAmmo) - viewSetMessage(GStrings("TXTB_INFAMMO")); + viewSetMessage(GStrings.GetString("TXTB_INFAMMO")); else - viewSetMessage(GStrings("TXTB_LIMAMMO")); + viewSetMessage(GStrings.GetString("TXTB_LIMAMMO")); } void SetMap(bool stat) { gFullMap = stat; if (gFullMap) - viewSetMessage(GStrings("TXTB_ALLMAP")); + viewSetMessage(GStrings.GetString("TXTB_ALLMAP")); else - viewSetMessage(GStrings("TXTB_NOALLMAP")); + viewSetMessage(GStrings.GetString("TXTB_NOALLMAP")); } void SetWooMode(DBloodPlayer* pPlayer, bool stat) @@ -200,7 +200,7 @@ void ToggleBoots(DBloodPlayer* pPlayer) { if (powerupCheck(pPlayer, kPwUpJumpBoots)) { - viewSetMessage(GStrings("TXTB_NOJBOOTS")); + viewSetMessage(GStrings.GetString("TXTB_NOJBOOTS")); if (!VanillaMode()) { pPlayer->pwUpTime[kPwUpJumpBoots] = 0; @@ -210,7 +210,7 @@ void ToggleBoots(DBloodPlayer* pPlayer) } else { - viewSetMessage(GStrings("TXTB_JBOOTS")); + viewSetMessage(GStrings.GetString("TXTB_JBOOTS")); if (!VanillaMode()) pPlayer->pwUpTime[kPwUpJumpBoots] = gPowerUpInfo[kPwUpJumpBoots].bonusTime; powerupActivate(pPlayer, kPwUpJumpBoots); @@ -221,14 +221,14 @@ void ToggleInvisibility(DBloodPlayer* pPlayer) { if (powerupCheck(pPlayer, kPwUpShadowCloak)) { - viewSetMessage(GStrings("TXTB_VISIBLE")); + viewSetMessage(GStrings.GetString("TXTB_VISIBLE")); if (!VanillaMode()) pPlayer->pwUpTime[kPwUpShadowCloak] = 0; powerupDeactivate(pPlayer, kPwUpShadowCloak); } else { - viewSetMessage(GStrings("TXTB_INVISIBLE")); + viewSetMessage(GStrings.GetString("TXTB_INVISIBLE")); powerupActivate(pPlayer, kPwUpShadowCloak); } } @@ -237,14 +237,14 @@ void ToggleInvulnerability(DBloodPlayer* pPlayer) { if (powerupCheck(pPlayer, kPwUpDeathMask)) { - viewSetMessage(GStrings("TXTB_VULN")); + viewSetMessage(GStrings.GetString("TXTB_VULN")); if (!VanillaMode()) pPlayer->pwUpTime[kPwUpDeathMask] = 0; powerupDeactivate(pPlayer, kPwUpDeathMask); } else { - viewSetMessage(GStrings("TXTB_INVULN")); + viewSetMessage(GStrings.GetString("TXTB_INVULN")); powerupActivate(pPlayer, kPwUpDeathMask); } } @@ -253,14 +253,14 @@ void ToggleDelirium(DBloodPlayer* pPlayer) { if (powerupCheck(pPlayer, kPwUpDeliriumShroom)) { - viewSetMessage(GStrings("TXTB_NODELIR")); + viewSetMessage(GStrings.GetString("TXTB_NODELIR")); if (!VanillaMode()) pPlayer->pwUpTime[kPwUpDeliriumShroom] = 0; powerupDeactivate(pPlayer, kPwUpDeliriumShroom); } else { - viewSetMessage(GStrings("TXTB_DELIR")); + viewSetMessage(GStrings.GetString("TXTB_DELIR")); powerupActivate(pPlayer, kPwUpDeliriumShroom); } } @@ -323,18 +323,18 @@ const char* GameInterface::GenericCheat(int player, int cheat) break; case kCheatKevorkian: actDamageSprite(pPlayer->GetActor(), pPlayer->GetActor(), kDamageBullet, 8000); - return GStrings("TXTB_KEVORKIAN"); + return GStrings.GetString("TXTB_KEVORKIAN"); case kCheatMcGee: { if (!pPlayer->GetActor()->xspr.burnTime) evPostActor(pPlayer->GetActor(), 0, kCallbackFXFlameLick); actBurnSprite(pPlayer->GetActor(), pPlayer->GetActor(), 2400); - return GStrings("TXTB_FIRED"); + return GStrings.GetString("TXTB_FIRED"); } case kCheatEdmark: actDamageSprite(pPlayer->GetActor(), pPlayer->GetActor(), kDamageExplode, 8000); - return GStrings("TXTB_THEDAYS"); + return GStrings.GetString("TXTB_THEDAYS"); case kCheatKrueger: { @@ -343,7 +343,7 @@ const char* GameInterface::GenericCheat(int player, int cheat) if (!pPlayer->GetActor()->xspr.burnTime) evPostActor(pPlayer->GetActor(), 0, kCallbackFXFlameLick); actBurnSprite(pPlayer->GetActor(), pPlayer->GetActor(), 2400); - return GStrings("TXTB_RETARD"); + return GStrings.GetString("TXTB_RETARD"); } case kCheatSterno: pPlayer->blindEffect = 250; @@ -357,7 +357,7 @@ const char* GameInterface::GenericCheat(int player, int cheat) case kCheatClarice: for (int i = 0; i < 3; i++) pPlayer->armor[i] = 1600; - return GStrings("TXTB_HALFARMOR"); + return GStrings.GetString("TXTB_HALFARMOR"); case kCheatFrankenstein: pPlayer->packSlots[0].curAmount = 100; break; diff --git a/source/games/blood/src/player.cpp b/source/games/blood/src/player.cpp index bff8d2363eb..6e987bad410 100644 --- a/source/games/blood/src/player.cpp +++ b/source/games/blood/src/player.cpp @@ -1339,17 +1339,17 @@ void PickUp(DBloodPlayer* pPlayer, DBloodActor* actor) if (nType >= kItemBase && nType <= kItemMax) { pickedUp = PickupItem(pPlayer, actor); - if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_ITEM%02d", int(nType - kItemBase + 1))); + if (pickedUp && customMsg == -1) msg = GStrings.GetString(FStringf("TXTB_ITEM%02d", int(nType - kItemBase + 1))); } else if (nType >= kItemAmmoBase && nType < kItemAmmoMax) { pickedUp = PickupAmmo(pPlayer, actor); - if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_AMMO%02d", int(nType - kItemAmmoBase + 1))); + if (pickedUp && customMsg == -1) msg = GStrings.GetString(FStringf("TXTB_AMMO%02d", int(nType - kItemAmmoBase + 1))); } else if (nType >= kItemWeaponBase && nType < kItemWeaponMax) { pickedUp = PickupWeapon(pPlayer, actor); - if (pickedUp && customMsg == -1) msg = GStrings(FStringf("TXTB_WPN%02d", int(nType - kItemWeaponBase + 1))); + if (pickedUp && customMsg == -1) msg = GStrings.GetString(FStringf("TXTB_WPN%02d", int(nType - kItemWeaponBase + 1))); } if (!pickedUp) return; @@ -1618,7 +1618,7 @@ void ProcessInput(DBloodPlayer* pPlayer) int key = pXSector->Key; if (pXSector->locked && pPlayer->pnum == myconnectindex) { - viewSetMessage(GStrings("TXTB_LOCKED")); + viewSetMessage(GStrings.GetString("TXTB_LOCKED")); auto snd = 3062; if (sndCheckPlaying(snd)) sndStopSample(snd); @@ -1628,7 +1628,7 @@ void ProcessInput(DBloodPlayer* pPlayer) trTriggerSector(pSector, kCmdSpritePush); else if (pPlayer->pnum == myconnectindex) { - viewSetMessage(GStrings("TXTB_KEY")); + viewSetMessage(GStrings.GetString("TXTB_KEY")); auto snd = 3063; if (sndCheckPlaying(snd)) sndStopSample(snd); @@ -1643,7 +1643,7 @@ void ProcessInput(DBloodPlayer* pPlayer) int key = pXWall->key; if (pXWall->locked && pPlayer->pnum == myconnectindex) { - viewSetMessage(GStrings("TXTB_LOCKED")); + viewSetMessage(GStrings.GetString("TXTB_LOCKED")); auto snd = 3062; if (sndCheckPlaying(snd)) sndStopSample(snd); @@ -1653,7 +1653,7 @@ void ProcessInput(DBloodPlayer* pPlayer) trTriggerWall(pWall, kCmdWallPush); else if (pPlayer->pnum == myconnectindex) { - viewSetMessage(GStrings("TXTB_KEY")); + viewSetMessage(GStrings.GetString("TXTB_KEY")); auto snd = 3063; if (sndCheckPlaying(snd)) sndStopSample(snd); @@ -1671,7 +1671,7 @@ void ProcessInput(DBloodPlayer* pPlayer) trTriggerSprite(act, kCmdSpritePush); else if (pPlayer->pnum == myconnectindex) { - viewSetMessage(GStrings("TXTB_KEY")); + viewSetMessage(GStrings.GetString("TXTB_KEY")); sndStartSample(3063, 255, 2, 0); } break; @@ -1918,7 +1918,7 @@ void playerFrag(DBloodPlayer* pKiller, DBloodPlayer* pVictim) int nSound = gSuicide[nMessage].Kills; if (pVictim->pnum == myconnectindex && pVictim->handTime <= 0) { - strcpy(buffer, GStrings("TXTB_KILLSELF")); + strcpy(buffer, GStrings.GetString("TXTB_KILLSELF")); if (gGameOptions.nGameType > 0 && nSound >= 0) sndStartSample(nSound, 255, 2, 0); } @@ -2310,7 +2310,7 @@ void PlayerSurvive(int, DBloodActor* actor) { DBloodPlayer* pPlayer = getPlayer(actor->spr.type - kDudePlayer1); if (pPlayer->pnum == myconnectindex) - viewSetMessage(GStrings("TXT_LIVEAGAIM")); + viewSetMessage(GStrings.GetString("TXT_LIVEAGAIM")); else { snprintf(buffer, sizeof(buffer), "%s lives again!", PlayerName(pPlayer->pnum)); diff --git a/source/games/blood/src/view.cpp b/source/games/blood/src/view.cpp index 72f24ee26e3..69d0cb5a297 100644 --- a/source/games/blood/src/view.cpp +++ b/source/games/blood/src/view.cpp @@ -737,7 +737,7 @@ void viewDrawScreen(bool sceneonly) viewDrawAimedPlayerName(pPlayer); if (paused) { - auto text = GStrings("TXTB_PAUSED"); + auto text = GStrings.GetString("TXTB_PAUSED"); viewDrawText(PickBigFont(text), text, 160, 10, 0, 0, 1, 0); } else if (pPlayer->pnum != myconnectindex) diff --git a/source/games/duke/src/cheats.cpp b/source/games/duke/src/cheats.cpp index fcf6898d1a3..6fc2aaaf3ed 100644 --- a/source/games/duke/src/cheats.cpp +++ b/source/games/duke/src/cheats.cpp @@ -133,7 +133,7 @@ static const char * cheatMonsters() static char textbuf[64]; if (++actor_tog == 3) actor_tog = 0; static const char* s[] = { "OPTVAL_ON", "OPTVAL_OFF", "TXT_ON2" }; - mysnprintf(textbuf, 64, "%s: %s", GStrings("NETMNU_MONSTERS"), GStrings(s[actor_tog])); + mysnprintf(textbuf, 64, "%s: %s", GStrings.GetString("NETMNU_MONSTERS"), GStrings.GetString(s[actor_tog])); return textbuf; } diff --git a/source/games/duke/src/game_misc.cpp b/source/games/duke/src/game_misc.cpp index 724e361954d..7f3610faa07 100644 --- a/source/games/duke/src/game_misc.cpp +++ b/source/games/duke/src/game_misc.cpp @@ -282,7 +282,7 @@ void drawoverlays(double interpfrac) { double x = 160, y = 100; double scale = isRR() ? 0.4 : 1.; - const char* text = GStrings("Game Paused"); + const char* text = GStrings.GetString("Game Paused"); auto myfont = PickBigFont(text); x -= myfont->StringWidth(text) * 0.5 * scale; DrawText(twod, myfont, CR_UNTRANSLATED, x, y - 12, text, DTA_FullscreenScale, FSMode_Fit320x200, DTA_ScaleX, scale, DTA_ScaleY, scale, TAG_DONE); diff --git a/source/games/duke/src/gameexec.cpp b/source/games/duke/src/gameexec.cpp index 48cd26b0b48..e46e7af08d1 100644 --- a/source/games/duke/src/gameexec.cpp +++ b/source/games/duke/src/gameexec.cpp @@ -1874,7 +1874,7 @@ int ParseState::parse(void) case concmd_move: g_ac->counter=0; insptr++; - g_ac->curMove = &moves[*insptr >= 0 && *insptr < moves.Size() ? *insptr : 0]; + g_ac->curMove = &moves[*insptr >= 0 && *insptr < moves.SSize() ? *insptr : 0]; insptr++; g_ac->spr.hitag = *insptr; insptr++; diff --git a/source/games/duke/src/spawn.cpp b/source/games/duke/src/spawn.cpp index 9a083475fa3..ebbf07d16e3 100644 --- a/source/games/duke/src/spawn.cpp +++ b/source/games/duke/src/spawn.cpp @@ -88,7 +88,7 @@ static void initanimations(DDukeActor* act) act->actioncounter = act->curframe = 0; ndx = LookupMove(act->GetClass(), ainf->DefaultMove); - act->curMove = &moves[ndx >= 0 && ndx < moves.Size() ? ndx : 0]; + act->curMove = &moves[ndx >= 0 && ndx < moves.SSize() ? ndx : 0]; if (ainf->DefaultMoveflags && act->spr.hitag == 0) act->spr.hitag = ainf->DefaultMoveflags; } @@ -96,7 +96,7 @@ static void initanimations(DDukeActor* act) { auto sa = &ScriptCode[coninf->scriptaddress]; act->curAction = &actions[sa[1]]; - act->curMove = &moves[sa[2] >= 0 && sa[2] < moves.Size() ? sa[2] : 0]; + act->curMove = &moves[sa[2] >= 0 && sa[2] < moves.SSize() ? sa[2] : 0]; int s3 = sa[3]; if (s3 && act->spr.hitag == 0) act->spr.hitag = s3; diff --git a/source/games/duke/src/vmexports.cpp b/source/games/duke/src/vmexports.cpp index d02e6e2d5f3..d5287f25fbc 100644 --- a/source/games/duke/src/vmexports.cpp +++ b/source/games/duke/src/vmexports.cpp @@ -772,9 +772,9 @@ void Duke_SetAI(DDukeActor* self, int intname) auto ai = &ais[ndx]; assert(!(ai->move & 0x80000000)); assert(!(ai->action & 0x80000000)); - if (ai->move < 0 || ai->move >= moves.SSize()) ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Bad 'move' index"); + if (ai->move >= moves.Size()) ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Bad 'move' index"); self->curMove = &moves[ai->move]; - if (ai->action < 0 || ai->action >= actions.SSize()) ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Bad 'action' index"); + if (ai->action >= actions.Size()) ThrowAbortException(X_ARRAY_OUT_OF_BOUNDS, "Bad 'action' index"); self->curAction = &actions[ai->action]; self->spr.hitag = ai->moveflags; self->curAI = ai->name; diff --git a/source/games/exhumed/src/2d.cpp b/source/games/exhumed/src/2d.cpp index 62753c1566d..b0f4f603370 100644 --- a/source/games/exhumed/src/2d.cpp +++ b/source/games/exhumed/src/2d.cpp @@ -303,7 +303,7 @@ DEFINE_ACTION_FUNCTION(_Exhumed, DrawPlasma) void TextOverlay::Create(const FString& text, int pal) { lastclock = 0; - FString ttext = GStrings(text); + FString ttext = GStrings.GetString(text); font = PickSmallFont(ttext.GetChars()); screentext = ttext.Split("\n"); ComputeCinemaText(); @@ -329,7 +329,7 @@ void TextOverlay::ComputeCinemaText() void TextOverlay::ReadyCinemaText(const char* nVal) { - FString label = nVal[0] == '$'? GStrings(nVal +1) : nVal; + FString label = nVal[0] == '$'? GStrings.GetString(nVal +1) : nVal; Create(label, 0); } diff --git a/source/games/exhumed/src/cheats.cpp b/source/games/exhumed/src/cheats.cpp index bfea379e896..2314c6aaad8 100644 --- a/source/games/exhumed/src/cheats.cpp +++ b/source/games/exhumed/src/cheats.cpp @@ -64,7 +64,7 @@ static const char* GodCheat(DExhumedPlayer* const pPlayer, int state) } else pPlayer->invincibility = -state; - return GStrings(pPlayer->invincibility ? "TXT_EX_DEITYON" : "TXT_EX_DEITYOFF"); + return GStrings.GetString(pPlayer->invincibility ? "TXT_EX_DEITYON" : "TXT_EX_DEITYOFF"); } //--------------------------------------------------------------------------- @@ -78,12 +78,12 @@ static const char* SlipCheat() if (bSlipMode == false) { bSlipMode = true; - return GStrings("TXT_EX_SLIPON"); + return GStrings.GetString("TXT_EX_SLIPON"); } else { bSlipMode = false; - return GStrings("TXT_EX_SLIPOFF"); + return GStrings.GetString("TXT_EX_SLIPOFF"); } } @@ -132,13 +132,13 @@ static bool HollyCheat(cheatseq_t* c) static bool KimberlyCheat(cheatseq_t* c) { - Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_SWEETIE")); + Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_SWEETIE")); return true; } static bool LiteCheat(cheatseq_t* c) { - Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_FLASHES")); + Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_FLASHES")); bDoFlashes = !bDoFlashes; g_visibility = 1024 + 512 - g_visibility; // let there be light - for real! return true; @@ -157,11 +157,11 @@ static bool SnakeCheat(cheatseq_t* c) if (bSnakeCam == false) { bSnakeCam = true; - Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_SNAKEON")); + Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_SNAKEON")); } else { bSnakeCam = false; - Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_SNAKEOFF")); + Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_SNAKEOFF")); } } return true; @@ -175,7 +175,7 @@ static bool SnakeCheat(cheatseq_t* c) static bool SphereCheat(cheatseq_t* c) { - Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_FULLMAP")); + Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_FULLMAP")); gFullMap = !gFullMap; // only set the cheat flag so it can be toggled. bShowTowers = gFullMap; return true; @@ -257,17 +257,17 @@ static void cmd_Give(int player, uint8_t** stream, bool skip) if (buttons & kButtonCheatGuns) // LOBOCOP cheat { FillWeapons(pPlayer); - if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_WEAPONS")); + if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_WEAPONS")); } if (buttons & kButtonCheatKeys) // LOBOPICK cheat { pPlayer->keys = 0xFFFF; - if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_KEYS")); + if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_KEYS")); } if (buttons & kButtonCheatItems) // LOBOSWAG cheat { FillItems(pPlayer); - if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_ITEMS")); + if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings.GetString("TXT_EX_ITEMS")); } } diff --git a/source/games/exhumed/src/gameloop.cpp b/source/games/exhumed/src/gameloop.cpp index 6d54a10f688..ecb722bd47d 100644 --- a/source/games/exhumed/src/gameloop.cpp +++ b/source/games/exhumed/src/gameloop.cpp @@ -85,7 +85,7 @@ void GameInterface::Render() if (paused && !M_Active()) { - auto tex = GStrings("TXTB_PAUSED"); + auto tex = GStrings.GetString("TXTB_PAUSED"); auto font = PickSmallFont(tex); int nStringWidth = font->StringWidth(tex); DrawText(twod, font, CR_UNTRANSLATED, 160 - nStringWidth / 2, 100, tex, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE); diff --git a/source/games/exhumed/src/lighting.cpp b/source/games/exhumed/src/lighting.cpp index 250535b2e26..ee7692aefd0 100644 --- a/source/games/exhumed/src/lighting.cpp +++ b/source/games/exhumed/src/lighting.cpp @@ -805,7 +805,7 @@ void SetTorch(DExhumedPlayer* const pPlayer, int bTorchOnOff) } const char* buf = bTorch ? "TXT_EX_TORCHLIT" : "TXT_EX_TORCHOUT"; - StatusMessage(150, GStrings(buf)); + StatusMessage(150, GStrings.GetString(buf)); } //--------------------------------------------------------------------------- diff --git a/source/games/exhumed/src/object.cpp b/source/games/exhumed/src/object.cpp index a7898e0013e..96597ba5ae7 100644 --- a/source/games/exhumed/src/object.cpp +++ b/source/games/exhumed/src/object.cpp @@ -1741,11 +1741,11 @@ void ExplodeEnergyBlock(DExhumedActor* pActor) if (nEnergyTowers == 1) { runlist_ChangeChannel(nEnergyChan, nEnergyTowers); - StatusMessage(1000, GStrings("TXT_EX_TAKEOUT")); + StatusMessage(1000, GStrings.GetString("TXT_EX_TAKEOUT")); } else if (nEnergyTowers != 0) { - FString msg = GStrings("TXT_EX_TOWERSREMAIN"); + FString msg = GStrings.GetString("TXT_EX_TOWERSREMAIN"); msg.Substitute("%d", std::to_string(nEnergyTowers).c_str()); StatusMessage(500, msg.GetChars()); } diff --git a/source/games/exhumed/src/player.cpp b/source/games/exhumed/src/player.cpp index dacc616144f..1323e9f7624 100644 --- a/source/games/exhumed/src/player.cpp +++ b/source/games/exhumed/src/player.cpp @@ -491,7 +491,7 @@ static void pickupMessage(int no) if (no != -1) { FStringf label("TXT_EX_PICKUP%d", no + 1); - auto str = GStrings[label.GetChars()]; + auto str = GStrings.CheckString(label.GetChars()); if (str) Printf(PRINT_NOTIFY, "%s\n", str); } } @@ -1343,7 +1343,7 @@ static void doPlayerCounters(DExhumedPlayer* const pPlayer) pPlayer->nDouble--; if (pPlayer->nDouble == 150 && bConsolePlayer) - PlayAlert(GStrings("TXT_EX_WEAPONEX")); + PlayAlert(GStrings.GetString("TXT_EX_WEAPONEX")); } if (pPlayer->nInvisible > 0) @@ -1359,7 +1359,7 @@ static void doPlayerCounters(DExhumedPlayer* const pPlayer) } else if (pPlayer->nInvisible == 150 && bConsolePlayer) { - PlayAlert(GStrings("TXT_EX_INVISEX")); + PlayAlert(GStrings.GetString("TXT_EX_INVISEX")); } } @@ -1368,7 +1368,7 @@ static void doPlayerCounters(DExhumedPlayer* const pPlayer) pPlayer->invincibility--; if (pPlayer->invincibility == 150 && bConsolePlayer) - PlayAlert(GStrings("TXT_EX_INVINCEX")); + PlayAlert(GStrings.GetString("TXT_EX_INVINCEX")); } if (pPlayer->nMaskAmount > 0 && pPlayer->nHealth > 0) @@ -1376,7 +1376,7 @@ static void doPlayerCounters(DExhumedPlayer* const pPlayer) pPlayer->nMaskAmount--; if (pPlayer->nMaskAmount == 150 && bConsolePlayer) - PlayAlert(GStrings("TXT_EX_MASKEX")); + PlayAlert(GStrings.GetString("TXT_EX_MASKEX")); } if (pPlayer->nQuake != 0) diff --git a/source/games/exhumed/src/switch.cpp b/source/games/exhumed/src/switch.cpp index 556857ef5ac..077438890fe 100644 --- a/source/games/exhumed/src/switch.cpp +++ b/source/games/exhumed/src/switch.cpp @@ -558,7 +558,7 @@ void AISWPressSector::Use(RunListEvent* ev) { PlayFXAtXYZ(StaticSound[nSwitchSound], pPlayer->GetActor()->spr.pos, CHANF_LISTENERZ); - StatusMessage(300, GStrings("TXT_EX_NEEDKEY")); + StatusMessage(300, GStrings.GetString("TXT_EX_NEEDKEY")); } } diff --git a/source/games/sw/src/cheats.cpp b/source/games/sw/src/cheats.cpp index 88afbb121bd..4a359b0f89d 100644 --- a/source/games/sw/src/cheats.cpp +++ b/source/games/sw/src/cheats.cpp @@ -69,7 +69,7 @@ const char *GameInterface::CheckCheatMode() { if (Skill >= 3 && !sv_cheats) { - return GStrings("TXTS_TOOSKILLFUL"); + return GStrings.GetString("TXTS_TOOSKILLFUL"); } return nullptr; } @@ -80,19 +80,19 @@ const char *GameInterface::GenericCheat(int player, int cheat) { case CHT_GOD: GodMode ^= 1; // fixme: Make god mode a player property. - return GStrings(GodMode ? "GOD MODE: ON" : "GOD MODE: OFF"); + return GStrings.GetString(GodMode ? "GOD MODE: ON" : "GOD MODE: OFF"); case CHT_GODOFF: GodMode = 0; // fixme: Make god mode a player property. - return GStrings("GOD MODE: OFF"); + return GStrings.GetString("GOD MODE: OFF"); case CHT_GODON: GodMode = 1; // fixme: Make god mode a player property. - return GStrings("GOD MODE: ON"); + return GStrings.GetString("GOD MODE: ON"); case CHT_NOCLIP: getPlayer(player)->Flags ^= PF_CLIP_CHEAT; - return GStrings(getPlayer(player)->Flags & PF_CLIP_CHEAT ? "CLIPPING: OFF" : "CLIPPING: ON"); + return GStrings.GetString(getPlayer(player)->Flags & PF_CLIP_CHEAT ? "CLIPPING: OFF" : "CLIPPING: ON"); case CHT_FLY: ToggleFlyMode = true; @@ -146,7 +146,7 @@ bool MapCheat(cheatseq_t* c) if (!(pp=checkCheat(c))) return false; gFullMap = !gFullMap; // Need to do this differently. The code here was completely broken. - PutStringInfo(pp, GStrings(gFullMap ? "TXTS_AMON" : "TXTS_AMOFF")); + PutStringInfo(pp, GStrings.GetString(gFullMap ? "TXTS_AMON" : "TXTS_AMOFF")); return true; } @@ -193,7 +193,7 @@ bool WinPachinkoCheat(cheatseq_t* c) return false; Pachinko_Win_Cheat = !Pachinko_Win_Cheat; - PutStringInfo(getPlayer(myconnectindex), GStrings(Pachinko_Win_Cheat ? "TXTS_WINPACHINKOEN" : "TXTS_WINPACHINKODIS")); + PutStringInfo(getPlayer(myconnectindex), GStrings.GetString(Pachinko_Win_Cheat ? "TXTS_WINPACHINKOEN" : "TXTS_WINPACHINKODIS")); return true; } @@ -209,7 +209,7 @@ bool BunnyCheat(cheatseq_t* c) return false; sw_bunnyrockets = !sw_bunnyrockets; - PutStringInfo(getPlayer(myconnectindex), GStrings(sw_bunnyrockets ? "TXTS_BUNNYENABLED" : "TXTS_BUNNYDISABLED")); + PutStringInfo(getPlayer(myconnectindex), GStrings.GetString(sw_bunnyrockets ? "TXTS_BUNNYENABLED" : "TXTS_BUNNYDISABLED")); return true; } @@ -290,7 +290,7 @@ static void WeaponCheat(int player) static void ItemCheat(int player) { auto p = getPlayer(player); - PutStringInfo(p, GStrings("GIVING EVERYTHING!")); + PutStringInfo(p, GStrings.GetString("GIVING EVERYTHING!")); memset(p->HasKey, true, sizeof(p->HasKey)); p->WpnShotgunAuto = 50; @@ -341,7 +341,7 @@ static void cmd_Give(int player, uint8_t** stream, bool skip) if (getPlayer(player)->GetActor()->user.Health < getPlayer(player)->MaxHealth) { getPlayer(player)->GetActor()->user.Health += 25; - PutStringInfo(getPlayer(player), GStrings("TXTS_ADDEDHEALTH")); + PutStringInfo(getPlayer(player), GStrings.GetString("TXTS_ADDEDHEALTH")); } break; @@ -370,19 +370,19 @@ static void cmd_Give(int player, uint8_t** stream, bool skip) if (getPlayer(player)->GetActor()->user.Health < getPlayer(player)->MaxHealth) { getPlayer(player)->Armor = 100; - PutStringInfo(getPlayer(player), GStrings("TXTB_FULLARM")); + PutStringInfo(getPlayer(player), GStrings.GetString("TXTB_FULLARM")); } break; case GIVE_KEYS: memset(getPlayer(player)->HasKey, true, sizeof(getPlayer(player)->HasKey)); - PutStringInfo(getPlayer(player), GStrings("TXTS_GIVEKEY")); + PutStringInfo(getPlayer(player), GStrings.GetString("TXTS_GIVEKEY")); break; case GIVE_INVENTORY: { auto p = getPlayer(player); - PutStringInfo(p, GStrings("GOT ALL INVENTORY")); + PutStringInfo(p, GStrings.GetString("GOT ALL INVENTORY")); p->WpnShotgunAuto = 50; p->WpnRocketHeat = 5; diff --git a/source/games/sw/src/draw.cpp b/source/games/sw/src/draw.cpp index 376e491ed88..ff226ddd668 100644 --- a/source/games/sw/src/draw.cpp +++ b/source/games/sw/src/draw.cpp @@ -1353,7 +1353,7 @@ void drawscreen(DSWPlayer* pp, double interpfrac, bool sceneonly) if (paused && !M_Active()) { - auto str = GStrings("Game Paused"); + auto str = GStrings.GetString("Game Paused"); auto font = PickSmallFont(str); int w = font->StringWidth(str); DrawText(twod, font, CR_UNTRANSLATED, 160-w, 100, str, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE); diff --git a/source/games/sw/src/player.cpp b/source/games/sw/src/player.cpp index 73226ebc446..efc7444ff2c 100644 --- a/source/games/sw/src/player.cpp +++ b/source/games/sw/src/player.cpp @@ -5602,7 +5602,7 @@ void DoPlayerBeginDie(DSWPlayer* pp) PlayerSound(PlayerLowHealthPainVocs[choosesnd],v3df_dontpan|v3df_doppler|v3df_follow,pp); - PutStringInfo(pp, GStrings("TXTS_PRESSSPACE")); + PutStringInfo(pp, GStrings.GetString("TXTS_PRESSSPACE")); if (pp->sop_control) DoPlayerStopOperate(pp); diff --git a/source/games/sw/src/rotator.cpp b/source/games/sw/src/rotator.cpp index d1c68dfd8be..48b4d61cfb3 100644 --- a/source/games/sw/src/rotator.cpp +++ b/source/games/sw/src/rotator.cpp @@ -182,7 +182,7 @@ void DoRotatorMatch(DSWPlayer* pp, short match, bool manual) // bool 8 must be set for message to display if (TEST_BOOL4(actor) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS)) { - if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings("TXT_SPONLY")); + if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings.GetString("TXT_SPONLY")); continue; } diff --git a/source/games/sw/src/sector.cpp b/source/games/sw/src/sector.cpp index 4a7055294cc..234a7d764a2 100644 --- a/source/games/sw/src/sector.cpp +++ b/source/games/sw/src/sector.cpp @@ -1909,7 +1909,7 @@ void TriggerSecret(sectortype* sectp, DSWPlayer* pp) SECRET_Trigger(sectindex(pp->cursector)); - PutStringInfo(pp, GStrings("TXTS_SECRET")); + PutStringInfo(pp, GStrings.GetString("TXTS_SECRET")); // always give to the first player Level.addSecret(myconnectindex); sectp->lotag = 0; diff --git a/source/games/sw/src/slidor.cpp b/source/games/sw/src/slidor.cpp index 6ca9f61c0cf..f1fec5e51ae 100644 --- a/source/games/sw/src/slidor.cpp +++ b/source/games/sw/src/slidor.cpp @@ -176,7 +176,7 @@ void DoSlidorMatch(DSWPlayer* pp, short match, bool manual) // bool 8 must be set for message to display if (TEST_BOOL4(actor) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS)) { - if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings("TXTS_SPONLY")); + if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings.GetString("TXTS_SPONLY")); continue; } diff --git a/source/games/sw/src/sprite.cpp b/source/games/sw/src/sprite.cpp index 1fe952e86c6..d6f90c3088d 100644 --- a/source/games/sw/src/sprite.cpp +++ b/source/games/sw/src/sprite.cpp @@ -5247,7 +5247,7 @@ int DoGet(DSWActor* actor) { int cookie = StdRandomRange(MAX_FORTUNES); // print to the console, and the user quote display. - FStringf msg("%s %s", GStrings("TXTS_FORTUNE"), quoteMgr.GetQuote(QUOTE_COOKIE + cookie)); + FStringf msg("%s %s", GStrings.GetString("TXTS_FORTUNE"), quoteMgr.GetQuote(QUOTE_COOKIE + cookie)); Printf(PRINT_NONOTIFY, TEXTCOLOR_SAPPHIRE "%s\n", msg.GetChars()); if (hud_messages) { @@ -5415,7 +5415,7 @@ int DoGet(DSWActor* actor) if (pp->WpnAmmo[WPN_STAR] >= DamageData[WPN_STAR].max_ammo) break; - PutStringInfo(pp, sw_darts? GStrings("TXTS_DARTS") : quoteMgr.GetQuote(QUOTE_WPNSHURIKEN)); + PutStringInfo(pp, sw_darts? GStrings.GetString("TXTS_DARTS") : quoteMgr.GetQuote(QUOTE_WPNSHURIKEN)); PlayerUpdateAmmo(pp, WPN_STAR, DamageData[WPN_STAR].weapon_pickup); SetFadeAmt(pp,ITEMFLASHAMT,ITEMFLASHCLR); // Flash blue on item pickup if (pp->pnum == myconnectindex) diff --git a/source/games/sw/src/vator.cpp b/source/games/sw/src/vator.cpp index 698205a9db6..fe2b07bf013 100644 --- a/source/games/sw/src/vator.cpp +++ b/source/games/sw/src/vator.cpp @@ -191,7 +191,7 @@ void DoVatorMatch(DSWPlayer* pp, short match) // bool 8 must be set for message to display if (TEST_BOOL4(actor) && (gNet.MultiGameType == MULTI_GAME_COMMBAT || gNet.MultiGameType == MULTI_GAME_AI_BOTS)) { - if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings("TXTS_SPONLY")); + if (pp && TEST_BOOL11(actor)) PutStringInfo(pp, GStrings.GetString("TXTS_SPONLY")); continue; } diff --git a/source/games/sw/src/weapon.cpp b/source/games/sw/src/weapon.cpp index 895545aacc5..bfc40ec554e 100644 --- a/source/games/sw/src/weapon.cpp +++ b/source/games/sw/src/weapon.cpp @@ -7065,94 +7065,94 @@ const char *DeathString(DSWActor* actor) case NINJA_RUN_R0: return " "; case ZOMBIE_RUN_R0: - return GStrings("Zombie"); + return GStrings.GetString("Zombie"); case BLOOD_WORM: - return GStrings("Blood Worm"); + return GStrings.GetString("Blood Worm"); case SKEL_RUN_R0: - return GStrings("Skeletor Priest"); + return GStrings.GetString("Skeletor Priest"); case COOLG_RUN_R0: - return GStrings("Coolie Ghost"); + return GStrings.GetString("Coolie Ghost"); case GORO_RUN_R0: - return GStrings("Guardian"); + return GStrings.GetString("Guardian"); case HORNET_RUN_R0: - return GStrings("Hornet"); + return GStrings.GetString("Hornet"); case RIPPER_RUN_R0: - return GStrings("Ripper Hatchling"); + return GStrings.GetString("Ripper Hatchling"); case RIPPER2_RUN_R0: - return GStrings("Ripper"); + return GStrings.GetString("Ripper"); case BUNNY_RUN_R0: - return GStrings("Killer Rabbit"); + return GStrings.GetString("Killer Rabbit"); case SERP_RUN_R0: - return GStrings("Serpent god"); + return GStrings.GetString("Serpent god"); case GIRLNINJA_RUN_R0: - return GStrings("Girl Ninja"); + return GStrings.GetString("Girl Ninja"); case BLADE1: case BLADE2: case BLADE3: case 5011: - return GStrings("blade"); + return GStrings.GetString("blade"); case STAR1: - if (sw_darts) return GStrings("dart"); - else return GStrings("shuriken"); + if (sw_darts) return GStrings.GetString("dart"); + else return GStrings.GetString("shuriken"); case CROSSBOLT: - return GStrings("crossbow bolt"); + return GStrings.GetString("crossbow bolt"); case SPEAR_R0: - return GStrings("spear"); + return GStrings.GetString("spear"); case LAVA_BOULDER: case LAVA_SHARD: - return GStrings("lava boulder"); + return GStrings.GetString("lava boulder"); case UZI_SMOKE: - return GStrings("Uzi"); + return GStrings.GetString("Uzi"); case UZI_SMOKE+2: - return GStrings("Evil Ninja Uzi"); + return GStrings.GetString("Evil Ninja Uzi"); case SHOTGUN_SMOKE: - return GStrings("shotgun"); + return GStrings.GetString("shotgun"); case MIRV_METEOR: case SERP_METEOR: - return GStrings("meteor"); + return GStrings.GetString("meteor"); case BOLT_THINMAN_R0: - return GStrings("rocket"); + return GStrings.GetString("rocket"); case BOLT_THINMAN_R1: - return GStrings("rail gun"); + return GStrings.GetString("rail gun"); case BOLT_THINMAN_R2: - return GStrings("enemy rocket"); + return GStrings.GetString("enemy rocket"); case BOLT_THINMAN_R4: // BunnyRocket - return GStrings("bunny rocket"); + return GStrings.GetString("bunny rocket"); case BOLT_EXP: - return GStrings("explosion"); + return GStrings.GetString("explosion"); case TANK_SHELL_EXP: - return GStrings("tank shell"); + return GStrings.GetString("tank shell"); case MUSHROOM_CLOUD: - return GStrings("nuclear bomb"); + return GStrings.GetString("nuclear bomb"); case GRENADE_EXP: - return GStrings("40mm grenade"); + return GStrings.GetString("40mm grenade"); case MICRO_EXP: - return GStrings("micro missile"); + return GStrings.GetString("micro missile"); case MINE_EXP: //case MINE_SHRAP: - return GStrings("sticky bomb"); + return GStrings.GetString("sticky bomb"); case NAP_EXP: - return GStrings("napalm"); + return GStrings.GetString("napalm"); case Vomit1: case Vomit2: - return GStrings("vomit"); + return GStrings.GetString("vomit"); case COOLG_FIRE: - return GStrings("Coolie Ghost phlem"); + return GStrings.GetString("Coolie Ghost phlem"); case SKULL_R0: - return GStrings("Accursed Head"); + return GStrings.GetString("Accursed Head"); case BETTY_R0: - return GStrings("Bouncing Betty"); + return GStrings.GetString("Bouncing Betty"); case SKULL_SERP: - return GStrings("Serpent god Protector"); + return GStrings.GetString("Serpent god Protector"); case FIREBALL1: case FIREBALL: case GORO_FIREBALL: case FIREBALL_FLAMES: - return GStrings("flames"); + return GStrings.GetString("flames"); case RADIATION_CLOUD: - return GStrings("radiation"); + return GStrings.GetString("radiation"); case CALTROPS: - return GStrings("useitem 7"); + return GStrings.GetString("useitem 7"); } return ""; } diff --git a/source/launcher/launcherbanner.cpp b/source/launcher/launcherbanner.cpp index 69f7e7ee1af..823b0021d01 100644 --- a/source/launcher/launcherbanner.cpp +++ b/source/launcher/launcherbanner.cpp @@ -17,7 +17,7 @@ LauncherBanner::LauncherBanner(Widget* parent) : Widget(parent) void LauncherBanner::UpdateLanguage() { - FString versionText = GStrings("PICKER_VERSION"); + FString versionText = GStrings.GetString("PICKER_VERSION"); versionText.Substitute("%s", GetVersionString()); VersionLabel->SetText(versionText.GetChars()); } diff --git a/source/launcher/launcherbuttonbar.cpp b/source/launcher/launcherbuttonbar.cpp index d542ea51ee3..789881000e0 100644 --- a/source/launcher/launcherbuttonbar.cpp +++ b/source/launcher/launcherbuttonbar.cpp @@ -15,8 +15,8 @@ LauncherButtonbar::LauncherButtonbar(LauncherWindow* parent) : Widget(parent) void LauncherButtonbar::UpdateLanguage() { - PlayButton->SetText(GStrings("PICKER_PLAY")); - ExitButton->SetText(GStrings("PICKER_EXIT")); + PlayButton->SetText(GStrings.GetString("PICKER_PLAY")); + ExitButton->SetText(GStrings.GetString("PICKER_EXIT")); } double LauncherButtonbar::GetPreferredHeight() const diff --git a/source/launcher/launcherwindow.cpp b/source/launcher/launcherwindow.cpp index 96039ea0853..1cf8335eadd 100644 --- a/source/launcher/launcherwindow.cpp +++ b/source/launcher/launcherwindow.cpp @@ -11,13 +11,13 @@ #include #include -int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags) +int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString& extraArgs) { Size screenSize = GetScreenSize(); double windowWidth = 615.0; double windowHeight = 700.0; - auto launcher = std::make_unique(wads, numwads, defaultiwad, autoloadflags); + auto launcher = std::make_unique(wads, numwads, defaultiwad, autoloadflags, extraArgs); launcher->SetFrameGeometry((screenSize.width - windowWidth) * 0.5, (screenSize.height - windowHeight) * 0.5, windowWidth, windowHeight); launcher->Show(); @@ -26,7 +26,7 @@ int LauncherWindow::ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* return launcher->ExecResult; } -LauncherWindow::LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags) : Widget(nullptr, WidgetType::Window) +LauncherWindow::LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString& extraArgs) : Widget(nullptr, WidgetType::Window) { SetWindowBackground(Colorf::fromRgba8(51, 51, 51)); SetWindowBorderColor(Colorf::fromRgba8(51, 51, 51)); @@ -72,8 +72,8 @@ void LauncherWindow::Exit() void LauncherWindow::UpdateLanguage() { - Pages->SetTabText(PlayGame, GStrings("PICKER_TAB_PLAY")); - Pages->SetTabText(Settings, GStrings("OPTMNU_TITLE")); + Pages->SetTabText(PlayGame, GStrings.GetString("PICKER_TAB_PLAY")); + Pages->SetTabText(Settings, GStrings.GetString("OPTMNU_TITLE")); Banner->UpdateLanguage(); PlayGame->UpdateLanguage(); Settings->UpdateLanguage(); diff --git a/source/launcher/launcherwindow.h b/source/launcher/launcherwindow.h index 8cdbc6ce779..c64676a467e 100644 --- a/source/launcher/launcherwindow.h +++ b/source/launcher/launcherwindow.h @@ -14,9 +14,9 @@ struct WadStuff; class LauncherWindow : public Widget { public: - static int ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags); + static int ExecModal(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString& extraArgs); - LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags); + LauncherWindow(WadStuff* wads, int numwads, int defaultiwad, int* autoloadflags, FString& extraArgs); void UpdateLanguage(); void Start(); diff --git a/source/launcher/playgamepage.cpp b/source/launcher/playgamepage.cpp index ce30930f8d4..972e48d26d4 100644 --- a/source/launcher/playgamepage.cpp +++ b/source/launcher/playgamepage.cpp @@ -52,9 +52,9 @@ int PlayGamePage::GetSelectedGame() void PlayGamePage::UpdateLanguage() { - SelectLabel->SetText(GStrings("PICKER_SELECT")); - ParametersLabel->SetText(GStrings("PICKER_ADDPARM")); - FString welcomeText = GStrings("PICKER_WELCOME"); + SelectLabel->SetText(GStrings.GetString("PICKER_SELECT")); + ParametersLabel->SetText(GStrings.GetString("PICKER_ADDPARM")); + FString welcomeText = GStrings.GetString("PICKER_WELCOME"); welcomeText.Substitute("%s", GAMENAME); WelcomeLabel->SetText(welcomeText.GetChars()); } diff --git a/source/launcher/settingspage.cpp b/source/launcher/settingspage.cpp index e50f994e8a2..6ddc7667992 100644 --- a/source/launcher/settingspage.cpp +++ b/source/launcher/settingspage.cpp @@ -138,23 +138,23 @@ void SettingsPage::Save() void SettingsPage::UpdateLanguage() { - LangLabel->SetText(GStrings("OPTMNU_LANGUAGE")); - GeneralLabel->SetText(GStrings("PICKER_GENERAL")); -// ExtrasLabel->SetText(GStrings("PICKER_EXTRA")); - FullscreenCheckbox->SetText(GStrings("PICKER_FULLSCREEN")); - DisableAutoloadCheckbox->SetText(GStrings("PICKER_NOAUTOLOAD")); - DontAskAgainCheckbox->SetText(GStrings("PICKER_DONTASK")); + LangLabel->SetText(GStrings.GetString("OPTMNU_LANGUAGE")); + GeneralLabel->SetText(GStrings.GetString("PICKER_GENERAL")); +// ExtrasLabel->SetText(GStrings.GetString("PICKER_EXTRA")); + FullscreenCheckbox->SetText(GStrings.GetString("PICKER_FULLSCREEN")); + DisableAutoloadCheckbox->SetText(GStrings.GetString("PICKER_NOAUTOLOAD")); + DontAskAgainCheckbox->SetText(GStrings.GetString("PICKER_DONTASK")); /* - LightsCheckbox->SetText(GStrings("PICKER_LIGHTS")); - BrightmapsCheckbox->SetText(GStrings("PICKER_BRIGHTMAPS")); - WidescreenCheckbox->SetText(GStrings("PICKER_WIDESCREEN")); + LightsCheckbox->SetText(GStrings.GetString("PICKER_LIGHTS")); + BrightmapsCheckbox->SetText(GStrings.GetString("PICKER_BRIGHTMAPS")); + WidescreenCheckbox->SetText(GStrings.GetString("PICKER_WIDESCREEN")); */ #ifdef RENDER_BACKENDS - BackendLabel->SetText(GStrings("PICKER_PREFERBACKEND")); - VulkanCheckbox->SetText(GStrings("OPTVAL_VULKAN")); - OpenGLCheckbox->SetText(GStrings("OPTVAL_OPENGL")); - GLESCheckbox->SetText(GStrings("OPTVAL_OPENGLES")); + BackendLabel->SetText(GStrings.GetString("PICKER_PREFERBACKEND")); + VulkanCheckbox->SetText(GStrings.GetString("OPTVAL_VULKAN")); + OpenGLCheckbox->SetText(GStrings.GetString("OPTVAL_OPENGL")); + GLESCheckbox->SetText(GStrings.GetString("OPTVAL_OPENGLES")); #endif }