├── lib └── .gitkeep ├── src ├── Media │ ├── Media.cpp │ ├── MediaLogger.h │ ├── CMakeLists.txt │ └── MediaPlayer.h ├── GUI │ ├── UI │ │ ├── UIGuilds.h │ │ ├── UIArena.h │ │ ├── Books │ │ │ ├── QuestBook.h │ │ │ ├── JournalBook.h │ │ │ ├── CalendarBook.h │ │ │ ├── AutonotesBook.h │ │ │ ├── TownPortalBook.h │ │ │ ├── LloydsBook.h │ │ │ └── MapBook.h │ │ ├── UIQuickReference.h │ │ ├── UIPartyCreation.h │ │ ├── UIChest.h │ │ ├── UIGameOver.h │ │ ├── UICredits.h │ │ ├── Spellbook.h │ │ ├── UIRest.h │ │ ├── UIMainMenu.h │ │ ├── UIShops.h │ │ ├── UIPopup.h │ │ ├── UIStatusBar.h │ │ ├── UITransition.h │ │ ├── UIInventory.h │ │ ├── UISaveLoad.h │ │ ├── UIDialogue.h │ │ ├── UICharacter.h │ │ └── UIBooks.h │ └── GUIProgressBar.h ├── Utility │ ├── Color.cpp │ ├── Geometry │ │ ├── Point.h │ │ ├── Margins.h │ │ ├── Size.h │ │ └── Rect.h │ ├── Format.h │ ├── Memory │ │ ├── MemSet.h │ │ └── FreeDeleter.h │ ├── Streams │ │ ├── InputStream.cpp │ │ ├── StringOutputStream.h │ │ ├── MemoryInputStream.h │ │ ├── FileOutputStream.h │ │ ├── StringOutputStream.cpp │ │ ├── Tests │ │ │ └── FileOutputStream_ut.cpp │ │ ├── MemoryInputStream.cpp │ │ ├── FileOutputStream.cpp │ │ ├── OutputStream.h │ │ └── InputStream.h │ ├── Preprocessor.h │ ├── Embedded.h │ ├── Workaround │ │ └── ToUnderlying.h │ ├── Math │ │ ├── Float.h │ │ ├── Tests │ │ │ └── Float_ut.cpp │ │ ├── TrigLut.cpp │ │ ├── FixPoint.h │ │ └── TrigLut.h │ ├── DataPath.h │ ├── Tests │ │ ├── String_ut.cpp │ │ └── Segment_ut.cpp │ ├── ScopeGuard.h │ ├── FileSystem.h │ └── Reversed.h ├── Engine │ ├── Graphics │ │ ├── RendererType.h │ │ ├── Texture.h │ │ ├── FrameLimiter.h │ │ ├── IRenderFactory.h │ │ ├── Weather.h │ │ ├── PCX.h │ │ ├── LightmapBuilder.h │ │ ├── OpenGL │ │ │ ├── TextureOpenGL.h │ │ │ └── GLShaderLoader.cpp │ │ ├── HWLContainer.h │ │ ├── FrameLimiter.cpp │ │ ├── NuklearEventHandler.h │ │ ├── Shaders │ │ │ └── UI.hlsl │ │ ├── PortalFunctions.h │ │ ├── Level │ │ │ └── Decoration.h │ │ ├── IRenderFactory.cpp │ │ ├── Nuklear.h │ │ └── PaletteManager.h │ ├── Tables │ │ ├── FactionTable.h │ │ ├── FrameTableInc.h │ │ ├── StorylineTextTable.h │ │ ├── CMakeLists.txt │ │ ├── PlayerFrameTable.h │ │ ├── StorylineTextTable.cpp │ │ └── FactionTable.cpp │ ├── EngineFactory.cpp │ ├── EngineFactory.h │ ├── stru123.h │ ├── TurnEngine │ │ └── CMakeLists.txt │ ├── Spells │ │ └── CMakeLists.txt │ ├── SpawnPoint.h │ ├── stru159.h │ ├── Serialization │ │ └── CMakeLists.txt │ ├── Autonotes.h │ ├── stru367.h │ ├── EngineGlobals.cpp │ ├── stru160.h │ ├── stru298.cpp │ ├── stru298.h │ ├── stru314.h │ ├── MapsLongTimer.h │ ├── Plugins │ │ ├── CMakeLists.txt │ │ ├── EngineTracePlugin.h │ │ └── EngineTracePlugin.cpp │ ├── Objects │ │ └── CMakeLists.txt │ ├── SaveLoad.h │ ├── IocContainer.h │ ├── ErrorHandling.h │ ├── AssetsManager.h │ └── EngineGlobals.h ├── Library │ ├── Json │ │ ├── JsonExceptions.h │ │ ├── JsonExceptions.cpp │ │ ├── JsonFwd.h │ │ └── CMakeLists.txt │ ├── Config │ │ ├── ConfigFwd.h │ │ ├── CMakeLists.txt │ │ ├── Config.h │ │ ├── AbstractConfigValue.h │ │ ├── ConfigSection.h │ │ └── ConfigSection.cpp │ ├── Lod │ │ ├── Internal │ │ │ ├── LodFile.h │ │ │ ├── LodDirectory.h │ │ │ ├── LodDirectoryHeader.h │ │ │ ├── LodHeader.h │ │ │ └── LodFileHeader.h │ │ ├── LodVersion.h │ │ ├── CMakeLists.txt │ │ └── LodReader.h │ ├── Random │ │ ├── Random.cpp │ │ ├── CMakeLists.txt │ │ ├── NonRandomEngine.h │ │ ├── RandomEngine.cpp │ │ └── MersenneTwisterRandomEngine.h │ ├── Logger │ │ ├── CMakeLists.txt │ │ ├── Logger.h │ │ └── Logger.cpp │ ├── CMakeLists.txt │ ├── Trace │ │ ├── CMakeLists.txt │ │ ├── PaintEvent.h │ │ └── EventTrace.h │ ├── Application │ │ ├── CMakeLists.txt │ │ └── PlatformApplicationAware.h │ ├── Compression │ │ ├── Compression.h │ │ └── CMakeLists.txt │ └── Serialization │ │ ├── StandardSerialization.h │ │ ├── SerializationFwd.h │ │ ├── SerializationExceptions.h │ │ ├── SerializationExceptions.cpp │ │ ├── CMakeLists.txt │ │ └── Serialization.h ├── Application │ ├── GameOver.h │ ├── GameOptions.h │ ├── GameFactory.h │ ├── IocContainer.h │ ├── GamePathResolver.h │ ├── GameFactory.cpp │ ├── GameMenu.h │ ├── IocContainer.cpp │ ├── CMakeLists.txt │ ├── GameKeyboardController.h │ ├── GameKeyboardController.cpp │ └── GameTraceHandler.h ├── Platform │ ├── Sdl │ │ ├── SdlMain.cpp │ │ ├── SdlLogger.h │ │ ├── SdlOpenGLContext.h │ │ ├── SdlGamepad.h │ │ ├── SdlEnumTranslation.h │ │ ├── SdlGamepad.cpp │ │ ├── SdlOpenGLContext.cpp │ │ ├── SdlPlatform.h │ │ └── SdlPlatformSharedState.h │ ├── Win │ │ └── WinPlatform.h │ ├── PlatformOpenGLContext.h │ ├── PlatformGamepad.h │ ├── Proxy │ │ ├── ProxyGamepad.cpp │ │ ├── ProxyGamepad.h │ │ ├── ProxyOpenGLContext.h │ │ ├── ProxyEventLoop.h │ │ ├── ProxyOpenGLContext.cpp │ │ ├── ProxyEventLoop.cpp │ │ ├── ProxyBase.h │ │ ├── ProxyPlatform.h │ │ ├── ProxyWindow.h │ │ └── ProxyPlatform.cpp │ ├── Posix │ │ └── PosixPlatform.cpp │ ├── Filters │ │ ├── FilteringEventHandler.h │ │ ├── FilteringEventHandler.cpp │ │ └── PlatformEventFilter.h │ ├── PlatformOpenGLOptions.h │ ├── PlatformEventHandler.h │ └── PlatformEventLoop.h ├── CMakeLists.txt ├── Arcomage │ └── CMakeLists.txt └── Io │ ├── IKeyboardController.h │ ├── Key.h │ └── CMakeLists.txt ├── test ├── Testing │ ├── Unit │ │ ├── UnitTest.cpp │ │ ├── UnitTest.h │ │ └── CMakeLists.txt │ ├── CMakeLists.txt │ ├── Game │ │ ├── TestConfig.h │ │ ├── TestConfig.cpp │ │ ├── CMakeLists.txt │ │ ├── TestController.h │ │ ├── GameTest.h │ │ ├── GameTest.cpp │ │ └── TestController.cpp │ └── Extensions │ │ ├── CMakeLists.txt │ │ ├── ThrowingAssertions.h │ │ └── ThrowingAssertions.cpp ├── Bin │ ├── CMakeLists.txt │ ├── UnitTest │ │ ├── UnitTestMain.cpp │ │ └── CMakeLists.txt │ └── GameTest │ │ ├── GameTestOptions.h │ │ ├── GameTestOptions.cpp │ │ └── CMakeLists.txt ├── CMakeLists.txt └── Tests │ └── CMakeLists.txt ├── CMakeModules ├── AppleLibcxxAssertionTest.cpp ├── AppleLibcxxAssertionWorkaround.cpp ├── Git.cmake └── Detection.cmake ├── resources └── shaders │ ├── gllinesshader.frag │ ├── glnuklear.frag │ ├── glnuklear.vert │ ├── gllinesshader.vert │ ├── gltextshader.frag │ ├── gltextshader.vert │ ├── gltwodshader.vert │ ├── glbillbshader.vert │ ├── gltwodshader.frag │ ├── glforcepershader.vert │ ├── gldecalshader.vert │ ├── glbspshader.vert │ ├── glterrain.vert │ ├── gloutbuild.vert │ ├── gldecalshader.frag │ └── glforcepershader.frag ├── .gitattributes ├── thirdparty ├── luajit │ ├── cmake │ │ ├── src │ │ │ └── host │ │ │ │ └── cmake │ │ │ │ ├── minilua │ │ │ │ └── CMakeLists.txt │ │ │ │ └── buildvm │ │ │ │ └── CMakeLists.txt │ │ └── cmake │ │ │ └── modules │ │ │ ├── DetectFpuAbi.c │ │ │ └── DetectArchitecture.c │ └── CMakeLists.txt ├── glad │ └── CMakeLists.txt ├── CMakeLists.txt └── nuklear │ └── nuklear_config.h ├── CPPLINT.cfg ├── .github ├── ISSUE_TEMPLATE │ ├── suggestion.md │ └── bug_report.md └── workflows │ ├── style.yml │ ├── shaders.yml │ ├── windows.yml │ ├── macos.yml │ └── doxygen.yml ├── .gitignore ├── .gitmodules └── TODO.md /lib/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Media/Media.cpp: -------------------------------------------------------------------------------- 1 | #include "Media/Media.h" 2 | -------------------------------------------------------------------------------- /src/GUI/UI/UIGuilds.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | void SpellBookGenerator(); 3 | -------------------------------------------------------------------------------- /src/Utility/Color.cpp: -------------------------------------------------------------------------------- 1 | #include "Color.h" 2 | 3 | ColorTable colorTable; 4 | -------------------------------------------------------------------------------- /src/Engine/Graphics/RendererType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class RendererType { 4 | OpenGL, 5 | OpenGLES 6 | }; 7 | -------------------------------------------------------------------------------- /test/Testing/Unit/UnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "UnitTest.h" 2 | 3 | // This source is here just to make the build system happy. 4 | -------------------------------------------------------------------------------- /src/Utility/Geometry/Point.h: -------------------------------------------------------------------------------- 1 | #include "Vec.h" 2 | 3 | template 4 | using Point = Vec2; 5 | 6 | using Pointi = Point; 7 | -------------------------------------------------------------------------------- /test/Bin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | add_subdirectory(GameTest) 4 | add_subdirectory(UnitTest) 5 | -------------------------------------------------------------------------------- /src/Utility/Format.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | using namespace fmt::literals; // NOLINT 7 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | add_subdirectory(Bin) 4 | add_subdirectory(Testing) 5 | add_subdirectory(Tests) 6 | -------------------------------------------------------------------------------- /CMakeModules/AppleLibcxxAssertionTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) { 4 | std::vector a; 5 | a[0] = 0; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /src/Library/Json/JsonExceptions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "JsonFwd.h" 4 | 5 | [[noreturn]] void throwJsonDeserializationError(const Json &json, const char *typeName); 6 | -------------------------------------------------------------------------------- /test/Testing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | add_subdirectory(Extensions) 4 | add_subdirectory(Game) 5 | add_subdirectory(Unit) 6 | -------------------------------------------------------------------------------- /src/Application/GameOver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Application { 4 | 5 | void GameOver_Loop(int); 6 | void CreateWinnerCertificate(); 7 | 8 | } // namespace Application 9 | -------------------------------------------------------------------------------- /resources/shaders/gllinesshader.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | in vec4 colour; 4 | 5 | out vec4 FragColour; 6 | 7 | void main() { 8 | FragColour = colour; 9 | } 10 | -------------------------------------------------------------------------------- /src/Application/GameOptions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Application { 4 | class GameConfig; 5 | 6 | bool ParseGameOptions(int argc, char **argv, GameConfig *config); 7 | } 8 | -------------------------------------------------------------------------------- /test/Testing/Game/TestConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Application { 4 | class GameConfig; 5 | } // namespace Application 6 | 7 | void ResetTestConfig(Application::GameConfig *config); 8 | -------------------------------------------------------------------------------- /test/Bin/UnitTest/UnitTestMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | GTEST_API_ int main(int argc, char **argv) { 4 | testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | -------------------------------------------------------------------------------- /src/Library/Config/ConfigFwd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Config; 6 | class ConfigSection; 7 | template 8 | class ConfigValue; 9 | class AbstractConfigValue; 10 | -------------------------------------------------------------------------------- /src/Library/Lod/Internal/LodFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | struct LodFile final { 7 | std::string name; 8 | size_t dataOffset = 0; 9 | size_t dataSize = 0; 10 | }; 11 | -------------------------------------------------------------------------------- /src/Engine/Tables/FactionTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 174 */ 4 | #pragma pack(push, 1) 5 | struct FactionTable { 6 | void Initialize(); 7 | 8 | char relations[89][89]; 9 | }; 10 | #pragma pack(pop) 11 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlMain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int platformMain(int argc, char** argv); 4 | 5 | // This gets #defined by SDL into SDL_main. 6 | int main(int argc, char** argv) { 7 | return platformMain(argc, argv); 8 | } 9 | -------------------------------------------------------------------------------- /src/Library/Lod/LodVersion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | enum class LodVersion { 5 | LOD_VERSION_MM6, 6 | LOD_VERSION_MM6_GAME, 7 | LOD_VERSION_MM7, 8 | LOD_VERSION_MM8, 9 | }; 10 | 11 | using enum LodVersion; 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | text eol=lf 3 | 4 | *.c text 5 | *.cpp text 6 | *.h text 7 | *.hpp text 8 | 9 | *.sln text eol=crlf 10 | *.vcxproj text eol=crlf 11 | *.vcxproj.filters text eol=crlf 12 | *.vcxproj.user text eol=crlf 13 | -------------------------------------------------------------------------------- /src/GUI/UI/UIArena.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Utility/Geometry/Vec.h" 6 | 7 | extern std::array pMonsterArenaPlacements; 8 | 9 | void Arena_SelectionFightLevel(); 10 | void ArenaFight(); 11 | -------------------------------------------------------------------------------- /src/Engine/Graphics/Texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Engine/Graphics/Image.h" 3 | 4 | class Texture : public Image { 5 | protected: 6 | explicit Texture(bool lazy_initialization = true) 7 | : Image(lazy_initialization) {} 8 | }; 9 | -------------------------------------------------------------------------------- /src/GUI/UI/Books/QuestBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/UI/UIBooks.h" 3 | 4 | struct GUIWindow_QuestBook : public GUIWindow_Book { 5 | GUIWindow_QuestBook(); 6 | virtual ~GUIWindow_QuestBook() {} 7 | 8 | virtual void Update(); 9 | }; 10 | -------------------------------------------------------------------------------- /test/Testing/Unit/UnitTest.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef TEST_GROUP 4 | # error "Please define TEST_GROUP before including this header." 5 | #endif 6 | 7 | #define UNIT_TEST(TestBase, TestName) \ 8 | TEST(TEST_GROUP, TestBase##_##TestName) 9 | -------------------------------------------------------------------------------- /resources/shaders/glnuklear.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | uniform sampler2D Texture; 3 | 4 | in vec2 Frag_UV; 5 | in vec4 Frag_Color; 6 | 7 | out vec4 Out_Color; 8 | 9 | void main() { 10 | Out_Color = Frag_Color * texture(Texture, Frag_UV.st); 11 | } 12 | -------------------------------------------------------------------------------- /src/Engine/EngineFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "Engine/EngineFactory.h" 2 | 3 | using Engine_::EngineFactory; 4 | 5 | std::shared_ptr EngineFactory::CreateEngine(std::shared_ptr config) { 6 | return std::make_shared(config); 7 | } 8 | -------------------------------------------------------------------------------- /src/GUI/UI/Books/JournalBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/UI/UIBooks.h" 3 | 4 | struct GUIWindow_JournalBook : public GUIWindow_Book { 5 | GUIWindow_JournalBook(); 6 | virtual ~GUIWindow_JournalBook() {} 7 | 8 | virtual void Update(); 9 | }; 10 | -------------------------------------------------------------------------------- /src/GUI/UI/UIQuickReference.h: -------------------------------------------------------------------------------- 1 | #include "GUI/GUIWindow.h" 2 | 3 | class GUIWindow_QuickReference : public GUIWindow { 4 | public: 5 | GUIWindow_QuickReference(); 6 | virtual ~GUIWindow_QuickReference() {} 7 | 8 | virtual void Update(); 9 | }; 10 | -------------------------------------------------------------------------------- /src/GUI/UI/Books/CalendarBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/UI/UIBooks.h" 3 | 4 | struct GUIWindow_CalendarBook : public GUIWindow_Book { 5 | GUIWindow_CalendarBook(); 6 | virtual ~GUIWindow_CalendarBook() {} 7 | 8 | virtual void Update(); 9 | }; 10 | -------------------------------------------------------------------------------- /src/GUI/UI/Books/AutonotesBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/UI/UIBooks.h" 3 | 4 | struct GUIWindow_AutonotesBook : public GUIWindow_Book { 5 | GUIWindow_AutonotesBook(); 6 | virtual ~GUIWindow_AutonotesBook() {} 7 | 8 | virtual void Update(); 9 | }; 10 | -------------------------------------------------------------------------------- /test/Bin/GameTest/GameTestOptions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct GameTestOptions { 6 | std::string testDataDir; 7 | std::string gameDataDir; 8 | bool helpRequested = false; 9 | 10 | bool Parse(int argc, char **argv); 11 | }; 12 | -------------------------------------------------------------------------------- /src/Engine/Graphics/FrameLimiter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class FrameLimiter { 6 | public: 7 | FrameLimiter(); 8 | 9 | void reset(); 10 | 11 | void tick(int targetFps); 12 | 13 | private: 14 | int64_t _lastFrameTimeNs = 0; 15 | }; 16 | -------------------------------------------------------------------------------- /src/Library/Random/Random.cpp: -------------------------------------------------------------------------------- 1 | #include "Random.h" 2 | 3 | #include "MersenneTwisterRandomEngine.h" 4 | 5 | std::unique_ptr grng = std::make_unique(); 6 | std::unique_ptr vrng = std::make_unique(); 7 | 8 | -------------------------------------------------------------------------------- /src/GUI/UI/Books/TownPortalBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/UI/UIBooks.h" 3 | 4 | struct GUIWindow_TownPortalBook : public GUIWindow_Book { 5 | GUIWindow_TownPortalBook(); // const char *a1); 6 | virtual ~GUIWindow_TownPortalBook() {} 7 | 8 | virtual void Update(); 9 | }; 10 | -------------------------------------------------------------------------------- /src/Engine/EngineFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "Engine/Engine.h" 5 | 6 | namespace Engine_ { 7 | class EngineFactory { 8 | public: 9 | std::shared_ptr CreateEngine(std::shared_ptr config); 10 | }; 11 | } // Engine_ 12 | -------------------------------------------------------------------------------- /src/Engine/stru123.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /* 62 */ 5 | #pragma pack(push, 1) 6 | struct stru123 { 7 | std::array field_0; 8 | std::array _decor_events; 9 | }; 10 | #pragma pack(pop) 11 | extern stru123 stru_5E4C90_MapPersistVars; 12 | -------------------------------------------------------------------------------- /src/Library/Logger/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(LOGGER_SOURCES Logger.cpp) 4 | 5 | set(LOGGER_HEADERS Logger.h) 6 | 7 | add_library(logger STATIC ${LOGGER_SOURCES} ${LOGGER_HEADERS}) 8 | target_link_libraries(logger platform) 9 | target_check_style(logger) 10 | -------------------------------------------------------------------------------- /src/Library/Lod/Internal/LodDirectory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Library/Lod/Internal/LodFile.h" 7 | 8 | 9 | struct LodDirectory final { 10 | std::string name; 11 | std::vector files; 12 | 13 | size_t fileHeadersOffset = 0; 14 | }; 15 | -------------------------------------------------------------------------------- /thirdparty/luajit/cmake/src/host/cmake/minilua/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(minilua) 4 | 5 | find_library(LIBM_LIBRARIES NAMES m) 6 | 7 | add_executable(minilua ../../minilua.c) 8 | if (LIBM_LIBRARIES) 9 | target_link_libraries(minilua ${LIBM_LIBRARIES}) 10 | endif() 11 | -------------------------------------------------------------------------------- /src/GUI/UI/Books/LloydsBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/UI/UIBooks.h" 3 | 4 | struct GUIWindow_LloydsBook : public GUIWindow_Book { 5 | GUIWindow_LloydsBook(); 6 | virtual ~GUIWindow_LloydsBook() {} 7 | 8 | virtual void Update(); 9 | }; 10 | 11 | extern bool _506360_installing_beacon; // 506360 12 | -------------------------------------------------------------------------------- /resources/shaders/glnuklear.vert: -------------------------------------------------------------------------------- 1 | uniform mat4 ProjMtx; 2 | 3 | in vec2 Position; 4 | in vec2 TexCoord; 5 | in vec4 Color; 6 | 7 | out vec2 Frag_UV; 8 | out vec4 Frag_Color; 9 | 10 | void main() { 11 | Frag_UV = TexCoord; 12 | Frag_Color = Color; 13 | gl_Position = ProjMtx * vec4(Position.xy, 0, 1); 14 | } 15 | -------------------------------------------------------------------------------- /src/Platform/Win/WinPlatform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/Sdl/SdlPlatform.h" 6 | 7 | class WinPlatform : public SdlPlatform { 8 | public: 9 | using SdlPlatform::SdlPlatform; 10 | 11 | virtual std::string winQueryRegistry(const std::wstring &path) const override; 12 | }; 13 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | add_subdirectory(Application) 4 | add_subdirectory(Arcomage) 5 | add_subdirectory(Engine) 6 | add_subdirectory(GUI) 7 | add_subdirectory(Io) 8 | add_subdirectory(Library) 9 | add_subdirectory(Media) 10 | add_subdirectory(Platform) 11 | add_subdirectory(Utility) 12 | -------------------------------------------------------------------------------- /src/Engine/TurnEngine/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(TURNENGINE_SOURCES TurnEngine.cpp) 4 | 5 | set(TURNENGINE_HEADERS TurnEngine.h) 6 | 7 | add_library(turnengine STATIC ${TURNENGINE_SOURCES} ${TURNENGINE_HEADERS}) 8 | target_link_libraries(turnengine engine) 9 | target_check_style(turnengine) 10 | -------------------------------------------------------------------------------- /src/Platform/PlatformOpenGLContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class PlatformOpenGLContext { 4 | public: 5 | virtual ~PlatformOpenGLContext() = default; 6 | 7 | virtual bool bind() = 0; 8 | virtual bool unbind() = 0; 9 | 10 | virtual void swapBuffers() = 0; 11 | 12 | virtual void *getProcAddress(const char *name) = 0; 13 | }; 14 | -------------------------------------------------------------------------------- /test/Testing/Game/TestConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "TestConfig.h" 2 | 3 | #include "Application/GameConfig.h" 4 | 5 | void ResetTestConfig(Application::GameConfig *config) { 6 | config->Reset(); 7 | 8 | config->debug.NoVideo.Set(true); 9 | config->window.MouseGrab.Set(false); 10 | config->graphics.FPSLimit.Set(0); // Unlimited 11 | } 12 | -------------------------------------------------------------------------------- /src/Library/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | add_subdirectory(Application) 4 | add_subdirectory(Compression) 5 | add_subdirectory(Config) 6 | add_subdirectory(Json) 7 | add_subdirectory(Lod) 8 | add_subdirectory(Logger) 9 | add_subdirectory(Random) 10 | add_subdirectory(Serialization) 11 | add_subdirectory(Trace) 12 | -------------------------------------------------------------------------------- /src/Library/Lod/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(LOD_SOURCES LodReader.cpp) 4 | 5 | set(LOD_HEADERS 6 | LodReader.h 7 | LodVersion.h) 8 | 9 | add_library(lod STATIC ${LOD_SOURCES} ${LOD_HEADERS}) 10 | target_link_libraries(lod compression utility) 11 | target_check_style(lod) 12 | -------------------------------------------------------------------------------- /src/GUI/UI/Books/MapBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "GUI/UI/UIBooks.h" 6 | 7 | std::string GetMapBookHintText(int mouse_x, int mouse_y); // sub_444564 8 | 9 | struct GUIWindow_MapBook : public GUIWindow_Book { 10 | GUIWindow_MapBook(); 11 | virtual ~GUIWindow_MapBook() {} 12 | 13 | virtual void Update(); 14 | }; 15 | -------------------------------------------------------------------------------- /src/Library/Json/JsonExceptions.cpp: -------------------------------------------------------------------------------- 1 | #include "JsonExceptions.h" 2 | 3 | #include "Utility/Format.h" 4 | 5 | #include "Json.h" 6 | 7 | void throwJsonDeserializationError(const Json &json, const char *typeName) { 8 | throw Json::type_error::create(334, fmt::format("Cannot deserialize json value '{}' as type {}", to_string(json), typeName), &json); 9 | } 10 | -------------------------------------------------------------------------------- /src/Utility/Geometry/Margins.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | struct Margins { 5 | T left = 0; 6 | T top = 0; 7 | T right = 0; 8 | T bottom = 0; 9 | 10 | Margins() = default; 11 | Margins(T left, T top, T right, T bottom): left(left), top(top), right(right), bottom(bottom) {} 12 | }; 13 | 14 | using Marginsi = Margins; 15 | -------------------------------------------------------------------------------- /src/Library/Trace/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(TRACE_SOURCES EventTrace.cpp) 4 | 5 | set(TRACE_HEADERS EventTrace.h 6 | PaintEvent.h) 7 | 8 | add_library(trace STATIC ${TRACE_SOURCES} ${TRACE_HEADERS}) 9 | target_link_libraries(trace serialization platform json random) 10 | target_check_style(trace) 11 | -------------------------------------------------------------------------------- /src/Utility/Geometry/Size.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | struct Size { 5 | T w = 0; 6 | T h = 0; 7 | 8 | Size() = default; 9 | Size(T w, T h): w(w), h(h) {} 10 | 11 | bool operator== (const Size &c) const { 12 | return c.h == h && c.w == w; 13 | } 14 | }; 15 | 16 | using Sizei = Size; 17 | using Sizef = Size; 18 | -------------------------------------------------------------------------------- /src/Arcomage/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(ACROMAGE_SOURCES Arcomage.cpp 4 | ArcomageCards.cpp) 5 | 6 | set(ACROMAGE_HEADERS Arcomage.h) 7 | 8 | add_library(arcomage STATIC ${ACROMAGE_SOURCES} ${ACROMAGE_HEADERS}) 9 | target_link_libraries(arcomage utility engine gui media) 10 | 11 | target_check_style(arcomage) 12 | -------------------------------------------------------------------------------- /src/Engine/Spells/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(SPELLS_SOURCES CastSpellInfo.cpp 4 | Spells.cpp) 5 | 6 | set(SPELLS_HEADERS CastSpellInfo.h 7 | Spells.h) 8 | 9 | add_library(spells STATIC ${SPELLS_SOURCES} ${SPELLS_HEADERS}) 10 | target_link_libraries(spells engine) 11 | target_check_style(spells) 12 | -------------------------------------------------------------------------------- /src/Io/IKeyboardController.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Platform/PlatformEnums.h" 4 | 5 | namespace Io { 6 | 7 | // Glue interface between Game and Platform-specific controller 8 | class IKeyboardController { 9 | public: 10 | virtual bool ConsumeKeyPress(PlatformKey key) = 0; 11 | virtual bool IsKeyDown(PlatformKey key) const = 0; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | filter=-readability/casting,-legal/copyright,-runtime/printf,-runtime/references,-runtime/threadsafe_fn,-runtime/int,-whitespace/line_length,-readability/fn_size,-readability/todo,-runtime/string,-runtime/indentation_namespace,-whitespace/parens,-whitespace/comments,-build/c++11,-build/header_guard,-readability/inheritance 2 | exclude_files=(build|lib|out|thirdparty)/* 3 | linelength=120 4 | -------------------------------------------------------------------------------- /src/Engine/SpawnPoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Engine/Objects/ActorEnums.h" 4 | 5 | struct SpawnPoint { 6 | Vec3i vPosition; 7 | uint16_t uRadius = 32; 8 | ObjectType uKind = OBJECT_None; 9 | ITEM_TREASURE_LEVEL uItemIndex = ITEM_TREASURE_LEVEL_INVALID; 10 | uint16_t uMonsterIndex = 0; 11 | uint16_t uAttributes = 0; 12 | unsigned int uGroup = 0; 13 | }; 14 | -------------------------------------------------------------------------------- /test/Tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | if(ENABLE_TESTS) 4 | set(TESTS_SOURCES TestPartyCreationMenu.cpp) 5 | 6 | add_library(tests OBJECT ${TESTS_SOURCES}) 7 | target_compile_definitions(tests PRIVATE TEST_GROUP=Tests) 8 | 9 | target_check_style(tests) 10 | 11 | target_link_libraries(OpenEnroth_GameTest tests) 12 | endif() 13 | -------------------------------------------------------------------------------- /resources/shaders/gllinesshader.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec4 vaCol; 3 | 4 | out vec4 colour; 5 | 6 | uniform mat4 view; 7 | uniform mat4 projection; 8 | 9 | void main() { 10 | vec4 adjpos = view * vec4(vaPos, 1.0); 11 | adjpos.x += 0.5; 12 | adjpos.y += 0.5; 13 | gl_Position = projection * adjpos; 14 | colour = vaCol; 15 | } 16 | -------------------------------------------------------------------------------- /src/GUI/UI/UIPartyCreation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GUI/GUIWindow.h" 4 | 5 | class Image; 6 | 7 | bool PartyCreationUI_Loop(); 8 | 9 | class GUIWindow_PartyCreation : public GUIWindow { 10 | public: 11 | GUIWindow_PartyCreation(); 12 | virtual ~GUIWindow_PartyCreation(); 13 | 14 | virtual void Update(); 15 | 16 | protected: 17 | Image *main_menu_background; 18 | }; 19 | -------------------------------------------------------------------------------- /src/Platform/PlatformGamepad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // TODO(captainurist): this should be just a POD 7 | class PlatformGamepad { 8 | public: 9 | virtual ~PlatformGamepad() = default; 10 | 11 | virtual std::string model() const = 0; 12 | virtual std::string serial() const = 0; 13 | 14 | virtual uint32_t id() const = 0; 15 | }; 16 | -------------------------------------------------------------------------------- /src/Utility/Memory/MemSet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template 7 | inline void memzero(T *dst) { 8 | memset(dst, 0, sizeof(*dst)); 9 | } 10 | 11 | inline void memset32(void *ptr, uint32_t value, int count) { 12 | uint32_t *p = static_cast(ptr); 13 | for (int i = 0; i < count; i++) 14 | *p++ = value; 15 | } 16 | -------------------------------------------------------------------------------- /src/Utility/Streams/InputStream.cpp: -------------------------------------------------------------------------------- 1 | #include "InputStream.h" 2 | 3 | #include 4 | 5 | #include "Utility/Format.h" 6 | 7 | void InputStream::ReadOrFail(void *data, size_t size) { 8 | size_t read = Read(data, size); 9 | if (read != size) 10 | throw std::runtime_error(fmt::format("Failed to read the requested number of bytes from a stream, requested {}, got {}", size, read)); 11 | } 12 | -------------------------------------------------------------------------------- /src/Application/GameFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Game.h" 7 | #include "GameConfig.h" 8 | 9 | class PlatformApplication; 10 | 11 | namespace Application { 12 | 13 | class GameFactory { 14 | public: 15 | std::shared_ptr CreateGame(PlatformApplication *app, const std::shared_ptr &config); 16 | }; 17 | 18 | } // namespace Application 19 | -------------------------------------------------------------------------------- /src/Utility/Preprocessor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /** 4 | * Concatenates two tokens together, performing macro substitution first. 5 | */ 6 | #define MM_PP_CAT(x, y) MM_PP_CAT_I(x, y) 7 | 8 | #define MM_PP_CAT_I(x, y) x ## y 9 | 10 | /** 11 | * Removes parentheses from the provided argument. 12 | */ 13 | #define MM_PP_REMOVE_PARENS(x) MM_PP_REMOVE_PARENS_I x 14 | 15 | #define MM_PP_REMOVE_PARENS_I(...) __VA_ARGS__ 16 | -------------------------------------------------------------------------------- /src/Engine/stru159.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Engine/Events2D.h" 4 | 5 | /* 152 */ 6 | // Originally was a packed struct. 7 | struct stru159 { 8 | const char *video_name; 9 | int field_4; 10 | int house_npc_id; 11 | BuildingType uBuildingType; // Originally was 1 byte. 12 | uint8_t uRoomSoundId; 13 | uint16_t padding_e; 14 | }; 15 | 16 | extern std::array pAnimatedRooms; 17 | -------------------------------------------------------------------------------- /src/Engine/Graphics/IRenderFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "Application/GameConfig.h" 6 | 7 | #include "RendererType.h" 8 | 9 | class IRender; 10 | class OSWindow; 11 | 12 | namespace Graphics { 13 | class IRenderFactory { 14 | public: 15 | std::shared_ptr Create(std::shared_ptr config); 16 | }; 17 | } // namespace Graphics 18 | -------------------------------------------------------------------------------- /src/Engine/Graphics/Weather.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | class Weather { 7 | public: 8 | Weather() : bNight(false), bRenderSnow(false) {} 9 | 10 | void DrawSnow(); 11 | void Initialize(); 12 | void Draw(); 13 | bool OnPlayerTurn(int dangle); 14 | 15 | std::array Screen_Coord; 16 | bool bNight; 17 | bool bRenderSnow; 18 | }; 19 | 20 | extern Weather *pWeather; 21 | -------------------------------------------------------------------------------- /src/GUI/UI/UIChest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GUI/GUIWindow.h" 4 | 5 | extern int pChestWidthsByType[8]; 6 | extern int pChestHeightsByType[8]; 7 | extern int pChestPixelOffsetX[8]; 8 | extern int pChestPixelOffsetY[8]; 9 | 10 | class GUIWindow_Chest : public GUIWindow { 11 | public: 12 | explicit GUIWindow_Chest(unsigned int chest_id); 13 | virtual ~GUIWindow_Chest() {} 14 | 15 | virtual void Update(); 16 | }; 17 | -------------------------------------------------------------------------------- /src/Library/Random/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(RANDOM_SOURCES Random.cpp 4 | RandomEngine.cpp) 5 | 6 | set(RANDOM_HEADERS Random.h 7 | RandomEngine.h 8 | MersenneTwisterRandomEngine.h 9 | NonRandomEngine.h) 10 | 11 | add_library(random STATIC ${RANDOM_SOURCES} ${RANDOM_HEADERS}) 12 | target_check_style(random) 13 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyGamepad.cpp: -------------------------------------------------------------------------------- 1 | #include "ProxyGamepad.h" 2 | 3 | ProxyGamepad::ProxyGamepad(PlatformGamepad *base): ProxyBase(base) {} 4 | 5 | std::string ProxyGamepad::model() const { 6 | return nonNullBase()->model(); 7 | } 8 | 9 | std::string ProxyGamepad::serial() const { 10 | return nonNullBase()->serial(); 11 | } 12 | 13 | uint32_t ProxyGamepad::id() const { 14 | return nonNullBase()->id(); 15 | } 16 | -------------------------------------------------------------------------------- /src/Io/Key.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Platform/PlatformEnums.h" 7 | 8 | #include "Library/Serialization/SerializationFwd.h" 9 | 10 | // TODO(captainurist): find a better place for this code 11 | 12 | MM_DECLARE_SERIALIZATION_FUNCTIONS(PlatformKey) 13 | 14 | std::string GetDisplayName(PlatformKey key); 15 | bool TryParseDisplayName(std::string_view displayName, PlatformKey *outKey); 16 | -------------------------------------------------------------------------------- /src/GUI/UI/UIGameOver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GUI/GUIWindow.h" 4 | 5 | class GUIWindow_GameOver : public GUIWindow { 6 | public: 7 | explicit GUIWindow_GameOver(UIMessageType on_release_event = UIMSG_OnGameOverWindowClose); 8 | virtual ~GUIWindow_GameOver() {} 9 | 10 | virtual void Update(); 11 | virtual void Release(); 12 | 13 | protected: 14 | CURRENT_SCREEN prev_screen_type; 15 | int64_t _tickcount{}; 16 | }; 17 | -------------------------------------------------------------------------------- /src/Platform/Posix/PosixPlatform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Platform/Sdl/SdlPlatform.h" 4 | #include "Platform/Sdl/SdlLogger.h" 5 | 6 | std::unique_ptr Platform::createStandardPlatform(PlatformLogger *logger) { 7 | return std::make_unique(logger); 8 | } 9 | 10 | std::unique_ptr PlatformLogger::createStandardLogger(PlatformLoggerOptions) { 11 | return std::make_unique(); 12 | } 13 | -------------------------------------------------------------------------------- /test/Testing/Extensions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | if(ENABLE_TESTS) 4 | set(TEST_EXTENSIONS_SOURCES ThrowingAssertions.cpp) 5 | set(TEST_EXTENSIONS_HEADERS ThrowingAssertions.h) 6 | 7 | add_library(test_extensions ${TEST_EXTENSIONS_SOURCES} ${TEST_EXTENSIONS_HEADERS}) 8 | target_link_libraries(test_extensions GTest::gtest) 9 | 10 | target_check_style(test_extensions) 11 | endif() 12 | -------------------------------------------------------------------------------- /src/Application/IocContainer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace Application { 6 | 7 | class Menu; 8 | class GameWindowHandler; 9 | 10 | class IocContainer { 11 | public: 12 | static Menu *ResolveGameMenu(); 13 | static GameWindowHandler *ResolveGameWindowHandler(); 14 | 15 | private: 16 | static Menu *menu; 17 | static GameWindowHandler *gameWindowHandler; 18 | }; 19 | 20 | } // namespace Application 21 | -------------------------------------------------------------------------------- /test/Testing/Unit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | if(ENABLE_TESTS) 4 | set(UNIT_TEST_SOURCES UnitTest.cpp) 5 | set(UNIT_TEST_HEADERS UnitTest.h) 6 | 7 | add_library(unit_test ${UNIT_TEST_SOURCES} ${UNIT_TEST_HEADERS}) 8 | target_link_libraries(unit_test GTest::gtest) 9 | target_compile_definitions(unit_test PRIVATE TEST_GROUP=None) 10 | 11 | target_check_style(unit_test) 12 | endif() 13 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlLogger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class SdlLogger: public PlatformLogger { 6 | public: 7 | virtual void setLogLevel(PlatformLogCategory category, PlatformLogLevel logLevel) override; 8 | virtual PlatformLogLevel logLevel(PlatformLogCategory category) const override; 9 | 10 | virtual void log(PlatformLogCategory category, PlatformLogLevel logLevel, const char *message) override; 11 | }; 12 | -------------------------------------------------------------------------------- /src/Utility/Memory/FreeDeleter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /** 6 | * Deleter class to be used with `std::unique_ptr` for managing memory allocated with `malloc`. 7 | * 8 | * Example usage: 9 | * ``` 10 | * std::unique_ptr ptr(malloc(1000)); 11 | * ``` 12 | */ 13 | struct FreeDeleter { 14 | template 15 | void operator()(const T *p) const { 16 | std::free(const_cast(p)); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /resources/shaders/gltextshader.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | in vec4 colour; 4 | in vec2 texuv; 5 | flat in float olayer; 6 | 7 | out vec4 FragColour; 8 | 9 | uniform sampler2D texture0; 10 | uniform sampler2D texture1; 11 | 12 | void main() { 13 | vec4 col; 14 | if (int(olayer) == 0) { 15 | col = texture(texture0, texuv) * colour; 16 | } else { 17 | col = texture(texture1, texuv) * colour; 18 | } 19 | 20 | FragColour = col; 21 | } -------------------------------------------------------------------------------- /src/Library/Application/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(APPLICATION_SOURCES PlatformApplication.cpp) 4 | 5 | set(APPLICATION_HEADERS PlatformApplication.h 6 | PlatformApplicationAware.h 7 | PlatformIntrospection.h) 8 | 9 | add_library(application STATIC ${APPLICATION_SOURCES} ${APPLICATION_HEADERS}) 10 | target_link_libraries(application platform) 11 | target_check_style(application) 12 | -------------------------------------------------------------------------------- /src/Library/Compression/Compression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Utility/Memory/Blob.h" 4 | 5 | namespace zlib { 6 | // TODO(captainurist): Drop non-Blob versions. 7 | int Compress(void *dest, unsigned int *destLen, void *source, unsigned int sourceLen); 8 | int Uncompress(void *dest, unsigned int *destLen, const void *source, unsigned int sourceLen); 9 | 10 | Blob Compress(const Blob &source); 11 | Blob Uncompress(const Blob &source, size_t sizeHint = 0); 12 | }; // namespace zlib 13 | -------------------------------------------------------------------------------- /resources/shaders/gltextshader.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec2 vaTexUV; 3 | layout (location = 2) in vec4 vaCol; 4 | layout (location = 3) in float vaTexID; 5 | 6 | out vec4 colour; 7 | out vec2 texuv; 8 | flat out float olayer; 9 | 10 | uniform mat4 view; 11 | uniform mat4 projection; 12 | 13 | void main() { 14 | gl_Position = projection * view * vec4(vaPos, 1.0); 15 | colour = vaCol; 16 | texuv = vaTexUV; 17 | olayer = vaTexID; 18 | } -------------------------------------------------------------------------------- /src/Utility/Streams/StringOutputStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "OutputStream.h" 6 | 7 | class StringOutputStream: public OutputStream { 8 | public: 9 | explicit StringOutputStream(std::string *target); 10 | virtual ~StringOutputStream(); 11 | virtual void Write(const void *data, size_t size) override; 12 | virtual void Flush() override; 13 | virtual void Close() override; 14 | 15 | private: 16 | std::string *target_ = nullptr; 17 | }; 18 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyGamepad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/PlatformGamepad.h" 6 | 7 | #include "ProxyBase.h" 8 | 9 | class ProxyGamepad: public ProxyBase { 10 | public: 11 | explicit ProxyGamepad(PlatformGamepad *base = nullptr); 12 | virtual ~ProxyGamepad() = default; 13 | 14 | virtual std::string model() const override; 15 | virtual std::string serial() const override; 16 | virtual uint32_t id() const override; 17 | }; 18 | -------------------------------------------------------------------------------- /src/Library/Compression/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(COMPRESSION_SOURCES Compression.cpp) 4 | 5 | set(COMPRESSION_HEADERS Compression.h) 6 | 7 | add_library(compression STATIC ${COMPRESSION_SOURCES} ${COMPRESSION_HEADERS}) 8 | target_link_libraries(compression utility ${ZLIB_LIBRARIES}) 9 | target_include_directories(compression PRIVATE ${ZLIB_INCLUDE_DIRS}) 10 | target_check_style(compression) 11 | 12 | message(VERBOSE "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}") 13 | -------------------------------------------------------------------------------- /src/Library/Random/NonRandomEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RandomEngine.h" 4 | 5 | class NonRandomEngine : public RandomEngine { 6 | public: 7 | virtual float RandomFloat() override { 8 | return Random(256) / 256.0f; 9 | } 10 | 11 | virtual uint32_t Random(uint32_t hi) override { 12 | return ++state_ % hi; 13 | } 14 | 15 | virtual void Seed(uint32_t seed) override { 16 | state_ = seed; 17 | } 18 | 19 | private: 20 | uint32_t state_ = 0; 21 | }; 22 | -------------------------------------------------------------------------------- /resources/shaders/gltwodshader.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec2 vaTexUV; 3 | layout (location = 2) in vec4 vaCol; 4 | 5 | layout (location = 4) in float palid; 6 | 7 | 8 | out vec4 colour; 9 | out vec2 texuv; 10 | flat out int paletteid; 11 | 12 | uniform mat4 view; 13 | uniform mat4 projection; 14 | 15 | void main() { 16 | gl_Position = projection * view * vec4(vaPos, 1.0); 17 | colour = vaCol; 18 | texuv = vaTexUV; 19 | paletteid = int(palid); 20 | } 21 | -------------------------------------------------------------------------------- /src/Library/Config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(CONFIG_SOURCES Config.cpp 4 | ConfigSection.cpp) 5 | 6 | set(CONFIG_HEADERS AbstractConfigValue.h 7 | Config.h 8 | ConfigFwd.h 9 | ConfigSection.h 10 | ConfigValue.h) 11 | 12 | add_library(config STATIC ${CONFIG_SOURCES} ${CONFIG_HEADERS}) 13 | target_link_libraries(config utility serialization) 14 | target_check_style(config) 15 | -------------------------------------------------------------------------------- /src/Application/GamePathResolver.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | class Platform; 5 | 6 | 7 | namespace Application { 8 | 9 | constexpr char mm6PathOverrideKey[] = "OPENENROTH_MM6_PATH"; 10 | constexpr char mm7PathOverrideKey[] = "OPENENROTH_MM7_PATH"; 11 | constexpr char mm8PathOverrideKey[] = "OPENENROTH_MM8_PATH"; 12 | 13 | std::string resolveMm6Path(Platform *platform); 14 | std::string resolveMm7Path(Platform *platform); 15 | std::string resolveMm8Path(Platform *platform); 16 | 17 | }; // namespace Application 18 | -------------------------------------------------------------------------------- /src/Engine/Serialization/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(ENGINE_SERIALIZATION_SOURCES LegacyImages.cpp) 4 | 5 | set(ENGINE_SERIALIZATION_HEADERS LegacyImages.h 6 | Deserializer.h 7 | Serializer.h) 8 | 9 | add_library(engine_serialization STATIC ${ENGINE_SERIALIZATION_SOURCES} ${ENGINE_SERIALIZATION_HEADERS}) 10 | target_link_libraries(engine_serialization engine) 11 | target_check_style(engine_serialization) 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/suggestion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Suggestion 3 | about: Share an idea for an improvement 4 | title: '' 5 | labels: 'enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the Idea** 11 | A clear and concise description of your suggestion. 12 | 13 | **Changes from original** 14 | Explain what behaviour changes from original in more detail. 15 | Cover your reasoning and consider game balance and different playstyles. 16 | 17 | **Screenshots** 18 | If applicable, add screenshots to help explain your idea. 19 | -------------------------------------------------------------------------------- /src/GUI/UI/UICredits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GUI/GUIWindow.h" 4 | 5 | class GUIFont; 6 | 7 | class GUICredits : public GUIWindow { 8 | public: 9 | GUICredits(); 10 | virtual ~GUICredits(); 11 | 12 | virtual void Update(); 13 | 14 | static void ExecuteCredits(); 15 | void EventLoop(); 16 | 17 | protected: 18 | GUIFont *pFontQuick; 19 | GUIFont *pFontCChar; 20 | 21 | Image *mm6title; 22 | 23 | int width; 24 | int height; 25 | Texture *cred_texture; 26 | float move_Y; 27 | }; 28 | -------------------------------------------------------------------------------- /src/Application/GameFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "GameFactory.h" 2 | 3 | #include "Game.h" 4 | #include "GameConfig.h" 5 | 6 | using Application::Game; 7 | using Application::GameConfig; 8 | using Application::GameFactory; 9 | 10 | std::shared_ptr GameFactory::CreateGame(PlatformApplication *app, const std::shared_ptr &config) { 11 | auto game = std::make_shared(app); 12 | if (game) { 13 | if (game->Configure(config)) { 14 | return game; 15 | } 16 | } 17 | return nullptr; 18 | } 19 | -------------------------------------------------------------------------------- /src/Application/GameMenu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "Engine/IocContainer.h" 5 | 6 | #include "Io/Mouse.h" 7 | 8 | using EngineIoc = Engine_::IocContainer; 9 | using Io::Mouse; 10 | 11 | namespace Application { 12 | 13 | class Menu { 14 | public: 15 | inline Menu() { 16 | this->mouse = EngineIoc::ResolveMouse(); 17 | } 18 | 19 | void MenuLoop(); 20 | 21 | private: 22 | std::shared_ptr mouse = nullptr; 23 | 24 | void EventLoop(); 25 | }; 26 | 27 | } // namespace Application 28 | -------------------------------------------------------------------------------- /src/Library/Json/JsonFwd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | using Json = nlohmann::json; 6 | 7 | /** 8 | * @param TYPE Type to forward-declare json serialization functions for. 9 | */ 10 | #define MM_DECLARE_JSON_SERIALIZATION_FUNCTIONS(TYPE) \ 11 | void to_json(Json &json, const TYPE &value); \ 12 | void from_json(const Json &j, TYPE &value); 13 | 14 | -------------------------------------------------------------------------------- /src/Engine/Autonotes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | /* 351 */ 5 | enum class AUTONOTE_TYPE : uint32_t { 6 | AUTONOTE_POTION_RECEPIE = 0, 7 | AUTONOTE_STAT_HINT = 1, 8 | AUTONOTE_OBELISK = 2, 9 | AUTONOTE_SEER = 3, 10 | AUTONOTE_MISC = 4, 11 | AUTONOTE_TEACHER = 5, 12 | }; 13 | using enum AUTONOTE_TYPE; 14 | 15 | /* 350 */ 16 | #pragma pack(push, 1) 17 | struct Autonote { 18 | const char *pText; 19 | AUTONOTE_TYPE eType; 20 | }; 21 | #pragma pack(pop) 22 | extern std::array pAutonoteTxt; 23 | -------------------------------------------------------------------------------- /src/Library/Random/RandomEngine.cpp: -------------------------------------------------------------------------------- 1 | #include "RandomEngine.h" 2 | 3 | #include 4 | 5 | int RandomEngine::RandomInSegment(int min, int max) { 6 | assert(max >= min); 7 | 8 | return min + Random(max - min + 1); 9 | } 10 | 11 | int RandomEngine::RandomDice(int count, int faces) { 12 | assert(count >= 0 && faces >= 0); 13 | 14 | if (count == 0 || faces == 0) 15 | return 0; 16 | 17 | int result = 0; 18 | for (int i = 0; i < count; i++) 19 | result += 1 + Random(faces); 20 | return result; 21 | } 22 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyOpenGLContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Platform/PlatformOpenGLContext.h" 4 | 5 | #include "ProxyBase.h" 6 | 7 | class ProxyOpenGLContext: public ProxyBase { 8 | public: 9 | explicit ProxyOpenGLContext(PlatformOpenGLContext *base = nullptr); 10 | virtual ~ProxyOpenGLContext() = default; 11 | 12 | virtual bool bind() override; 13 | virtual bool unbind() override; 14 | virtual void swapBuffers() override; 15 | virtual void *getProcAddress(const char *name) override; 16 | }; 17 | -------------------------------------------------------------------------------- /src/Utility/Streams/MemoryInputStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "InputStream.h" 4 | 5 | class MemoryInputStream: public InputStream { 6 | public: 7 | MemoryInputStream(); 8 | MemoryInputStream(const void *data, size_t size); 9 | virtual ~MemoryInputStream(); 10 | 11 | void Reset(const void *data, size_t size); 12 | 13 | virtual size_t Read(void *data, size_t size) override; 14 | virtual size_t Skip(size_t size) override; 15 | 16 | private: 17 | const char *pos_ = nullptr; 18 | const char *end_ = nullptr; 19 | }; 20 | -------------------------------------------------------------------------------- /src/Engine/stru367.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "Engine/OurMath.h" 5 | 6 | /* 152 */ 7 | #pragma pack(push, 1) 8 | struct stru367 { 9 | bool direction; // is portal faced to camera 10 | std::array field_4; 11 | std::array _view_transformed_x; 12 | std::array _view_transformed_y; 13 | std::array _view_transformed_z; 14 | std::array _screen_space_y; 15 | std::array _screen_space_x; 16 | }; 17 | #pragma pack(pop) 18 | 19 | // extern const stru367 stru_367; 20 | -------------------------------------------------------------------------------- /src/Library/Lod/Internal/LodDirectoryHeader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // memset 5 | #include 6 | 7 | 8 | #pragma pack(push, 1) 9 | struct LodDirectoryHeader_Mm6 { 10 | inline LodDirectoryHeader_Mm6() { 11 | memset(this, 0, sizeof(this)); 12 | } 13 | 14 | std::array filename; 15 | std::uint32_t dataOffset; 16 | std::uint32_t dataSize; 17 | std::uint32_t dword_000018; 18 | std::uint16_t numFiles; 19 | std::uint16_t priority; 20 | }; 21 | #pragma pack(pop) 22 | -------------------------------------------------------------------------------- /src/Utility/Embedded.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /** 6 | * Base class implementing the base-from-member idiom. 7 | * 8 | * @tparam T Stored type. 9 | */ 10 | template 11 | class Embedded { 12 | public: 13 | template 14 | explicit Embedded(Args &&...args): data_(std::forward(args)...) {} 15 | 16 | T &get() { 17 | return data_; 18 | } 19 | 20 | const T &get() const { 21 | return data_; 22 | } 23 | 24 | private: 25 | T data_; 26 | }; 27 | -------------------------------------------------------------------------------- /src/Utility/Workaround/ToUnderlying.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /* TODO: this workaround is bizarrely still needed for latest Android's NDK (25.1.8937393) which is based on CLang 14.0.6 7 | * Bring it back for now and investigate why later. */ 8 | #ifndef __cpp_lib_to_underlying 9 | 10 | namespace std { 11 | template 12 | [[nodiscard]] inline constexpr underlying_type_t to_underlying(T value) noexcept { 13 | return static_cast>(value); 14 | } 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /src/GUI/UI/Spellbook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/GUIWindow.h" 3 | 4 | class GUIWindow_Spellbook : public GUIWindow { 5 | public: 6 | GUIWindow_Spellbook(); 7 | virtual ~GUIWindow_Spellbook() {} 8 | 9 | virtual void Update(); 10 | virtual void Release(); 11 | 12 | void OpenSpellbook(); 13 | void OpenSpellbookPage(int page); 14 | }; 15 | 16 | class Image; 17 | extern Image *ui_spellbook_btn_quckspell; 18 | extern Image *ui_spellbook_btn_quckspell_click; 19 | extern Image *ui_spellbook_btn_close; 20 | extern Image *ui_spellbook_btn_close_click; 21 | -------------------------------------------------------------------------------- /test/Bin/UnitTest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | if(ENABLE_TESTS) 4 | set(UNIT_TEST_MAIN_SOURCES UnitTestMain.cpp) 5 | 6 | add_executable(OpenEnroth_UnitTest ${UNIT_TEST_MAIN_SOURCES}) 7 | target_fix_libcxx_assertions(OpenEnroth_UnitTest) 8 | target_link_libraries(OpenEnroth_UnitTest unit_test) 9 | 10 | add_custom_target(UnitTest OpenEnroth_UnitTest 11 | DEPENDS OpenEnroth_UnitTest 12 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) 13 | 14 | target_check_style(OpenEnroth_UnitTest) 15 | endif() 16 | -------------------------------------------------------------------------------- /thirdparty/glad/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | project(glad) 4 | 5 | set(GLAD_GL_SOURCES src/gl.c 6 | src/egl.c) 7 | 8 | set(GLAD_GL_HEADERS include/glad/gl.h 9 | include/glad/egl.h 10 | include/EGL/eglplatform.h 11 | include/KHR/khrplatform.h) 12 | 13 | add_library(glad STATIC ${GLAD_GL_SOURCES} ${GLAD_GL_HEADERS}) 14 | target_include_directories(glad PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include") 15 | 16 | source_check_style(glad "${GLAD_GL_SOURCES}") 17 | -------------------------------------------------------------------------------- /src/Engine/EngineGlobals.cpp: -------------------------------------------------------------------------------- 1 | #include "EngineGlobals.h" 2 | 3 | #include "Library/Application/PlatformApplication.h" 4 | 5 | Platform *platform = nullptr; 6 | PlatformWindow *window = nullptr; 7 | PlatformOpenGLContext *openGLContext = nullptr; 8 | PlatformEventLoop *eventLoop = nullptr; 9 | PlatformEventHandler *eventHandler = nullptr; 10 | PlatformApplication *application = nullptr; 11 | 12 | 13 | void detail::globalProcessMessages() { 14 | application->processMessages(); 15 | } 16 | 17 | void detail::globalWaitForMessages() { 18 | application->waitForMessages(); 19 | } 20 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyEventLoop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Platform/PlatformEventLoop.h" 4 | 5 | #include "ProxyBase.h" 6 | 7 | class ProxyEventLoop: public ProxyBase { 8 | public: 9 | explicit ProxyEventLoop(PlatformEventLoop *base = nullptr); 10 | virtual ~ProxyEventLoop() = default; 11 | 12 | virtual void exec(PlatformEventHandler *eventHandler) override; 13 | virtual void quit() override; 14 | virtual void processMessages(PlatformEventHandler *eventHandler, int count = -1) override; 15 | virtual void waitForMessages() override; 16 | }; 17 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyOpenGLContext.cpp: -------------------------------------------------------------------------------- 1 | #include "ProxyOpenGLContext.h" 2 | 3 | ProxyOpenGLContext::ProxyOpenGLContext(PlatformOpenGLContext *base) : ProxyBase(base) {} 4 | 5 | bool ProxyOpenGLContext::bind() { 6 | return nonNullBase()->bind(); 7 | } 8 | 9 | bool ProxyOpenGLContext::unbind() { 10 | return nonNullBase()->unbind(); 11 | } 12 | 13 | void ProxyOpenGLContext::swapBuffers() { 14 | nonNullBase()->swapBuffers(); 15 | } 16 | 17 | void *ProxyOpenGLContext::getProcAddress(const char *name) { 18 | return nonNullBase()->getProcAddress(name); 19 | } 20 | -------------------------------------------------------------------------------- /thirdparty/luajit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | list(APPEND CMAKE_MODULE_PATH 4 | "${CMAKE_CURRENT_SOURCE_DIR}/luajit/cmake" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/luajit/cmake/modules" 6 | ) 7 | 8 | set(LUAJIT_TOP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/luajit) 9 | 10 | project(luajit) 11 | 12 | execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory 13 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake" "${CMAKE_CURRENT_SOURCE_DIR}/luajit") 14 | 15 | set(can_use_assembler TRUE) 16 | enable_language(ASM) 17 | 18 | include (GNUInstallDirs) 19 | 20 | add_subdirectory(luajit/src) 21 | -------------------------------------------------------------------------------- /src/Io/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(IO_SOURCES InputAction.cpp 4 | KeyboardActionMapping.cpp 5 | KeyboardInputHandler.cpp 6 | Mouse.cpp) 7 | 8 | set(IO_HEADERS IKeyboardController.h 9 | InputAction.h 10 | KeyboardActionMapping.h 11 | KeyboardInputHandler.h 12 | Mouse.h 13 | Key.h 14 | Key.cpp) 15 | 16 | add_library(io STATIC ${IO_SOURCES} ${IO_HEADERS}) 17 | target_link_libraries(io serialization) 18 | target_check_style(io) 19 | -------------------------------------------------------------------------------- /src/Engine/Graphics/PCX.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Image.h" 6 | 7 | namespace PCX { 8 | uint8_t *Decode(const void *pcx_data, size_t filesize, unsigned int *width, 9 | unsigned int *height, IMAGE_FORMAT *format, IMAGE_FORMAT requested_format); 10 | void Encode16(const void *picture_data, unsigned int width, unsigned int height, 11 | void *pcx_data, int max_buff_size, unsigned int *packed_size); 12 | void Encode32(const void *picture_data, unsigned int width, unsigned int height, 13 | void *pcx_data, int max_buff_size, unsigned int *packed_size); 14 | } // namespace PCX 15 | -------------------------------------------------------------------------------- /src/Library/Trace/PaintEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/PlatformEvents.h" 6 | 7 | #include "Utility/Workaround/ToUnderlying.h" 8 | 9 | inline constexpr PlatformEventType EVENT_PAINT = static_cast(std::to_underlying(EVENT_LAST) + 1); 10 | 11 | class PaintEvent : public PlatformEvent { 12 | public: 13 | /** Tick count for the next frame. */ 14 | int64_t tickCount = -1; // 15 | 16 | /** Result of `grng->Random(1024)` call from inside `swapBuffers`, basically a random state at the start of the 17 | * next frame. */ 18 | int randomState = -1; 19 | }; 20 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyEventLoop.cpp: -------------------------------------------------------------------------------- 1 | #include "ProxyEventLoop.h" 2 | 3 | ProxyEventLoop::ProxyEventLoop(PlatformEventLoop *base) : ProxyBase(base) {} 4 | 5 | void ProxyEventLoop::exec(PlatformEventHandler *eventHandler) { 6 | nonNullBase()->exec(eventHandler); 7 | } 8 | 9 | void ProxyEventLoop::quit() { 10 | nonNullBase()->quit(); 11 | } 12 | 13 | void ProxyEventLoop::processMessages(PlatformEventHandler *eventHandler, int count) { 14 | nonNullBase()->processMessages(eventHandler, count); 15 | } 16 | 17 | void ProxyEventLoop::waitForMessages() { 18 | nonNullBase()->waitForMessages(); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/Utility/Math/Float.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | [[nodiscard]] inline bool FuzzyIsNull(float value) { 7 | return std::abs(value) < 0.00001f; 8 | } 9 | 10 | [[nodiscard]] inline bool FuzzyIsNull(double value) { 11 | return std::abs(value) < 0.000000000001; 12 | } 13 | 14 | [[nodiscard]] inline bool FuzzyEquals(float l, float r) { 15 | return std::abs(l - r) * 100000.f <= std::min(std::abs(l), std::abs(r)); 16 | } 17 | 18 | [[nodiscard]] inline bool FuzzyEquals(double l, double r) { 19 | return std::abs(l - r) * 1000000000000. <= std::min(std::abs(l), std::abs(r)); 20 | } 21 | -------------------------------------------------------------------------------- /src/Engine/stru160.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 153 */ 4 | #pragma pack(push, 1) 5 | struct stru160 { 6 | inline stru160() {} 7 | inline stru160(float a, float b, float c) 8 | : field_0(a), field_4(b), field_8(c) {} 9 | 10 | float field_0 = 0; 11 | float field_4 = 0; 12 | float field_8 = 0; 13 | }; 14 | #pragma pack(pop) 15 | 16 | #pragma pack(push, 1) 17 | struct stru16x : public stru160 { 18 | float field_C = 0; 19 | }; 20 | #pragma pack(pop) 21 | 22 | extern std::array array_4EB8B8; 23 | extern std::array array_4EBBD0; 24 | extern std::array array_4EBBD0_x; 25 | -------------------------------------------------------------------------------- /src/Utility/Streams/FileOutputStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "OutputStream.h" 7 | 8 | class FileOutputStream : public OutputStream { 9 | public: 10 | explicit FileOutputStream(const std::string &path); 11 | virtual ~FileOutputStream(); 12 | virtual void Write(const void *data, size_t size) override; 13 | virtual void Flush() override; 14 | virtual void Close() override; 15 | 16 | private: 17 | void CloseInternal(bool canThrow); 18 | [[noreturn]] void ThrowFromErrno(); 19 | 20 | private: 21 | std::string path_; 22 | FILE *file_ = nullptr; 23 | }; 24 | -------------------------------------------------------------------------------- /src/Engine/stru298.cpp: -------------------------------------------------------------------------------- 1 | #include "Engine/stru298.h" 2 | 3 | //----- (0040261D) -------------------------------------------------------- 4 | void stru298::Add(int16_t uID, int16_t a3, int16_t x, int16_t y, int16_t z, 5 | ABILITY_INDEX a7, char a8) { 6 | if (count < 100) { 7 | pIDs[count] = uID; 8 | pXs[count] = x; 9 | pYs[count] = y; 10 | pZs[count] = z; 11 | attack_range[count] = a3; // a3 = 5120 for melee attack (attack range?) 12 | attack_type[count] = a8; // a8 = 1 for melee / 0 for spells 13 | attack_special[count++] = a7; // a7 = special ability 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Platform/Filters/FilteringEventHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/PlatformEventHandler.h" 6 | 7 | #include "Utility/IndexedArray.h" 8 | 9 | class PlatformEventFilter; 10 | 11 | class FilteringEventHandler : public PlatformEventHandler { 12 | public: 13 | virtual void event(const PlatformEvent *event) override; 14 | 15 | void installEventFilter(PlatformEventFilter *filter); 16 | void removeEventFilter(PlatformEventFilter *filter); 17 | 18 | private: 19 | IndexedArray, EVENT_FIRST, EVENT_LAST> _filters; 20 | bool _insideEvent = false; 21 | }; 22 | -------------------------------------------------------------------------------- /src/Utility/Math/Tests/Float_ut.cpp: -------------------------------------------------------------------------------- 1 | #include "Testing/Unit/UnitTest.h" 2 | 3 | #include "Utility/Math/Float.h" 4 | 5 | UNIT_TEST(Float, Fuzzy) { 6 | EXPECT_TRUE(FuzzyIsNull(0.000001f)); 7 | EXPECT_FALSE(FuzzyIsNull(0.0001f)); 8 | 9 | EXPECT_TRUE(FuzzyIsNull(0.0000000000001)); 10 | EXPECT_FALSE(FuzzyIsNull(0.00000000001)); 11 | 12 | EXPECT_TRUE(FuzzyEquals(1.0f, 1.0000001f)); 13 | EXPECT_FALSE(FuzzyEquals(10000.0f, 10001.0f)); 14 | 15 | EXPECT_TRUE(FuzzyEquals(1.0f, 1.0f)); 16 | EXPECT_TRUE(FuzzyEquals(1.0, 1.0)); 17 | EXPECT_FALSE(FuzzyEquals(1.0f, 2.0f)); 18 | EXPECT_FALSE(FuzzyEquals(1.0, 2.0)); 19 | } 20 | -------------------------------------------------------------------------------- /test/Testing/Game/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | if(ENABLE_TESTS) 4 | set(GAME_TEST_SOURCES GameTest.cpp 5 | TestConfig.cpp 6 | TestController.cpp) 7 | set(GAME_TEST_HEADERS GameTest.h 8 | TestConfig.h 9 | TestController.h) 10 | 11 | add_library(game_test ${GAME_TEST_SOURCES} ${GAME_TEST_HEADERS}) 12 | target_link_libraries(game_test game test_extensions GTest::gtest) 13 | target_compile_definitions(game_test PRIVATE TEST_GROUP=None) 14 | 15 | target_check_style(game_test) 16 | endif() 17 | -------------------------------------------------------------------------------- /src/Engine/Tables/FrameTableInc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 322 */ 4 | enum FRAME_TABLE_FLAGS { 5 | FRAME_TABLE_MORE_FRAMES = 0x1, 6 | FRAME_TABLE_FIRST = 0x4, 7 | }; 8 | 9 | /* 359 */ 10 | #pragma pack(push, 1) 11 | struct FrameTableTxtLine { // 7C 12 | int uPropCount; 13 | const char *pProperties[30]; 14 | }; 15 | #pragma pack(pop) 16 | 17 | FrameTableTxtLine *txt_file_frametable_parser(const char *str_to_parse, 18 | FrameTableTxtLine *tokens_table); 19 | 20 | FrameTableTxtLine *frame_table_txt_parser(const char *pString, 21 | FrameTableTxtLine *a2); 22 | -------------------------------------------------------------------------------- /src/Library/Lod/Internal/LodHeader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // memset 5 | #include 6 | 7 | 8 | #pragma pack(push, 1) 9 | struct LodHeader_Mm6 { 10 | inline LodHeader_Mm6() { 11 | memset(this, 0, sizeof(this)); 12 | } 13 | 14 | std::array signature; 15 | std::array version; 16 | std::array description; 17 | std::uint32_t size; 18 | std::uint32_t dword_0000A8; 19 | std::uint32_t numDirectories; 20 | std::array _unused; // never set/accessed so stores random memory garbage 21 | }; 22 | #pragma pack(pop) 23 | -------------------------------------------------------------------------------- /src/Utility/DataPath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | void SetDataPath(const std::string &data_path); 7 | 8 | std::string MakeDataPath(std::initializer_list paths); 9 | 10 | template 11 | std::string MakeDataPath(Ts&&... paths) { 12 | static_assert(((std::is_same_v, std::string> || 13 | std::is_same_v, const char *>) && ...), 14 | "T must be a basic string"); 15 | return MakeDataPath({ paths... }); 16 | } 17 | 18 | std::string MakeTempPath(const char *file_rel_path); 19 | bool validateDataPath(const std::string &data_path); 20 | -------------------------------------------------------------------------------- /test/Testing/Game/TestController.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class EngineController; 8 | class EngineTracer; 9 | 10 | class TestController { 11 | public: 12 | TestController(EngineController *controller, const std::string &testDataPath); 13 | 14 | void loadGameFromTestData(const std::string &name); 15 | void playTraceFromTestData(const std::string &saveName, const std::string &traceName, std::function postLoadCallback); 16 | 17 | void prepareForNextTest(); 18 | 19 | private: 20 | EngineController *_controller; 21 | std::filesystem::path _testDataPath; 22 | }; 23 | -------------------------------------------------------------------------------- /src/Library/Random/MersenneTwisterRandomEngine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "RandomEngine.h" 7 | 8 | class MersenneTwisterRandomEngine: public RandomEngine { 9 | public: 10 | virtual float RandomFloat() override { 11 | return std::uniform_real_distribution(0.0f, 1.0f)(base_); 12 | } 13 | 14 | virtual uint32_t Random(uint32_t hi) override { 15 | assert(hi > 0); 16 | 17 | return (static_cast(base_()) * hi) >> 32; 18 | } 19 | 20 | virtual void Seed(uint32_t seed) override { 21 | base_.seed(seed); 22 | } 23 | 24 | private: 25 | std::mt19937 base_; 26 | }; 27 | -------------------------------------------------------------------------------- /src/Engine/Tables/StorylineTextTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #pragma pack(push, 1) 7 | struct StorylineRecord { 8 | char* pText; // 0 9 | char* pPageTitle; // 4 10 | uint8_t uTime; // 8 11 | char f_9; 12 | char f_A; 13 | char f_B; 14 | }; 15 | #pragma pack(pop) 16 | 17 | /* 173 */ 18 | #pragma pack(push, 1) 19 | struct StorylineText { 20 | void Initialize(); 21 | StorylineRecord StoreLine[29]; 22 | int field_15C; 23 | // int field_0; 24 | // int field_4[87]; 25 | }; 26 | #pragma pack(pop) 27 | 28 | extern std::string pHistoryTXT_Raw; 29 | extern struct StorylineText* pStorylineText; 30 | -------------------------------------------------------------------------------- /src/GUI/UI/UIRest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GUI/GUIWindow.h" 4 | 5 | class GUIWindow_Rest : public GUIWindow { 6 | public: 7 | GUIWindow_Rest(); 8 | virtual ~GUIWindow_Rest() {} 9 | 10 | virtual void Update(); 11 | }; 12 | 13 | class GUIWindow_RestWindow : public GUIWindow { 14 | public: 15 | GUIWindow_RestWindow(Pointi position, Sizei dimensions, WindowData data, const char *hint) : 16 | GUIWindow(WINDOW_Rest, position, dimensions, data, hint) 17 | {} 18 | virtual ~GUIWindow_RestWindow() {} 19 | 20 | virtual void Update(); 21 | }; 22 | 23 | extern class Image *rest_ui_sky_frame_current; 24 | extern class Image *rest_ui_hourglass_frame_current; 25 | -------------------------------------------------------------------------------- /src/GUI/UI/UIMainMenu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GUI/GUIWindow.h" 4 | 5 | class GUIWindow_MainMenu : public GUIWindow { 6 | public: 7 | GUIWindow_MainMenu(); 8 | virtual ~GUIWindow_MainMenu(); 9 | 10 | virtual void Update(); 11 | 12 | static void Loop(); 13 | void EventLoop(); 14 | 15 | protected: 16 | GUIButton *pBtnExit; 17 | GUIButton *pBtnCredits; 18 | GUIButton *pBtnLoad; 19 | GUIButton *pBtnNew; 20 | 21 | Image *main_menu_background; 22 | 23 | Image *ui_mainmenu_new; 24 | Image *ui_mainmenu_load; 25 | Image *ui_mainmenu_credits; 26 | Image *ui_mainmenu_exit; 27 | }; 28 | 29 | extern GUIWindow_MainMenu *pWindow_MainMenu; 30 | -------------------------------------------------------------------------------- /CMakeModules/AppleLibcxxAssertionWorkaround.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef _LIBCPP_DEBUG 5 | 6 | static void debug_handler(const std::__libcpp_debug_info &info) { 7 | const size_t bufsize = 1024; 8 | char buf[bufsize] = {}; 9 | char *pos = buf; 10 | char *end = buf + bufsize - 1; 11 | 12 | pos = stpncpy(pos, info.__pred_, end - pos); 13 | pos = stpncpy(pos, " (", end - pos); 14 | pos = stpncpy(pos, info.__msg_, end - pos); 15 | pos = stpncpy(pos, ")", end - pos); 16 | 17 | __assert_rtn("", info.__file_, info.__line_, buf); 18 | } 19 | 20 | std::__libcpp_debug_function_type std::__libcpp_debug_function = &debug_handler; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /src/Application/IocContainer.cpp: -------------------------------------------------------------------------------- 1 | #include "IocContainer.h" 2 | 3 | #include "GameMenu.h" 4 | #include "GameWindowHandler.h" 5 | 6 | 7 | using Application::IocContainer; 8 | using Application::Menu; 9 | using Application::GameWindowHandler; 10 | 11 | Menu *IocContainer::menu = nullptr; 12 | Menu *IocContainer::ResolveGameMenu() { 13 | if (!menu) { 14 | menu = new Menu(); 15 | } 16 | return menu; 17 | } 18 | 19 | GameWindowHandler *IocContainer::gameWindowHandler = nullptr; 20 | GameWindowHandler *IocContainer::ResolveGameWindowHandler() { 21 | if (!gameWindowHandler) { 22 | gameWindowHandler = new GameWindowHandler(); 23 | } 24 | return gameWindowHandler; 25 | } 26 | -------------------------------------------------------------------------------- /src/GUI/UI/UIShops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Engine/Events2D.h" 4 | 5 | void WeaponShopWares(GUIWindow dialogwin, bool special = 0); 6 | void ArmorShopWares(GUIWindow dialogwin, bool special = 0); 7 | void AlchemyMagicShopWares(GUIWindow dialogwin, BuildingType building, bool special = 0); 8 | 9 | 10 | void UIShop_Buy_Identify_Repair(); 11 | void sub_4B1523_showSpellbookInfo(ITEM_TYPE spellItemId); 12 | void ShowPopupShopSkills(); 13 | void ShowPopupShopItem(); 14 | void GetHouseGoodbyeSpeech(); 15 | void sub_4B1447_party_fine(int shopId, int stealingResult, int fineToAdd); 16 | 17 | extern class Image *shop_ui_background; 18 | 19 | extern std::array shop_ui_items_in_store; 20 | -------------------------------------------------------------------------------- /src/Platform/PlatformOpenGLOptions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class PlatformVSyncMode { 4 | GL_VSYNC_NONE, 5 | GL_VSYNC_ADAPTIVE, 6 | GL_VSYNC_NORMAL 7 | }; 8 | using enum PlatformVSyncMode; 9 | 10 | enum class PlatformOpenGLProfile { 11 | GL_PROFILE_CORE, 12 | GL_PROFILE_COMPATIBILITY, 13 | GL_PROFILE_ES 14 | }; 15 | using enum PlatformOpenGLProfile; 16 | 17 | struct PlatformOpenGLOptions { 18 | int versionMajor = -1; 19 | int versionMinor = -1; 20 | PlatformOpenGLProfile profile = GL_PROFILE_CORE; 21 | 22 | PlatformVSyncMode vsyncMode = GL_VSYNC_ADAPTIVE; 23 | bool doubleBuffered = true; 24 | 25 | int depthBits = -1; 26 | int stencilBits = -1; 27 | }; 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #env`s 2 | *.user 3 | *.sdf 4 | *.opensdf 5 | .vs 6 | Debug 7 | Release 8 | Build/Visual Studio 2015/Debug 9 | Build/Visual Studio 2017/Debug 10 | *.pcx 11 | 12 | # Visual Studio Code 13 | .vscode 14 | *.code-workspace 15 | 16 | # CLion 17 | .idea 18 | cmake-build-debug 19 | cmake-build-release 20 | cmake-build-relwithdebinfo 21 | cmake-build-minsizerel 22 | 23 | # CMake 24 | ## Default output folder used by Visual Studio 25 | out 26 | 27 | ## Output folder on Linux as described in HACKING 28 | build 29 | 30 | # 3d-party libs are auto-resolved by cmake 31 | lib 32 | 33 | # Doxygen 34 | docs 35 | 36 | # Release 37 | dist 38 | 39 | # patch artifacts 40 | *.orig 41 | *.rej 42 | *.diff 43 | *.patch 44 | -------------------------------------------------------------------------------- /src/Engine/Graphics/LightmapBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // TODO(pskelton): rename - lighting functions 4 | 5 | #include 6 | 7 | #include "Engine/Graphics/IRender.h" 8 | 9 | struct LightsStack_StationaryLight_; 10 | struct LightsStack_MobileLight_; 11 | 12 | #define LIGHTMAP_FLAGS_USE_SPECULAR 0x01 13 | 14 | extern LightsStack_StationaryLight_ *pStationaryLightsStack; 15 | // extern StationaryLight pStationaryLights[400]; 16 | // extern int uNumStationaryLightsApplied; 17 | extern LightsStack_MobileLight_ *pMobileLightsStack; 18 | // extern MobileLight pMobileLights[400]; 19 | // extern int uNumMobileLightsApplied; 20 | 21 | void DrawLightsDebugOutlines(char bit_one_for_list1__bit_two_for_list2); 22 | -------------------------------------------------------------------------------- /resources/shaders/glbillbshader.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec2 vaTexUV; 3 | layout (location = 2) in vec4 vaCol; 4 | layout (location = 3) in float vaScreenSpace; 5 | 6 | layout (location = 5) in float palid; 7 | 8 | out vec4 colour; 9 | out vec2 texuv; 10 | out float screenspace; 11 | flat out int paletteid; 12 | 13 | uniform mat4 view; 14 | uniform mat4 projection; 15 | 16 | void main() { 17 | gl_Position = projection * view * vec4(vaPos, 1.0); 18 | // float opacity = smoothstep(1.0 , 0.9999, vaPos.z); 19 | colour = vec4(vaCol.r, vaCol.g, vaCol.b, 1.0); 20 | texuv = vaTexUV; 21 | screenspace = vaScreenSpace; 22 | paletteid = int(palid); 23 | } 24 | -------------------------------------------------------------------------------- /src/Utility/Streams/StringOutputStream.cpp: -------------------------------------------------------------------------------- 1 | #include "StringOutputStream.h" 2 | 3 | #include 4 | #include 5 | 6 | StringOutputStream::StringOutputStream(std::string *target) : target_(target) { 7 | assert(target); 8 | } 9 | 10 | StringOutputStream::~StringOutputStream() {} 11 | 12 | void StringOutputStream::Write(const void *data, size_t size) { 13 | assert(target_); 14 | 15 | target_->resize(target_->size() + size); 16 | memcpy(target_->data() + target_->size() - size, data, size); 17 | } 18 | 19 | void StringOutputStream::Flush() { 20 | assert(target_); 21 | 22 | // Nothing else to do here. 23 | } 24 | 25 | void StringOutputStream::Close() { 26 | target_ = nullptr; 27 | } 28 | -------------------------------------------------------------------------------- /src/Engine/Tables/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(TABLES_SOURCES FactionTable.cpp 4 | FrameTableInc.cpp 5 | IconFrameTable.cpp 6 | PlayerFrameTable.cpp 7 | StorylineTextTable.cpp 8 | TileTable.cpp) 9 | 10 | set(TABLES_HEADERS FactionTable.h 11 | FrameTableInc.h 12 | IconFrameTable.h 13 | PlayerFrameTable.h 14 | StorylineTextTable.h 15 | TileFrameTable.h) 16 | 17 | add_library(tables STATIC ${TABLES_SOURCES} ${TABLES_HEADERS}) 18 | target_link_libraries(tables engine) 19 | target_check_style(tables) 20 | -------------------------------------------------------------------------------- /src/Library/Serialization/StandardSerialization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "SerializationFwd.h" 6 | 7 | MM_DECLARE_SERIALIZATION_FUNCTIONS(bool) 8 | MM_DECLARE_SERIALIZATION_FUNCTIONS(std::string) 9 | MM_DECLARE_SERIALIZATION_FUNCTIONS(short) 10 | MM_DECLARE_SERIALIZATION_FUNCTIONS(unsigned short) 11 | MM_DECLARE_SERIALIZATION_FUNCTIONS(int) 12 | MM_DECLARE_SERIALIZATION_FUNCTIONS(unsigned int) 13 | MM_DECLARE_SERIALIZATION_FUNCTIONS(long) 14 | MM_DECLARE_SERIALIZATION_FUNCTIONS(unsigned long) 15 | MM_DECLARE_SERIALIZATION_FUNCTIONS(long long) 16 | MM_DECLARE_SERIALIZATION_FUNCTIONS(unsigned long long) 17 | MM_DECLARE_SERIALIZATION_FUNCTIONS(float) 18 | MM_DECLARE_SERIALIZATION_FUNCTIONS(double) 19 | 20 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlOpenGLContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/PlatformOpenGLContext.h" 6 | 7 | class SdlPlatformSharedState; 8 | 9 | class SdlOpenGLContext: public PlatformOpenGLContext { 10 | public: 11 | SdlOpenGLContext(SdlPlatformSharedState *state, SDL_Window *window, SDL_GLContext context); 12 | virtual ~SdlOpenGLContext(); 13 | 14 | virtual bool bind() override; 15 | virtual bool unbind() override; 16 | virtual void swapBuffers() override; 17 | virtual void *getProcAddress(const char *name) override; 18 | 19 | private: 20 | SdlPlatformSharedState *_state = nullptr; 21 | SDL_Window *_window = nullptr; 22 | SDL_GLContext _context = nullptr; 23 | }; 24 | -------------------------------------------------------------------------------- /src/Media/MediaLogger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Library/Logger/Logger.h" 10 | 11 | class MediaLogger { 12 | public: 13 | explicit MediaLogger(Logger *logger); 14 | 15 | void Log(void *ptr, int logLevel, const char *format, va_list args); 16 | 17 | static void SetGlobalMediaLogger(MediaLogger *logger); 18 | static MediaLogger *GlobalMediaLogger(); 19 | 20 | private: 21 | struct LogState { 22 | int prefixFlag = 1; 23 | std::string message; 24 | }; 25 | 26 | private: 27 | Logger *logger_ = nullptr; 28 | std::unordered_map stateByThreadId_; 29 | }; 30 | -------------------------------------------------------------------------------- /resources/shaders/gltwodshader.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | precision highp usamplerBuffer; 3 | 4 | in vec4 colour; 5 | in vec2 texuv; 6 | flat in int paletteid; 7 | 8 | out vec4 FragColour; 9 | 10 | uniform sampler2D texture0; 11 | uniform usamplerBuffer palbuf; 12 | uniform bool repaint; 13 | 14 | void main() { 15 | vec4 fragcol = texture(texture0, texuv); 16 | int index = int(fragcol.r * 255.0); 17 | vec4 newcol = vec4(texelFetch(palbuf, int(256 * paletteid + index))); 18 | 19 | if (repaint == true) { 20 | if (paletteid > 0) 21 | if (index > 0) 22 | fragcol = vec4(newcol.r / 255.0, newcol.g / 255.0, newcol.b / 255.0, 1.0); 23 | } 24 | 25 | FragColour = fragcol * colour; 26 | } 27 | -------------------------------------------------------------------------------- /src/GUI/UI/UIPopup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | unsigned int GetSpellColor(signed int a1); 5 | uint64_t GetExperienceRequiredForLevel(int level); 6 | void CharacterUI_DrawTooltip(const char *title, std::string &content); 7 | 8 | class Image; 9 | class Texture; 10 | extern Texture *parchment; 11 | extern Image *messagebox_corner_x; // 5076AC 12 | extern Image *messagebox_corner_y; // 5076B4 13 | extern Image *messagebox_corner_z; // 5076A8 14 | extern Image *messagebox_corner_w; // 5076B0 15 | extern Image *messagebox_border_top; // 507698 16 | extern Image *messagebox_border_bottom; // 5076A4 17 | extern Image *messagebox_border_left; // 50769C 18 | extern Image *messagebox_border_right; // 5076A0 19 | -------------------------------------------------------------------------------- /src/Engine/stru298.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Engine/Objects/Actor.h" 6 | 7 | /* 303 */ 8 | #pragma pack(push, 1) 9 | struct stru298 { 10 | // holds info of attacks 11 | void Add(int16_t uID, int16_t a3, int16_t x, int16_t y, int16_t z, ABILITY_INDEX a7, char a8); 12 | 13 | int count; 14 | int16_t pIDs[100]; 15 | int16_t pXs[100]; 16 | int16_t pYs[100]; 17 | int16_t pZs[100]; 18 | int16_t attack_range[100]; // range 19 | char attack_type[100]; // melee = 1 / spells = 0 20 | ABILITY_INDEX attack_special[100]; // special ability 21 | Vec3i vec_4B4[100]; // attack vector 22 | }; 23 | #pragma pack(pop) 24 | 25 | extern stru298 AttackerInfo; // for area of effect damage 26 | -------------------------------------------------------------------------------- /src/Library/Trace/EventTrace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Platform/PlatformEvents.h" 8 | 9 | struct EventTraceHeader { 10 | int saveFileSize = -1; 11 | // TODO(captainurist): std::string saveFileChecksum; 12 | }; 13 | 14 | struct EventTrace { 15 | static void saveToFile(std::string_view path, const EventTrace &trace); 16 | static EventTrace loadFromFile(std::string_view path, PlatformWindow *window); 17 | 18 | static bool isTraceable(const PlatformEvent *event); 19 | static std::unique_ptr cloneEvent(const PlatformEvent *event); 20 | 21 | EventTraceHeader header; 22 | std::vector> events; 23 | }; 24 | -------------------------------------------------------------------------------- /resources/shaders/glforcepershader.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec4 vaPos; 2 | layout (location = 1) in vec3 vaTexUV; 3 | layout (location = 2) in float vaScreenSpace; 4 | layout (location = 3) in vec4 vaCol; 5 | 6 | out vec4 colour; 7 | out vec4 texuv; 8 | out float screenspace; 9 | 10 | uniform mat4 view; 11 | uniform mat4 projection; 12 | 13 | void main() { 14 | // vaPos.w - 0.000001 is needed for 6700XT under linux or sky will flicker 15 | vec4 forcepos = vec4(vaPos.x * vaPos.w, vaPos.y * vaPos.w, vaPos.z * vaPos.w - 0.000001, vaPos.w); 16 | gl_Position = projection * view * forcepos; 17 | colour = vec4(vaCol); 18 | texuv = vec4(vaTexUV.x * vaTexUV.z, vaTexUV.y * vaTexUV.z, 0, vaTexUV.z); 19 | screenspace = vaScreenSpace; 20 | } 21 | -------------------------------------------------------------------------------- /src/GUI/UI/UIStatusBar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void GameUI_StatusBar_Draw(); 6 | void GameUI_StatusBar_DrawForced(); 7 | 8 | void GameUI_StatusBar_Set(const std::string &str); 9 | void GameUI_StatusBar_Clear(); 10 | 11 | void GameUI_SetStatusBar(const std::string &str); 12 | void GameUI_SetStatusBar(int localization_string_id, ...); 13 | void GameUI_SetStatusBarShortNotification(const std::string &str); 14 | void GameUI_StatusBar_ClearEventString(); 15 | 16 | std::string GameUI_StatusBar_GetInput(); 17 | void GameUI_StatusBar_OnInput(const std::string &str); 18 | void GameUI_StatusBar_ClearInputString(); 19 | 20 | void GameUI_StatusBar_NothingHere(); 21 | 22 | void GameUI_StatusBar_DrawImmediate(const std::string &str, int color); 23 | -------------------------------------------------------------------------------- /src/GUI/UI/UITransition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "GUI/GUIWindow.h" 6 | 7 | class GUIWindow_Travel : public GUIWindow { 8 | public: 9 | GUIWindow_Travel(); 10 | virtual ~GUIWindow_Travel() {} 11 | 12 | virtual void Update(); 13 | virtual void Release(); 14 | }; 15 | 16 | class GUIWindow_Transition : public GUIWindow { 17 | public: 18 | GUIWindow_Transition(uint32_t anim_id, uint32_t exit_pic_id, int x, int y, int z, int directiony, int directionx, int a8, const char *pLocationName); 19 | virtual ~GUIWindow_Transition() {} 20 | 21 | virtual void Update(); 22 | virtual void Release(); 23 | 24 | int mapid{}; 25 | std::string mapname{}; 26 | }; 27 | 28 | extern std::string transition_button_label; 29 | -------------------------------------------------------------------------------- /CMakeModules/Git.cmake: -------------------------------------------------------------------------------- 1 | if(NOT PROJECT_VERSION) 2 | set(PROJECT_VERSION "unknown") 3 | endif() 4 | 5 | find_package(Git) 6 | 7 | if(GIT_FOUND) 8 | execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags --dirty 9 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 10 | OUTPUT_VARIABLE GIT_VERSION 11 | OUTPUT_STRIP_TRAILING_WHITESPACE) 12 | 13 | if(NOT "${GIT_VERSION}" STREQUAL "") 14 | set(PROJECT_VERSION ${GIT_VERSION}) 15 | endif() 16 | 17 | execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive 18 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 19 | OUTPUT_VARIABLE OPENENROTH_VERSION 20 | OUTPUT_STRIP_TRAILING_WHITESPACE) 21 | endif() 22 | 23 | message(STATUS "OpenEnroth version: ${PROJECT_VERSION}") 24 | -------------------------------------------------------------------------------- /src/Library/Logger/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/PlatformLogger.h" 6 | 7 | class Logger { 8 | public: 9 | // TODO(captainurist): this should go to ctor, but that's not doable right now because of a shitload of static 10 | // variables that call EngineIoc::ResolveLogger. 11 | PlatformLogger *BaseLogger() const; 12 | void SetBaseLogger(PlatformLogger *baseLogger); 13 | 14 | void Log(PlatformLogLevel logLevel, const char *format, ...); 15 | 16 | void Info(const char *pFormat, ...); 17 | void Warning(const char *pFormat, ...); 18 | 19 | private: 20 | void LogV(PlatformLogLevel logLevel, const char *pFormat, va_list args); 21 | 22 | private: 23 | PlatformLogger *baseLogger_ = nullptr; 24 | }; 25 | -------------------------------------------------------------------------------- /src/Library/Json/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(JSON_SOURCES JsonExceptions.cpp) 4 | 5 | set(JSON_HEADERS Json.h 6 | JsonFwd.h 7 | JsonExceptions.h) 8 | 9 | add_library(json STATIC ${JSON_SOURCES} ${JSON_HEADERS}) 10 | target_link_libraries(json utility nlohmann_json serialization) 11 | target_check_style(json) 12 | 13 | 14 | if(ENABLE_TESTS) 15 | set(TEST_JSON_SOURCES Tests/Json_ut.cpp) 16 | 17 | add_library(test_json OBJECT ${TEST_JSON_SOURCES}) 18 | target_compile_definitions(test_json PRIVATE TEST_GROUP=Json) 19 | target_link_libraries(test_json json) 20 | 21 | target_check_style(test_json) 22 | 23 | target_link_libraries(OpenEnroth_UnitTest test_json) 24 | endif() 25 | -------------------------------------------------------------------------------- /src/Engine/Graphics/OpenGL/TextureOpenGL.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Engine/Graphics/Texture.h" 3 | 4 | class TextureOpenGL : public Texture { 5 | public: 6 | int GetOpenGlTexture(bool bLoad = true); 7 | 8 | virtual ~TextureOpenGL(); 9 | 10 | protected: 11 | friend class RenderOpenGL; 12 | 13 | static Texture *Create(unsigned int width, unsigned int height, IMAGE_FORMAT format, const void * pixels); 14 | 15 | static Texture *Create(ImageLoader *loader); 16 | 17 | void SetOpenGlTexture(int ogl_texture) { this->ogl_texture = ogl_texture; } 18 | 19 | explicit TextureOpenGL(bool lazy_initialization = true) 20 | : Texture(lazy_initialization), ogl_texture(-1) {} 21 | 22 | int ogl_texture; 23 | 24 | virtual bool LoadImageData(); 25 | }; 26 | -------------------------------------------------------------------------------- /src/Library/Config/Config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ConfigFwd.h" 8 | #include "ConfigSection.h" 9 | #include "ConfigValue.h" 10 | 11 | class Config { 12 | public: 13 | Config() = default; 14 | Config(const Config &other) = delete; // non-copyable 15 | Config(Config&& other) = delete; // non-movable 16 | 17 | void Load(const std::string &path); 18 | void Save(const std::string &path) const; 19 | void Reset(); 20 | 21 | void RegisterSection(ConfigSection *section); 22 | 23 | ConfigSection *Section(const std::string &name) const; 24 | 25 | std::vector Sections() const; 26 | 27 | private: 28 | std::map sectionByName_; 29 | }; 30 | -------------------------------------------------------------------------------- /src/GUI/UI/UIInventory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "GUI/GUIWindow.h" 6 | 7 | struct CastSpellInfo; 8 | 9 | class GUIWindow_Inventory : public GUIWindow { 10 | public: 11 | GUIWindow_Inventory(Pointi position, Sizei dimensions, WindowData data, const std::string &hint = std::string()) : 12 | GUIWindow(WINDOW_CharacterWindow_Inventory, position, dimensions, data, hint) {} 13 | virtual ~GUIWindow_Inventory() {} 14 | 15 | virtual void Update(); 16 | }; 17 | 18 | class GUIWindow_Inventory_CastSpell : public GUIWindow { 19 | public: 20 | GUIWindow_Inventory_CastSpell(Pointi position, Sizei dimensions, CastSpellInfo *spellInfo, const std::string &hint = std::string()); 21 | virtual ~GUIWindow_Inventory_CastSpell() {} 22 | 23 | virtual void Update(); 24 | }; 25 | -------------------------------------------------------------------------------- /test/Testing/Game/GameTest.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Testing/Extensions/ThrowingAssertions.h" 4 | 5 | #include "Engine/Plugins/EngineController.h" 6 | 7 | #include "TestController.h" 8 | 9 | class GameTest : public testing::Test { 10 | public: 11 | static void init(EngineController *engineController, TestController *testController); 12 | 13 | private: 14 | virtual void SetUp() override; 15 | virtual void TearDown() override; 16 | 17 | protected: 18 | EngineController *const game = nullptr; 19 | TestController *const test = nullptr; 20 | }; 21 | 22 | #ifndef TEST_GROUP 23 | # error "Please define TEST_GROUP before including this header." 24 | #endif 25 | 26 | #define GAME_TEST(TestBase, TestName) \ 27 | GTEST_TEST_(TEST_GROUP, TestBase##_##TestName, GameTest, testing::internal::GetTypeId()) 28 | -------------------------------------------------------------------------------- /src/Engine/Graphics/HWLContainer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class HWLTexture { 9 | public: 10 | inline HWLTexture() {} 11 | 12 | int uBufferWidth = 0; 13 | int uBufferHeight = 0; 14 | int uAreaWidth = 0; 15 | int uAreaHeigth = 0; 16 | unsigned int uWidth = 0; 17 | unsigned int uHeight = 0; 18 | int uAreaX = 0; 19 | int uAreaY = 0; 20 | uint16_t *pPixels = nullptr; 21 | }; 22 | 23 | class Logger; 24 | 25 | class HWLContainer { 26 | public: 27 | HWLContainer(); 28 | virtual ~HWLContainer(); 29 | 30 | bool Open(const std::string &pFilename); 31 | 32 | HWLTexture *LoadTexture(const std::string &pName); 33 | 34 | protected: 35 | FILE *pFile; 36 | Logger *log; 37 | std::map mNodes; 38 | }; 39 | -------------------------------------------------------------------------------- /.github/workflows/style.yml: -------------------------------------------------------------------------------- 1 | name: Style 2 | 3 | on: 4 | pull_request: 5 | push: 6 | release: 7 | types: [published] 8 | 9 | jobs: 10 | check_style: 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | with: 16 | submodules: 'recursive' 17 | 18 | - name: Install dependencies 19 | run: | 20 | sudo apt-get update 21 | sudo apt-get install -y libglu1-mesa-dev zlib1g-dev 22 | sudo apt-get install -y libavformat-dev libavcodec-dev libswscale-dev 23 | sudo apt-get install -y libopenal-dev 24 | sudo apt-get install -y libsdl2-dev 25 | 26 | - name: Configure 27 | run: | 28 | cmake -B build -DENABLE_TESTS=On 29 | 30 | - name: Check style 31 | working-directory: build 32 | run: | 33 | make check_style 34 | -------------------------------------------------------------------------------- /src/Engine/stru314.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 179 */ 4 | #pragma pack(push, 1) 5 | struct stru314 { // facet normals face / wall / celings 6 | //----- (00489B60) -------------------------------------------------------- 7 | stru314() { 8 | this->Normal.x = 0.0; 9 | this->Normal.y = 0.0; 10 | this->Normal.z = 0.0; 11 | 12 | this->field_10.x = 0.0; 13 | this->field_10.y = 0.0; 14 | this->field_10.z = 0.0; 15 | 16 | this->field_1C.x = 0.0; 17 | this->field_1C.y = 0.0; 18 | this->field_1C.z = 0.0; 19 | 20 | this->dist = 0; 21 | } 22 | 23 | //----- (00489B96) -------------------------------------------------------- 24 | inline ~stru314() {} 25 | 26 | Vec3f Normal; 27 | Vec3f field_10; 28 | Vec3f field_1C; 29 | float dist = 0; 30 | }; 31 | #pragma pack(pop) 32 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlGamepad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "Platform/PlatformGamepad.h" 9 | 10 | class SdlPlatformSharedState; 11 | 12 | class SdlGamepad: public PlatformGamepad { 13 | public: 14 | SdlGamepad(SdlPlatformSharedState *state, SDL_GameController *gamepad, uint32_t id); 15 | virtual ~SdlGamepad(); 16 | 17 | virtual std::string model() const override; 18 | virtual std::string serial() const override; 19 | 20 | uint32_t id() const override { 21 | return _id; 22 | } 23 | 24 | SDL_GameController *sdlHandle() const { 25 | return _gamepad; 26 | } 27 | 28 | int32_t gamepadSdlId(); 29 | 30 | private: 31 | SdlPlatformSharedState *_state = nullptr; 32 | SDL_GameController *_gamepad = nullptr; 33 | uint32_t _id = 0; 34 | }; 35 | -------------------------------------------------------------------------------- /src/Engine/Graphics/FrameLimiter.cpp: -------------------------------------------------------------------------------- 1 | #include "FrameLimiter.h" 2 | 3 | #include 4 | 5 | static int64_t nowNs() { 6 | // We're going through std::chrono here and not through Platform because we need actual clock time, not 7 | // "simulation time". 8 | return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); 9 | } 10 | 11 | FrameLimiter::FrameLimiter() { 12 | reset(); 13 | } 14 | 15 | void FrameLimiter::reset() { 16 | _lastFrameTimeNs = nowNs(); 17 | } 18 | 19 | void FrameLimiter::tick(int targetFps) { 20 | int64_t targetDeltaNs = 1'000'000'000 / targetFps; 21 | 22 | int64_t currentTimeNs; 23 | do { 24 | currentTimeNs = nowNs(); 25 | } while (currentTimeNs - _lastFrameTimeNs < targetDeltaNs); 26 | 27 | _lastFrameTimeNs = currentTimeNs; 28 | } 29 | -------------------------------------------------------------------------------- /resources/shaders/gldecalshader.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec2 vaTexUV; 3 | layout (location = 2) in float vaTexLayer; 4 | layout (location = 3) in vec3 vaColours; 5 | layout (location = 4) in float vaAttrib; 6 | 7 | out vec4 vertexColour; 8 | out vec2 texuv; 9 | //flat out float olayer; 10 | //out vec3 vsPos; 11 | //out vec3 vsNorm; 12 | //flat out int vsAttrib; 13 | out vec4 viewspace; 14 | 15 | uniform mat4 view; 16 | uniform mat4 projection; 17 | 18 | uniform float decalbias; 19 | 20 | void main() { 21 | viewspace = view * vec4(vaPos, 1.0); 22 | gl_Position = projection * view * vec4(vaPos, 1.0); 23 | gl_Position -= vec4(0, 0, decalbias, 0); 24 | 25 | vertexColour = vec4(vaColours, 1.0); 26 | 27 | texuv = vaTexUV; 28 | //olayer = vaTexLayer; 29 | //vsPos = vaPos; 30 | //vsNorm = vaNormal; 31 | //vsAttrib = int(vaAttrib); 32 | } -------------------------------------------------------------------------------- /src/Library/Serialization/SerializationFwd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * Forward-declares lexical serialization functions for the given type. 8 | * 9 | * @param TYPE Type to forward-declare lexical serialization functions for. 10 | */ 11 | #define MM_DECLARE_SERIALIZATION_FUNCTIONS(TYPE) \ 12 | [[nodiscard]] bool trySerialize(const TYPE &src, std::string *dst); \ 13 | [[nodiscard]] bool tryDeserialize(std::string_view src, TYPE *dst); \ 14 | void serialize(const TYPE &src, std::string *dst); \ 15 | void deserialize(std::string_view src, TYPE *dst); 16 | 17 | -------------------------------------------------------------------------------- /src/Utility/Streams/Tests/FileOutputStream_ut.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Testing/Unit/UnitTest.h" 4 | 5 | #include "Utility/Streams/FileOutputStream.h" 6 | 7 | UNIT_TEST(FileOutputStream, Write) { 8 | const char* tmpfile = "tmp_test.txt"; 9 | const char* tmpfilecontent = "1234\n"; 10 | size_t tmpfilesize = strlen(tmpfilecontent); 11 | 12 | FileOutputStream out(tmpfile); 13 | out.Write(tmpfilecontent, tmpfilesize); 14 | out.Close(); 15 | 16 | FILE* in = fopen(tmpfile, "rb"); 17 | EXPECT_NE(in, nullptr); 18 | 19 | char buf[1024] = {}; 20 | size_t bytes = fread(buf, 1, 1024, in); 21 | EXPECT_EQ(bytes, 5); 22 | EXPECT_EQ(strcmp(buf, tmpfilecontent), 0); 23 | 24 | bytes = fread(buf, 1, 1024, in); 25 | EXPECT_EQ(bytes, 0); 26 | EXPECT_TRUE(feof(in)); 27 | 28 | fclose(in); 29 | remove(tmpfile); 30 | } 31 | -------------------------------------------------------------------------------- /src/Utility/Tests/String_ut.cpp: -------------------------------------------------------------------------------- 1 | #include "Testing/Unit/UnitTest.h" 2 | 3 | #include "Utility/String.h" 4 | 5 | UNIT_TEST(String, iequals) { 6 | EXPECT_FALSE(iequals("abc", "abcd")); 7 | EXPECT_FALSE(iequals("abd", "abc")); 8 | EXPECT_TRUE(iequals("abc\0\0", "abc")); 9 | EXPECT_TRUE(iequals("ABC", "abc")); 10 | EXPECT_TRUE(iequals("Abc", "abC")); 11 | EXPECT_TRUE(iequals("123ab..?z", "123Ab..?Z")); 12 | EXPECT_TRUE(iequals("", "")); 13 | EXPECT_FALSE(iequals("", "Z")); 14 | EXPECT_FALSE(iequals("@", "`")); // \x40 vs \x60 15 | } 16 | 17 | UNIT_TEST(String, iless) { 18 | EXPECT_TRUE(iless("A", "AB")); 19 | EXPECT_FALSE(iless("AB", "A")); 20 | EXPECT_TRUE(iless("a", "B")); 21 | EXPECT_FALSE(iless("B", "a")); 22 | EXPECT_FALSE(iless("b", "B")); 23 | EXPECT_FALSE(iless("B", "b")); 24 | EXPECT_TRUE(iless("@", "`")); 25 | } 26 | -------------------------------------------------------------------------------- /resources/shaders/glbspshader.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec2 vaTexUV; 3 | layout (location = 2) in vec2 vaTexLayer; 4 | layout (location = 3) in vec3 vaNormal; 5 | layout (location = 4) in float vaAttrib; 6 | layout (location = 5) in float vaSector; 7 | 8 | out vec4 vertexColour; 9 | out vec2 texuv; 10 | flat out vec2 olayer; 11 | out vec3 vsPos; 12 | out vec3 vsNorm; 13 | flat out int vsAttrib; 14 | flat out int vsSector; 15 | 16 | uniform mat4 view; 17 | uniform mat4 projection; 18 | 19 | 20 | void main() { 21 | gl_Position = projection * view * vec4(vaPos, 1.0); 22 | 23 | //unused 24 | vertexColour = vec4(0.0005 * vaPos.y, 0.30, 0.30, 1.0); 25 | 26 | texuv = vaTexUV; 27 | olayer = vaTexLayer; 28 | vsPos = vaPos; 29 | vsNorm = vaNormal; 30 | vsAttrib = int(vaAttrib); 31 | vsSector = int(vaSector); 32 | } 33 | -------------------------------------------------------------------------------- /src/Application/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(GAME_SOURCES 4 | Game.cpp 5 | GameConfig.cpp 6 | GameFactory.cpp 7 | GameKeyboardController.cpp 8 | GameMenu.cpp 9 | GameOptions.cpp 10 | GameOver.cpp 11 | GamePathResolver.cpp 12 | GameTraceHandler.cpp 13 | GameWindowHandler.cpp 14 | IocContainer.cpp) 15 | 16 | set(GAME_HEADERS 17 | Game.h 18 | GameConfig.h 19 | GameFactory.h 20 | GameKeyboardController.h 21 | GameMenu.h 22 | GameOver.h 23 | GamePathResolver.h 24 | GameOptions.h 25 | GameTraceHandler.h 26 | GameWindowHandler.h 27 | IocContainer.h) 28 | 29 | add_library(game STATIC ${GAME_SOURCES} ${GAME_HEADERS}) 30 | target_check_style(game) 31 | 32 | target_link_libraries(game io gui engine platform graphics media lod utility config trace application plugins CLI11::CLI11) 33 | -------------------------------------------------------------------------------- /src/Engine/Graphics/NuklearEventHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/Filters/PlatformEventFilter.h" 6 | 7 | class NuklearEventHandler : public PlatformEventFilter { 8 | public: 9 | NuklearEventHandler(); 10 | 11 | private: 12 | virtual bool keyPressEvent(const PlatformKeyEvent *event) override; 13 | virtual bool keyReleaseEvent(const PlatformKeyEvent *event) override; 14 | virtual bool mouseMoveEvent(const PlatformMouseEvent *event) override; 15 | virtual bool mousePressEvent(const PlatformMouseEvent *event) override; 16 | virtual bool mouseReleaseEvent(const PlatformMouseEvent *event) override; 17 | virtual bool wheelEvent(const PlatformWheelEvent *event) override; 18 | 19 | bool KeyEvent(PlatformKey key, PlatformModifiers mods, bool down); 20 | bool MouseEvent(PlatformMouseButton button, const Pointi &pos, bool down); 21 | }; 22 | -------------------------------------------------------------------------------- /src/Engine/MapsLongTimer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Engine/Time.h" 6 | 7 | /* 169 */ 8 | // Originally packed struct 9 | struct MapsLongTimer { 10 | GameTime NextStartTime {}; // timer will either fire event at this time (type 11 | // 2, field_C == 0) 12 | int16_t timer_evt_ID = 0; 13 | int16_t timer_evt_seq_num = 0; 14 | int16_t time_left_to_fire = 0; 15 | int16_t IntervalHalfMins = 0; // or fire on these intervals (type 1) 16 | int16_t YearsInterval = 0; 17 | int16_t MonthsInterval = 0; 18 | int16_t WeeksInterval = 0; 19 | int16_t HoursInterval = 0; 20 | int16_t MinutesInterval = 0; 21 | int16_t SecondsInterval = 0; 22 | EventType timer_evt_type = EVENT_Invalid; // Originally int16_t 23 | int16_t field_1E = 0; 24 | }; 25 | extern std::array MapsLongTimersList; // 5B5928 26 | -------------------------------------------------------------------------------- /src/Utility/ScopeGuard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Preprocessor.h" 6 | 7 | /** 8 | * Scope guard to be used to roll back operations in an exception-safe way. 9 | * 10 | * Example usage: 11 | * \code 12 | * value = 10; 13 | * auto guard = ScopeGuard([&] { value = 1; }); 14 | * \endcode 15 | */ 16 | template 17 | class ScopeGuard { 18 | public: 19 | explicit ScopeGuard(T &&callable): callable_(std::move(callable)) {} 20 | 21 | ~ScopeGuard() { 22 | callable_(); 23 | } 24 | 25 | private: 26 | T callable_; 27 | }; 28 | 29 | /** 30 | * Runs provided statements at scope exit by creating a temporary `ScopeGuard` object. 31 | */ 32 | #define MM_AT_SCOPE_EXIT(...) \ 33 | auto MM_PP_CAT(guard, __LINE__) = ScopeGuard([&] { __VA_ARGS__; }) 34 | 35 | -------------------------------------------------------------------------------- /resources/shaders/glterrain.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec2 vaTexUV; 3 | layout (location = 2) in vec2 vaTexLayer; 4 | layout (location = 3) in vec3 vaNormal; 5 | // loc 4 is attributes but not used here yet 6 | 7 | out vec4 vertexColour; 8 | out vec2 texuv; 9 | flat out vec2 olayer; 10 | out vec3 vsPos; 11 | out vec3 vsNorm; 12 | out vec4 viewspace; 13 | 14 | uniform mat4 view; 15 | uniform mat4 projection; 16 | 17 | void main() { 18 | viewspace = view * vec4(vaPos, 1.0); 19 | gl_Position = projection * view * vec4(vaPos, 1.0); 20 | 21 | // rgb unused 22 | //float opacity = smoothstep(1.0 , 0.99999, gl_Position.z / gl_Position.w); 23 | //if (gl_Position.z < 0.0) opacity = 1.0; 24 | vertexColour = vec4(0.0, 0.0, 0.0, 1.0); 25 | 26 | texuv = vaTexUV; 27 | olayer = vaTexLayer; 28 | vsPos = vaPos; 29 | vsNorm = vaNormal; 30 | } 31 | -------------------------------------------------------------------------------- /src/GUI/UI/UISaveLoad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GUI/GUIWindow.h" 4 | 5 | class GUIWindow_Save : public GUIWindow { 6 | public: 7 | GUIWindow_Save(); 8 | virtual ~GUIWindow_Save() {} 9 | 10 | virtual void Update(); 11 | 12 | protected: 13 | // Image * main_menu_background; 14 | 15 | Image *saveload_ui_save_up; 16 | Image *saveload_ui_loadsave; 17 | Image *saveload_ui_saveu; 18 | Image *saveload_ui_x_u; 19 | }; 20 | 21 | class GUIWindow_Load : public GUIWindow { 22 | public: 23 | explicit GUIWindow_Load(bool ingame); 24 | virtual ~GUIWindow_Load() {} 25 | 26 | virtual void Update(); 27 | 28 | protected: 29 | Image *main_menu_background; 30 | 31 | Image *saveload_ui_load_up; 32 | Image *saveload_ui_loadsave; 33 | Image *saveload_ui_loadu; 34 | Image *saveload_ui_x_u; 35 | }; 36 | 37 | void MainMenuLoad_Loop(); 38 | void MainMenuLoad_EventLoop(); 39 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlEnumTranslation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "Platform/PlatformEnums.h" 8 | #include "Platform/PlatformOpenGLOptions.h" 9 | 10 | PlatformKey translateSdlKey(SDL_Scancode key); 11 | PlatformKey translateSdlGamepadButton(SDL_GameControllerButton button); 12 | std::pair translateSdlGamepadAxis(SDL_GameControllerAxis axis, float value); 13 | PlatformModifiers translateSdlMods(uint16_t mods); 14 | PlatformMouseButton translateSdlMouseButton(uint8_t mouseButton); 15 | PlatformMouseButtons translateSdlMouseButtons(uint32_t mouseButtons); 16 | int translatePlatformVSyncMode(PlatformVSyncMode vsyncMode); 17 | SDL_GLprofile translatePlatformOpenGLProfile(PlatformOpenGLProfile profile); 18 | SDL_LogPriority translatePlatformLogLevel(PlatformLogLevel logLevel); 19 | PlatformLogLevel translateSdlLogLevel(SDL_LogPriority logLevel); 20 | -------------------------------------------------------------------------------- /src/GUI/GUIProgressBar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Image; 6 | 7 | class GUIProgressBar { 8 | public: 9 | enum Type { 10 | TYPE_None = 0, 11 | TYPE_Fullscreen = 1, 12 | TYPE_Box = 2 13 | }; 14 | 15 | public: 16 | GUIProgressBar(); 17 | 18 | bool Initialize(Type type); 19 | void Reset(uint8_t uMaxProgress); 20 | void Progress(); 21 | void Release(); 22 | void Draw(); 23 | 24 | bool IsActive(); 25 | 26 | protected: 27 | int uX; 28 | int uY; 29 | int uWidth; 30 | int uHeight; 31 | 32 | uint8_t uProgressMax; 33 | uint8_t uProgressCurrent; 34 | Type uType; 35 | 36 | Image *progressbar_dungeon; // struct Texture_MM7 pBardata; 37 | Image *progressbar_loading; // struct Texture_MM7 pLoadingProgress; 38 | 39 | Image *loading_bg; 40 | }; 41 | 42 | extern GUIProgressBar *pGameLoadingUI_ProgressBar; 43 | -------------------------------------------------------------------------------- /src/Utility/Math/TrigLut.cpp: -------------------------------------------------------------------------------- 1 | #include "TrigLut.h" 2 | 3 | #include 4 | 5 | TrigTableLookup TrigLUT; 6 | 7 | TrigTableLookup::TrigTableLookup() { 8 | for (int i = 0; i <= this->uIntegerHalfPi; i++) 9 | pCosTable[i] = std::cos(i * M_PI / uIntegerPi); 10 | } 11 | 12 | float TrigTableLookup::Cos(int angle) const { 13 | angle &= uDoublePiMask; 14 | 15 | if (angle > uIntegerPi) 16 | angle = uIntegerDoublePi - angle; 17 | if (angle >= uIntegerHalfPi) 18 | return -pCosTable[uIntegerPi - angle]; 19 | else 20 | return pCosTable[angle]; 21 | } 22 | 23 | float TrigTableLookup::Sin(int angle) const { 24 | return Cos(angle - this->uIntegerHalfPi); 25 | } 26 | 27 | int TrigTableLookup::Atan2(int x, int y) const { 28 | double angle = std::atan2(static_cast(y), static_cast(x)); 29 | 30 | return static_cast(angle / M_PI * 1024) & uDoublePiMask; 31 | } 32 | -------------------------------------------------------------------------------- /src/Engine/Plugins/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(PLUGINS_SOURCES EngineController.cpp 4 | EngineControlPlugin.cpp 5 | EngineDeterministicPlugin.cpp 6 | EngineTracePlugin.cpp 7 | EngineTracer.cpp) 8 | 9 | set(PLUGINS_HEADERS EngineController.h 10 | EngineControlPlugin.h 11 | EngineControlState.h 12 | EngineControlStateHandle.h 13 | EngineDeterministicPlugin.h 14 | EngineTracePlugin.h 15 | EngineTracer.h) 16 | 17 | # TODO(captainurist): lib naming policy needs revisiting. engine_plugins would make more sense here. 18 | add_library(plugins STATIC ${PLUGINS_SOURCES} ${PLUGINS_HEADERS}) 19 | target_check_style(plugins) 20 | 21 | target_link_libraries(plugins engine platform utility application) 22 | -------------------------------------------------------------------------------- /src/Engine/Graphics/Shaders/UI.hlsl: -------------------------------------------------------------------------------- 1 | cbuffer fast: register(b0) 2 | { 3 | float2 position : packoffset(c0.x); 4 | float2 size : packoffset(c0.z); 5 | }; 6 | 7 | cbuffer slow: register(b1) 8 | { 9 | }; 10 | 11 | 12 | struct VInput 13 | { 14 | float4 pos: POSITION0; 15 | }; 16 | 17 | struct VOutput 18 | { 19 | float4 pos: SV_Position0; 20 | float2 uv: TEXCOORD0; 21 | }; 22 | 23 | 24 | VOutput vs(VInput vin) 25 | { 26 | VOutput vout; 27 | 28 | float2 normalized_pos = vin.pos.xy * position.xy + vin.pos.zw * size.xy; 29 | vout.pos.xy = float2(2, -2) * normalized_pos + float2(-1, 1); 30 | vout.pos.zw = float2(0, 1); 31 | vout.uv = vin.pos.zw; 32 | 33 | return vout; 34 | } 35 | 36 | 37 | 38 | 39 | SamplerState basic_sampler: register(s0); 40 | Texture2D image: register(t0); 41 | 42 | float4 main(VOutput pin): SV_Target0 43 | { 44 | return image.Sample(basic_sampler, pin.uv); 45 | } -------------------------------------------------------------------------------- /src/Utility/Streams/MemoryInputStream.cpp: -------------------------------------------------------------------------------- 1 | #include "MemoryInputStream.h" 2 | 3 | #include 4 | #include 5 | 6 | MemoryInputStream::MemoryInputStream() { 7 | Reset(nullptr, 0); 8 | } 9 | 10 | MemoryInputStream::MemoryInputStream(const void *data, size_t size) { 11 | Reset(data, size); 12 | } 13 | 14 | MemoryInputStream::~MemoryInputStream() {} 15 | 16 | void MemoryInputStream::Reset(const void *data, size_t size) { 17 | pos_ = static_cast(data); 18 | end_ = pos_ + size; 19 | } 20 | 21 | size_t MemoryInputStream::Read(void *data, size_t size) { 22 | size_t result = std::min(size, static_cast(end_ - pos_)); 23 | 24 | memcpy(data, pos_, result); 25 | pos_ += result; 26 | return result; 27 | } 28 | 29 | size_t MemoryInputStream::Skip(size_t size) { 30 | size_t result = std::min(size, static_cast(end_ - pos_)); 31 | pos_ += result; 32 | return result; 33 | } 34 | -------------------------------------------------------------------------------- /src/Library/Config/AbstractConfigValue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "ConfigFwd.h" 6 | 7 | class AbstractConfigValue { 8 | public: 9 | AbstractConfigValue(ConfigSection *section, const std::string &name, const std::string &description); // Defined in Config.cpp 10 | virtual ~AbstractConfigValue() = default; 11 | 12 | virtual std::string GetString() const = 0; 13 | virtual std::string DefaultString() const = 0; 14 | virtual void SetString(const std::string &value) = 0; 15 | virtual void Reset() = 0; 16 | 17 | ConfigSection *Section() const { 18 | return section_; 19 | } 20 | 21 | const std::string &Name() const { 22 | return name_; 23 | } 24 | 25 | const std::string &Description() const { 26 | return description_; 27 | } 28 | 29 | private: 30 | ConfigSection *section_ = nullptr; 31 | std::string name_; 32 | std::string description_; 33 | }; 34 | -------------------------------------------------------------------------------- /src/Library/Config/ConfigSection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ConfigFwd.h" 8 | 9 | class ConfigSection { 10 | public: 11 | ConfigSection(::Config *config, const std::string &name); // Defined in Config.cpp 12 | 13 | ConfigSection(const ConfigSection &other) = delete; // non-copyable 14 | ConfigSection(ConfigSection&& other) = delete; // non-movable 15 | 16 | ::Config *Config() const { 17 | return config_; 18 | } 19 | 20 | const std::string &Name() const { 21 | return name_; 22 | } 23 | 24 | void RegisterValue(AbstractConfigValue *value); 25 | 26 | AbstractConfigValue *Value(const std::string &name) const; 27 | 28 | std::vector Values() const; 29 | 30 | private: 31 | ::Config *config_ = nullptr; 32 | std::string name_; 33 | std::map valueByName_; 34 | }; 35 | -------------------------------------------------------------------------------- /test/Testing/Extensions/ThrowingAssertions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifndef GTEST_FATAL_FAILURE_ 6 | # error "Something changed in Google Test implementation, this hack won't work." 7 | #endif 8 | 9 | /* 10 | * Include this header and all your gtest `ASSERT_*` macros will instantly become better: 11 | * - Can be used inside any function, not just the ones returning void. 12 | * - Always stop the current test by throwing an exception. 13 | * 14 | * Note that it won't affect ASSERT_* macros in translation units that don't include this header. 15 | */ 16 | 17 | namespace detail { 18 | struct ScopedEnableThrowingAssertions { 19 | ScopedEnableThrowingAssertions(); 20 | ~ScopedEnableThrowingAssertions(); 21 | }; 22 | } 23 | 24 | #undef GTEST_FATAL_FAILURE_ 25 | #define GTEST_FATAL_FAILURE_(message) \ 26 | detail::ScopedEnableThrowingAssertions(), GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) 27 | -------------------------------------------------------------------------------- /thirdparty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(INCLUDE_THIRDPARTY_DIRS 4 | ${CMAKE_CURRENT_SOURCE_DIR} 5 | ${CMAKE_CURRENT_SOURCE_DIR}/luajit/luajit/src 6 | ${CMAKE_CURRENT_SOURCE_DIR}/glad/include 7 | ${CMAKE_CURRENT_SOURCE_DIR}/glm/glm 8 | ${CMAKE_CURRENT_SOURCE_DIR}/googletest/googletest/include 9 | ${CMAKE_CURRENT_SOURCE_DIR}/mini/src 10 | PARENT_SCOPE) 11 | 12 | set(BUILD_GMOCK OFF) 13 | set(INSTALL_GTEST OFF) 14 | 15 | add_subdirectory(fast_float) 16 | add_subdirectory(fmt) 17 | add_subdirectory(glad) 18 | add_subdirectory(glm) 19 | add_subdirectory(luajit) 20 | add_subdirectory(magic_enum) 21 | add_subdirectory(nuklear) 22 | add_subdirectory(cli11) 23 | add_subdirectory(nlohmann_json) 24 | if(ENABLE_TESTS) 25 | add_subdirectory(googletest) 26 | endif() 27 | 28 | set_target_properties(libluajit PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS}" LINK_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") 29 | -------------------------------------------------------------------------------- /thirdparty/nuklear/nuklear_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define NK_INCLUDE_FIXED_TYPES 6 | #define NK_INCLUDE_STANDARD_IO 7 | #define NK_INCLUDE_STANDARD_VARARGS 8 | #define NK_INCLUDE_DEFAULT_ALLOCATOR 9 | #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT 10 | #define NK_INCLUDE_FONT_BAKING 11 | #define NK_INCLUDE_DEFAULT_FONT 12 | #define NK_IMPLEMENTATION 13 | 14 | #define NK_ASSERT(E) { if (!(E)) { \ 15 | time_t t = time(NULL); \ 16 | struct tm tm = *localtime(&t); \ 17 | fprintf(stderr, "[%04d/%02d/%02d %02d:%02d:%02d] Nuklear Engine: error on %s:%d, condition: '%s'\n", \ 18 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, __FILE__, __LINE__, #E); \ 19 | }} 20 | 21 | #ifdef _DEBUG 22 | #define STBTT_malloc(ptr, userdata) malloc(ptr) 23 | #define STBTT_free(ptr, userdata) free(ptr) 24 | #endif 25 | 26 | #define STBTT_RASTERIZER_VERSION 2 27 | 28 | #include "nuklear.h" 29 | #include "nuklear_internal.h" 30 | -------------------------------------------------------------------------------- /src/Library/Config/ConfigSection.cpp: -------------------------------------------------------------------------------- 1 | #include "ConfigSection.h" 2 | 3 | #include 4 | 5 | #include "Utility/MapAccess.h" 6 | 7 | #include "Config.h" 8 | 9 | ConfigSection::ConfigSection(::Config *config, const std::string &name): config_(config), name_(name) { 10 | assert(config); 11 | assert(!name.empty()); 12 | 13 | config->RegisterSection(this); 14 | } 15 | 16 | void ConfigSection::RegisterValue(AbstractConfigValue *value) { 17 | assert(value); 18 | assert(!valueByName_.contains(value->Name())); 19 | 20 | valueByName_.emplace(value->Name(), value); 21 | } 22 | 23 | AbstractConfigValue *ConfigSection::Value(const std::string &name) const { 24 | return ValueOr(valueByName_, name, nullptr); 25 | } 26 | 27 | std::vector ConfigSection::Values() const { 28 | std::vector result; 29 | for(const auto &[_, value] : valueByName_) 30 | result.push_back(value); 31 | return result; 32 | } 33 | -------------------------------------------------------------------------------- /src/Library/Serialization/SerializationExceptions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "Utility/Flags.h" 9 | 10 | [[noreturn]] void throwEnumSerializationError(int64_t value, std::string_view typeName, bool isFlags); 11 | [[noreturn]] void throwDeserializationError(std::string_view value, std::string_view typeName); 12 | [[noreturn]] void throwNumberDeserializationError(std::string_view invalidValue, std::string_view typeName, std::errc error); 13 | 14 | template 15 | void throwEnumSerializationError(T value, std::string_view typeName) { 16 | if constexpr (std::is_enum_v || std::is_integral_v) { 17 | throwEnumSerializationError(static_cast(value), typeName, false); 18 | } else { 19 | // Assume it's flags. 20 | throwEnumSerializationError(static_cast(std::to_underlying(value)), typeName, true); 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /test/Testing/Game/GameTest.cpp: -------------------------------------------------------------------------------- 1 | #include "GameTest.h" 2 | 3 | #include 4 | 5 | #include "Engine/Plugins/EngineController.h" 6 | 7 | static EngineController *globalEngineController = nullptr; 8 | static TestController *globalTestController = nullptr; 9 | 10 | void GameTest::init(EngineController *engineController, TestController *testController) { 11 | assert(!globalEngineController && !globalTestController); 12 | assert(engineController && testController); 13 | 14 | globalEngineController = engineController; 15 | globalTestController = testController; 16 | } 17 | 18 | void GameTest::SetUp() { 19 | const_cast(game) = globalEngineController; 20 | const_cast(test) = globalTestController; 21 | 22 | game->goToMainMenu(); 23 | test->prepareForNextTest(); 24 | } 25 | 26 | void GameTest::TearDown() { 27 | const_cast(game) = nullptr; 28 | const_cast(test) = nullptr; 29 | } 30 | -------------------------------------------------------------------------------- /src/Utility/Geometry/Rect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Point.h" 4 | #include "Size.h" 5 | 6 | template 7 | struct Rect { 8 | T x = 0; 9 | T y = 0; 10 | T w = 0; 11 | T h = 0; 12 | 13 | Rect() = default; 14 | Rect(T x, T y, T w, T h): x(x), y(y), w(w), h(h) {} 15 | Rect(Point topLeft, Size size): x(topLeft.x), y(topLeft.y), w(size.w), h(size.h) {} 16 | 17 | bool Contains(const Point &point) { 18 | return x <= point.x && point.x < x + w && y <= point.y && point.y < y + h; 19 | } 20 | 21 | Point TopLeft() const { 22 | return {x, y}; 23 | } 24 | 25 | Point BottomRight() const { 26 | return {x + w, y + h}; 27 | } 28 | 29 | Point Center() const { 30 | return {x + w / 2, y + h / 2}; 31 | } 32 | 33 | ::Size Size() const { 34 | return {w, h}; 35 | } 36 | 37 | friend bool operator==(const Rect &l, const Rect &r) = default; 38 | }; 39 | 40 | using Recti = Rect; 41 | -------------------------------------------------------------------------------- /thirdparty/luajit/cmake/cmake/modules/DetectFpuAbi.c: -------------------------------------------------------------------------------- 1 | #if defined(__SOFTFP__) || defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE) || defined(__mips_soft_float) 2 | #define HAS_FPU 0 3 | #else 4 | #define HAS_FPU 1 5 | #endif 6 | 7 | #if !HAS_FPU 8 | const char *str = "\0FPU IS Soft"; 9 | #else 10 | const char *str = "\0FPU IS Hard"; 11 | #endif 12 | 13 | #if defined(__SOFTFP__) || defined(_SOFT_FLOAT) || defined(_SOFT_DOUBLE) || defined(__mips_soft_float) 14 | #define SOFT_FPU_ABI 1 15 | #else 16 | #if (defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM)) && !defined(__ARM_PCS_VFP) 17 | #define SOFT_FPU_ABI 1 18 | #else 19 | #define SOFT_FPU_ABI 0 20 | #endif 21 | #endif 22 | 23 | #if SOFT_FPU_ABI 24 | const char *fpu_abi_str = "\0FPU ABI IS Soft"; 25 | #else 26 | const char *fpu_abi_str = "\0FPU ABI IS Hard"; 27 | #endif 28 | 29 | int main(int argc, char **argv) { 30 | int require = str[argc]; 31 | (void)argv; 32 | require += fpu_abi_str[argc]; 33 | return require; 34 | } 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behaviour: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Environment (please complete the following information):** 24 | - OS: [e.g. Windows, Linux, OSX] 25 | - Architecture [e.g. x86, x64i] 26 | - Version [e.g. Windows 10, Ubuntu 18.04, OSX 10.15] 27 | 28 | **Screenshots** 29 | If applicable, add screenshots to help explain your problem. 30 | 31 | **Saved game file** 32 | If applicable, add saved game file so we can try and reproduce your issue more easily. 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /** 6 | * A convenient base class for other platform proxies. It provides common accessors for the base class, 7 | * and exposes a `nonNullBase` method for derived classes to simplify implementations. 8 | * 9 | * Note that it's perfectly OK for a proxy to point to a null base, and in this case `base` will return `nullptr`, 10 | * but `nonNullBase` will assert, and thus you cannot really call any methods on such a proxy. 11 | * 12 | * @tparam T Platform class to proxy, e.g. a `PlatformWindow`. 13 | */ 14 | template 15 | class ProxyBase : public T { 16 | public: 17 | explicit ProxyBase(T *base) : base_(base) {} 18 | 19 | T *base() const { 20 | return base_; 21 | } 22 | 23 | void setBase(T *base) { 24 | base_ = base; 25 | } 26 | 27 | protected: 28 | T *nonNullBase() const { 29 | assert(base_); 30 | return base_; 31 | } 32 | 33 | private: 34 | T *base_; 35 | }; 36 | -------------------------------------------------------------------------------- /test/Bin/GameTest/GameTestOptions.cpp: -------------------------------------------------------------------------------- 1 | #include "GameTestOptions.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | bool GameTestOptions::Parse(int argc, char **argv) { 8 | std::unique_ptr app = std::make_unique(); 9 | 10 | std::string requiredOptions = "Required Options"; 11 | std::string otherOptions = "Other Options"; 12 | 13 | app->add_option("--test-data", testDataDir, "Path to test data dir")->check(CLI::ExistingDirectory)->option_text("PATH")->required()->group(requiredOptions); 14 | app->add_option("--game-data", gameDataDir, "Path to game data dir")->check(CLI::ExistingDirectory)->option_text("PATH")->group(otherOptions); 15 | app->set_help_flag("-h,--help", "Print help and exit")->group(otherOptions); 16 | app->allow_extras(); 17 | 18 | try { 19 | app->parse(argc, argv); 20 | } catch (const CLI::ParseError &e) { 21 | app->exit(e); 22 | helpRequested = app->get_help_ptr()->as(); 23 | return false; 24 | } 25 | 26 | return true; 27 | } 28 | -------------------------------------------------------------------------------- /src/Media/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(MEDIA_SOURCES Media.cpp 4 | MediaPlayer.cpp 5 | MediaLogger.cpp 6 | Audio/AudioPlayer.cpp 7 | Audio/OpenALSoundProvider.cpp) 8 | 9 | set(MEDIA_HEADERS Media.h 10 | MediaPlayer.h 11 | MediaLogger.h 12 | Audio/AudioPlayer.h 13 | Audio/OpenALSoundProvider.h) 14 | 15 | add_library(media STATIC ${MEDIA_SOURCES} ${MEDIA_HEADERS}) 16 | target_link_libraries(media utility game) 17 | target_compile_definitions(media PRIVATE FF_API_NEXT) 18 | 19 | include_directories(${INCLUDE_DIRECTORIES} ${OPENAL_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIRS}) 20 | target_link_libraries(media ${OPENAL_LIBRARY} ${AVCODEC_LIBRARIES} ${AVFORMAT_LIBRARIES} ${AVUTIL_LIBRARIES} ${SWSCALE_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) 21 | 22 | target_check_style(media) 23 | 24 | message(VERBOSE "FFMPEG_LIBRARIES: ${FFMPEG_LIBRARIES}") 25 | message(VERBOSE "OPENAL_LIBRARY: ${OPENAL_LIBRARY}") 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/luajit"] 2 | path = thirdparty/luajit/luajit 3 | url = https://github.com/LuaJIT/LuaJIT 4 | branch = v2.1 5 | [submodule "thirdparty/glm"] 6 | path = thirdparty/glm 7 | url = https://github.com/g-truc/glm 8 | [submodule "thirdparty/mini"] 9 | path = thirdparty/mini 10 | url = https://github.com/pulzed/mINI 11 | [submodule "thirdparty/googletest"] 12 | path = thirdparty/googletest 13 | url = https://github.com/google/googletest.git 14 | [submodule "thirdparty/cli11"] 15 | path = thirdparty/cli11 16 | url = https://github.com/CLIUtils/CLI11.git 17 | [submodule "thirdparty/fmt"] 18 | path = thirdparty/fmt 19 | url = https://github.com/fmtlib/fmt.git 20 | [submodule "thirdparty/nlohmann_json"] 21 | path = thirdparty/nlohmann_json 22 | url = https://github.com/nlohmann/json.git 23 | [submodule "thirdparty/magic_enum"] 24 | path = thirdparty/magic_enum 25 | url = https://github.com/Neargye/magic_enum.git 26 | [submodule "thirdparty/fast_float"] 27 | path = thirdparty/fast_float 28 | url = https://github.com/fastfloat/fast_float.git 29 | -------------------------------------------------------------------------------- /src/Engine/Objects/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(OBJECTS_SOURCES Actor.cpp 4 | Chest.cpp 5 | Items.cpp 6 | ItemTable.cpp 7 | Monsters.cpp 8 | NPC.cpp 9 | ObjectList.cpp 10 | Player.cpp 11 | SpriteObject.cpp) 12 | 13 | set(OBJECTS_HEADERS Actor.h 14 | ActorEnums.h 15 | Chest.h 16 | ItemEnchantment.h 17 | ItemEnums.h 18 | Items.h 19 | ItemTable.h 20 | Monsters.h 21 | NPC.h 22 | NPCEnums.h 23 | ObjectList.h 24 | Player.h 25 | PlayerEnums.h 26 | SpriteObject.h) 27 | 28 | add_library(objects STATIC ${OBJECTS_SOURCES} ${OBJECTS_HEADERS}) 29 | target_check_style(objects) 30 | 31 | target_link_libraries(objects engine gui utility) 32 | -------------------------------------------------------------------------------- /src/Application/GameKeyboardController.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Utility/IndexedArray.h" 6 | 7 | #include "Library/Application/PlatformApplicationAware.h" 8 | 9 | #include "Io/IKeyboardController.h" 10 | 11 | class PlatformKeyEvent; 12 | 13 | // TODO(captainurist): deriving from PlatformApplicationAware is a temporary (and ugly!) measure. 14 | // We need it so that `EngineTracer` can call reset. Just turn this one into an event filter! 15 | class GameKeyboardController: public Io::IKeyboardController, public PlatformApplicationAware { 16 | public: 17 | GameKeyboardController(); 18 | 19 | virtual bool ConsumeKeyPress(PlatformKey key) override; 20 | virtual bool IsKeyDown(PlatformKey key) const override; 21 | 22 | void ProcessKeyPressEvent(const PlatformKeyEvent *event); 23 | void ProcessKeyReleaseEvent(const PlatformKeyEvent *event); 24 | 25 | void reset(); 26 | 27 | private: 28 | IndexedArray isKeyDown_ = {{}}; 29 | IndexedArray isKeyDownReported_ = {{}}; 30 | }; 31 | -------------------------------------------------------------------------------- /src/GUI/UI/UIDialogue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "GUI/GUIWindow.h" 6 | 7 | 8 | class GUIWindow_Dialogue : public GUIWindow { 9 | public: 10 | GUIWindow_Dialogue(Pointi position, Sizei dimensions, WindowData data, const std::string &hint = std::string()); 11 | virtual ~GUIWindow_Dialogue() {} 12 | 13 | virtual void Update(); 14 | virtual void Release(); 15 | }; 16 | 17 | void GameUI_InitializeDialogue(Actor *actor, int bPlayerSaysHello); 18 | 19 | class GUIWindow_GenericDialogue : public GUIWindow { 20 | public: 21 | GUIWindow_GenericDialogue(Pointi position, Sizei dimensions, WindowData data, const std::string &hint = std::string()); 22 | virtual ~GUIWindow_GenericDialogue() {} 23 | 24 | virtual void Update(); 25 | virtual void Release(); 26 | }; 27 | 28 | void StartBranchlessDialogue(int eventid, int entryline, int button); 29 | 30 | void OnSelectNPCDialogueOption(DIALOGUE_TYPE option); 31 | 32 | extern const IndexedArray DialogueBackgroundResourceByAlignment; 33 | -------------------------------------------------------------------------------- /src/Engine/Tables/PlayerFrameTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Engine/Objects/Player.h" 4 | 5 | #include "Utility/Memory/Blob.h" 6 | 7 | /* 46 */ 8 | #pragma pack(push, 1) 9 | struct PlayerFrame { 10 | CHARACTER_EXPRESSION_ID expression; 11 | uint16_t uTextureID; 12 | int16_t uAnimTime; 13 | int16_t uAnimLength; 14 | int16_t uFlags; 15 | }; 16 | #pragma pack(pop) 17 | 18 | /* 47 */ 19 | #pragma pack(push, 1) 20 | struct PlayerFrameTable { 21 | inline PlayerFrameTable() : uNumFrames(0), pFrames(nullptr) {} 22 | 23 | unsigned int GetFrameIdByExpression(CHARACTER_EXPRESSION_ID expression); 24 | PlayerFrame *GetFrameBy_x(unsigned int uFramesetID, unsigned int uFrameID); 25 | PlayerFrame *GetFrameBy_y(int *a2, int *a3, int a4); 26 | void ToFile(); 27 | void FromFile(const Blob &data_mm6, const Blob &data_mm7, const Blob &data_mm8); 28 | int FromFileTxt(const char *Args); 29 | 30 | unsigned int uNumFrames; 31 | struct PlayerFrame *pFrames; 32 | }; 33 | #pragma pack(pop) 34 | 35 | extern struct PlayerFrameTable *pPlayerFrameTable; // idb 36 | -------------------------------------------------------------------------------- /resources/shaders/gloutbuild.vert: -------------------------------------------------------------------------------- 1 | layout (location = 0) in vec3 vaPos; 2 | layout (location = 1) in vec2 vaTexUV; 3 | layout (location = 2) in vec2 vaTexLayer; 4 | layout (location = 3) in vec3 vaNormal; 5 | layout (location = 4) in float vaAttrib; 6 | 7 | out vec4 vertexColour; 8 | out vec2 texuv; 9 | flat out vec2 olayer; 10 | out vec3 vsPos; 11 | out vec3 vsNorm; 12 | flat out int vsAttrib; 13 | out vec4 viewspace; 14 | 15 | uniform mat4 view; 16 | uniform mat4 projection; 17 | 18 | void main() { 19 | viewspace = view * vec4(vaPos, 1.0); 20 | gl_Position = projection * view * vec4(vaPos, 1.0); 21 | 22 | //if (gl_Position.z > 1.0) 23 | // gl_Position = vec4(gl_Position.x, gl_Position.y, 0.999999999999, gl_Position.w); 24 | 25 | // rgb unused 26 | //float opacity = smoothstep(1.0 , 0.9999, gl_Position.z / gl_Position.w); 27 | //if (gl_Position.z < 0.0) opacity = 1.0; 28 | vertexColour = vec4(0.0, 0.0, 0.0, 1.0); 29 | 30 | texuv = vaTexUV; 31 | olayer = vaTexLayer; 32 | vsPos = vaPos; 33 | vsNorm = vaNormal; 34 | vsAttrib = int(vaAttrib); 35 | } 36 | -------------------------------------------------------------------------------- /test/Testing/Extensions/ThrowingAssertions.cpp: -------------------------------------------------------------------------------- 1 | #include "ThrowingAssertions.h" 2 | 3 | static bool globalThrowListenerInstalled = false; 4 | static bool globalThrowListenerEnabled = false; 5 | 6 | class ThrowListener : public testing::EmptyTestEventListener { 7 | void OnTestPartResult(const testing::TestPartResult& result) override { 8 | if (!globalThrowListenerEnabled) 9 | return; 10 | 11 | if (result.type() == testing::TestPartResult::kFatalFailure) { 12 | throw testing::AssertionException(result); 13 | } 14 | } 15 | }; 16 | 17 | detail::ScopedEnableThrowingAssertions::ScopedEnableThrowingAssertions() { 18 | // Totally not thread-safe, but gtest is not thread-safe on Windows anyway. 19 | if (!globalThrowListenerInstalled) { 20 | testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener); 21 | globalThrowListenerInstalled = true; 22 | } 23 | 24 | globalThrowListenerEnabled = true; 25 | } 26 | 27 | detail::ScopedEnableThrowingAssertions::~ScopedEnableThrowingAssertions() { 28 | globalThrowListenerEnabled = false; 29 | } 30 | -------------------------------------------------------------------------------- /src/Platform/Filters/FilteringEventHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "FilteringEventHandler.h" 2 | 3 | #include "Utility/Reversed.h" 4 | #include "Utility/ScopeGuard.h" 5 | 6 | #include "PlatformEventFilter.h" 7 | 8 | void FilteringEventHandler::event(const PlatformEvent *event) { 9 | _insideEvent = true; 10 | MM_AT_SCOPE_EXIT(_insideEvent = false); 11 | 12 | for (PlatformEventFilter *filter : Reversed(_filters[event->type])) 13 | if (filter->event(event)) 14 | return; 15 | } 16 | 17 | void FilteringEventHandler::installEventFilter(PlatformEventFilter *filter) { 18 | assert(!_insideEvent); // This can be properly supported, but right now it's not really needed. 19 | 20 | for (PlatformEventType eventType : filter->eventTypes()) 21 | _filters[eventType].push_back(filter); 22 | } 23 | 24 | void FilteringEventHandler::removeEventFilter(PlatformEventFilter *filter) { 25 | assert(!_insideEvent); // This can be properly supported, but right now it's not really needed. 26 | 27 | for (PlatformEventType eventType : filter->eventTypes()) 28 | std::erase(_filters[eventType], filter); 29 | } 30 | -------------------------------------------------------------------------------- /src/Engine/SaveLoad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Engine/Time.h" 7 | 8 | constexpr unsigned int MAX_SAVE_SLOTS = 45; 9 | 10 | struct SavegameList { 11 | static void Initialize(); 12 | SavegameList(); 13 | 14 | void Reset(); 15 | 16 | std::array pFileList; 17 | }; 18 | 19 | /* 244 */ 20 | #pragma pack(push, 1) 21 | struct SavegameHeader { 22 | char pName[20]{}; 23 | char pLocationName[20]{}; 24 | GameTime playing_time{}; // uint64_t uWordTime; 25 | char field_30[52]{}; 26 | }; 27 | #pragma pack(pop) 28 | 29 | void LoadGame(unsigned int uSlot); 30 | void SaveGame(bool IsAutoSAve, bool NotSaveWorld); 31 | void DoSavegame(unsigned int uSlot); 32 | bool Initialize_GamesLOD_NewLOD(); 33 | void SaveNewGame(); 34 | 35 | extern unsigned int uNumSavegameFiles; 36 | extern std::array pSavegameUsedSlots; 37 | extern struct SavegameList *pSavegameList; 38 | extern std::array pSavegameHeader; 39 | 40 | extern std::array pSavegameThumbnails; 41 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyPlatform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Platform/Platform.h" 8 | 9 | #include "ProxyBase.h" 10 | 11 | class ProxyPlatform : public ProxyBase { 12 | public: 13 | explicit ProxyPlatform(Platform *base = nullptr); 14 | 15 | virtual ~ProxyPlatform() = default; 16 | 17 | virtual std::unique_ptr createWindow() override; 18 | virtual std::unique_ptr createEventLoop() override; 19 | virtual std::unique_ptr createGamepad(uint32_t id) override; 20 | virtual void setCursorShown(bool cursorShown) override; 21 | virtual bool isCursorShown() const override; 22 | virtual std::vector displayGeometries() const override; 23 | virtual void showMessageBox(const std::string& title, const std::string &message) const override; 24 | virtual int64_t tickCount() const override; 25 | virtual std::string winQueryRegistry(const std::wstring &path) const override; 26 | virtual std::string storagePath(const PlatformStorage type) const override; 27 | }; 28 | -------------------------------------------------------------------------------- /src/Library/Application/PlatformApplicationAware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class PlatformApplication; 4 | 5 | /** 6 | * Derive your plugin from `PlatformApplicationAware` to get access to an application instance that it was 7 | * installed into. 8 | */ 9 | class PlatformApplicationAware { 10 | protected: 11 | ~PlatformApplicationAware() = default; // Don't destroy instances through this interface. 12 | 13 | PlatformApplication *application() const { 14 | return _application; 15 | } 16 | 17 | /** 18 | * Called after installation into a `PlatformApplication`. `application()` will return non-null inside this function. 19 | */ 20 | virtual void installNotify() {} 21 | 22 | /** 23 | * Called before removal from a `PlatformApplication`. `application()` will return non-null inside this function. 24 | */ 25 | virtual void removeNotify() {} 26 | 27 | private: 28 | friend class PlatformApplication; 29 | 30 | void setApplication(PlatformApplication *application) { 31 | _application = application; 32 | } 33 | 34 | private: 35 | PlatformApplication *_application = nullptr; 36 | }; 37 | -------------------------------------------------------------------------------- /src/Engine/Plugins/EngineTracePlugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Platform/Proxy/ProxyOpenGLContext.h" 4 | #include "Platform/Filters/PlatformEventFilter.h" 5 | 6 | #include "Library/Application/PlatformApplicationAware.h" 7 | #include "Library/Trace/EventTrace.h" 8 | 9 | /** 10 | * Plugin that can be used to record events. 11 | * 12 | * Note that this plugin is intentionally very dumb. Calling `start` starts recording events right away, and 13 | * calling `finish` just returns everything that was recorded. 14 | */ 15 | class EngineTracePlugin : private ProxyOpenGLContext, private PlatformEventFilter, private PlatformApplicationAware { 16 | public: 17 | EngineTracePlugin(); 18 | virtual ~EngineTracePlugin(); 19 | 20 | void start(); 21 | EventTrace finish(); 22 | 23 | bool isTracing() const { 24 | return _tracing; 25 | } 26 | 27 | private: 28 | friend class PlatformIntrospection; // Give access to private bases. 29 | 30 | virtual void swapBuffers() override; 31 | virtual bool event(const PlatformEvent *event) override; 32 | 33 | private: 34 | bool _tracing = false; 35 | EventTrace _trace; 36 | }; 37 | -------------------------------------------------------------------------------- /src/Media/MediaPlayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Media/Media.h" 7 | 8 | // MOVIE_3DOLogo "3dologo" 9 | // MOVIE_NWCLogo "new world logo" 10 | // MOVIE_JVC "jvc" 11 | // MOVIE_Intro "Intro" 12 | // MOVIE_Emerald "Intro Post" 13 | // MOVIE_Death "losegame" 14 | // MOVIE_Outro "end_seq1" 15 | 16 | class VideoList; 17 | class MediaLogger; 18 | 19 | class MPlayer { 20 | public: 21 | MPlayer(); 22 | virtual ~MPlayer(); 23 | 24 | void Initialize(); 25 | void Unload(); 26 | 27 | void PlayFullscreenMovie(const std::string &pMovieName); 28 | 29 | void OpenHouseMovie(const std::string &pMovieName, bool bLoop); 30 | void HouseMovieLoop(); 31 | 32 | bool IsMoviePlaying() const; 33 | bool StopMovie(); 34 | 35 | protected: 36 | std::unique_ptr mediaLogger; 37 | VideoList *might_list; 38 | VideoList *magic_list; 39 | std::string sInHouseMovie; 40 | 41 | FILE *LoadMovie(const std::string &video_name, size_t &size, 42 | size_t &offset); 43 | }; 44 | 45 | extern MPlayer *pMediaPlayer; 46 | extern PMovie pMovie_Track; 47 | -------------------------------------------------------------------------------- /src/Utility/Tests/Segment_ut.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Testing/Unit/UnitTest.h" 5 | 6 | #include "Utility/Segment.h" 7 | 8 | UNIT_TEST(Segment, Iteration) { 9 | enum class Index { AA, BB, CC }; 10 | using enum Index; 11 | 12 | int counter = 0; 13 | for(Index i : Segment(AA, CC)) 14 | counter++; 15 | EXPECT_EQ(counter, 3); 16 | 17 | counter = 0; 18 | for(Index i : Segment(AA, AA)) 19 | counter++; 20 | EXPECT_EQ(counter, 1); 21 | 22 | std::vector v; 23 | for(int i : Segment(0, 99)) 24 | v.push_back(i); 25 | std::vector w(100, 0); 26 | std::iota(w.begin(), w.end(), 0); 27 | EXPECT_EQ(v, w); 28 | } 29 | 30 | UNIT_TEST(Segment, Contains) { 31 | auto seg = Segment(0, 2); 32 | 33 | EXPECT_FALSE(seg.contains(-1)); 34 | EXPECT_TRUE(seg.contains(0)); 35 | EXPECT_TRUE(seg.contains(1)); 36 | EXPECT_TRUE(seg.contains(2)); 37 | EXPECT_FALSE(seg.contains(3)); 38 | } 39 | 40 | UNIT_TEST(Segment, Constexpr) { 41 | constexpr auto seg = Segment(0, 2); 42 | constexpr bool b = seg.contains(1); 43 | 44 | EXPECT_TRUE(b); 45 | } 46 | -------------------------------------------------------------------------------- /src/Application/GameKeyboardController.cpp: -------------------------------------------------------------------------------- 1 | #include "GameKeyboardController.h" 2 | 3 | #include "Platform/PlatformEvents.h" 4 | 5 | GameKeyboardController::GameKeyboardController() {} 6 | 7 | bool GameKeyboardController::ConsumeKeyPress(PlatformKey key) { 8 | if (key == PlatformKey::None) 9 | return false; 10 | 11 | if (!isKeyDown_[key]) 12 | return false; 13 | 14 | if (isKeyDownReported_[key]) 15 | return false; 16 | 17 | isKeyDownReported_[key] = true; 18 | return true; 19 | } 20 | 21 | bool GameKeyboardController::IsKeyDown(PlatformKey key) const { 22 | return isKeyDown_[key]; 23 | } 24 | 25 | void GameKeyboardController::ProcessKeyPressEvent(const PlatformKeyEvent *event) { 26 | if (isKeyDown_[event->key]) 27 | return; // Auto repeat 28 | 29 | isKeyDown_[event->key] = true; 30 | isKeyDownReported_[event->key] = false; 31 | } 32 | 33 | void GameKeyboardController::ProcessKeyReleaseEvent(const PlatformKeyEvent *event) { 34 | isKeyDown_[event->key] = false; 35 | } 36 | 37 | void GameKeyboardController::reset() { 38 | isKeyDown_.fill(false); 39 | isKeyDownReported_.fill(false); 40 | } 41 | -------------------------------------------------------------------------------- /src/Engine/Tables/StorylineTextTable.cpp: -------------------------------------------------------------------------------- 1 | #include "Engine/Tables/StorylineTextTable.h" 2 | 3 | #include 4 | 5 | #include "Utility/String.h" 6 | #include "../LOD.h" 7 | 8 | std::string pHistoryTXT_Raw; 9 | struct StorylineText *pStorylineText; 10 | 11 | //----- (00453E6D) -------------------------------------------------------- 12 | void StorylineText::Initialize() { 13 | char *test_string; 14 | 15 | pHistoryTXT_Raw = pEvents_LOD->LoadCompressedTexture("history.txt").string_view(); 16 | strtok(pHistoryTXT_Raw.data(), "\r"); 17 | 18 | StoreLine[0].pText = nullptr; 19 | StoreLine[0].pPageTitle = nullptr; 20 | StoreLine[0].uTime = 0; 21 | StoreLine[0].f_9 = 0; 22 | StoreLine[0].f_A = 0; 23 | StoreLine[0].f_B = 0; 24 | 25 | for (int i = 0; i < 28; ++i) { 26 | test_string = strtok(NULL, "\r") + 1; 27 | auto tokens = Tokenize(test_string, '\t'); 28 | 29 | StoreLine[i + 1].pText = RemoveQuotes(tokens[1]); 30 | StoreLine[i + 1].uTime = 31 | atoi(tokens[2]); // strange but in text here string not digit 32 | StoreLine[i + 1].pPageTitle = RemoveQuotes(tokens[3]); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Library/Serialization/SerializationExceptions.cpp: -------------------------------------------------------------------------------- 1 | #include "SerializationExceptions.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "Utility/Format.h" 7 | 8 | void throwEnumSerializationError(int64_t value, std::string_view typeName, bool isFlags) { 9 | throw std::runtime_error(fmt::format("Cannot serialize provided {} value `{}` of type {} to string", isFlags ? "flags" : "enum", value, typeName)); 10 | } 11 | 12 | void throwDeserializationError(std::string_view value, std::string_view typeName) { 13 | throw std::runtime_error(fmt::format("Cannot deserialize '{}' as type {}", value, typeName)); 14 | } 15 | 16 | void throwNumberDeserializationError(std::string_view invalidValue, std::string_view typeName, std::errc error) { 17 | if (error == std::errc::invalid_argument) 18 | throw std::runtime_error(fmt::format("'{}' is not a number"_cf, invalidValue)); 19 | 20 | if (error == std::errc::result_out_of_range) 21 | throw std::runtime_error(fmt::format("'{}' does not fit in the range of {}"_cf, invalidValue, typeName)); 22 | 23 | throw std::system_error(std::make_error_code(error), std::string(invalidValue)); 24 | } 25 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlGamepad.cpp: -------------------------------------------------------------------------------- 1 | #include "SdlGamepad.h" 2 | 3 | #include 4 | 5 | #include "SdlPlatformSharedState.h" 6 | 7 | SdlGamepad::SdlGamepad(SdlPlatformSharedState *state, SDL_GameController *gamepad, uint32_t id): 8 | _state(state), _gamepad(gamepad), _id(id) { 9 | assert(state); 10 | assert(gamepad); 11 | } 12 | 13 | SdlGamepad::~SdlGamepad() { 14 | _state->unregisterGamepad(this); 15 | SDL_GameControllerClose(_gamepad); 16 | } 17 | 18 | std::string SdlGamepad::model() const { 19 | const char *model = SDL_GameControllerName(sdlHandle()); 20 | if (model != NULL) 21 | return model; 22 | 23 | return {}; 24 | } 25 | 26 | std::string SdlGamepad::serial() const { 27 | // TODO: Just update SDL 28 | #if SDL_VERSION_ATLEAST(2, 0, 14) 29 | const char *serial = SDL_GameControllerGetSerial(sdlHandle()); 30 | if (serial != NULL) 31 | return serial; 32 | #endif 33 | 34 | return {}; 35 | } 36 | 37 | int32_t SdlGamepad::gamepadSdlId() { 38 | SDL_Joystick *joystick = SDL_GameControllerGetJoystick(sdlHandle()); 39 | int32_t joystickId = SDL_JoystickInstanceID(joystick); 40 | 41 | return joystickId; 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/shaders.yml: -------------------------------------------------------------------------------- 1 | name: Shaders 2 | 3 | on: 4 | pull_request: 5 | push: 6 | release: 7 | types: [published] 8 | 9 | jobs: 10 | check_shaders: 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | with: 16 | submodules: 'recursive' 17 | 18 | - name: Install dependencies 19 | run: | 20 | sudo apt-get update 21 | sudo apt-get install -y glslang-tools 22 | 23 | - name: Check OpenGL 4.1 (Core) shaders 24 | working-directory: resources/shaders 25 | run: | 26 | mkdir ../shaders_opengl41core 27 | find . -type f -exec bash -c 'echo "#version 410 core" > ../shaders_opengl41core/{} && cat {} >> ../shaders_opengl41core/{}' \; 28 | find ../shaders_opengl41core -type f | xargs -n1 glslangValidator 29 | 30 | - name: Check OpenGL ES 3.2 shaders 31 | working-directory: resources/shaders 32 | run: | 33 | mkdir ../shaders_opengles32 34 | find . -type f -exec bash -c 'echo "#version 320 es" > ../shaders_opengles32/{} && cat {} >> ../shaders_opengles32/{}' \; 35 | find ../shaders_opengles32 -type f | xargs -n1 glslangValidator 36 | -------------------------------------------------------------------------------- /src/Utility/Math/FixPoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | inline int64_t fixpoint_mul(int32_t l, int32_t r) { 7 | return (static_cast(l) * r) >> 16; 8 | } 9 | 10 | inline int64_t fixpoint_div(int32_t l, int32_t r) { 11 | return (static_cast(l) << 16) / r; 12 | } 13 | 14 | // These shouldn't compile: 15 | void fixpoint_mul(float, float) = delete; 16 | void fixpoint_div(float, float) = delete; 17 | void fixpoint_mul(double, double) = delete; 18 | void fixpoint_div(double, double) = delete; 19 | 20 | /** 21 | * @param value Fixed-point value. 22 | * @return Corresponding value as a `float`. 23 | */ 24 | inline float fixpoint_to_float(int32_t value) { 25 | return static_cast(value / 65536.0); 26 | } 27 | 28 | // TODO(captainurist): Drop! 29 | /** 30 | * Takes a non-fixpoint vector and normalizes it, resulting in a fixpoint vector. 31 | */ 32 | inline void normalize_to_fixpoint(int *x, int *y, int *z) { 33 | int denom = *y * *y + *z * *z + *x * *x; 34 | int mult = 65536 / (static_cast(std::sqrt(denom)) | 1); 35 | *x *= mult; 36 | *y *= mult; 37 | *z *= mult; 38 | } 39 | -------------------------------------------------------------------------------- /src/Application/GameTraceHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Platform/Filters/PlatformEventFilter.h" 4 | 5 | class EngineTracer; 6 | 7 | // TODO(captainurist): tbh we just need a hotkey system instead of this monstrosity. 8 | /** 9 | * Event filter that reacts to start/stop recording hotkey and calls into event tracer to start/stop recording. 10 | * 11 | * Note that this event filter should be installed last (or at least after the `EventTracer`), so that the start/stop 12 | * keystrokes don't end up being recorded. Technically there's nothing wrong with recording them, but there's little 13 | * point in doing so. 14 | */ 15 | class GameTraceHandler : public PlatformEventFilter { 16 | public: 17 | explicit GameTraceHandler(EngineTracer *tracer); 18 | virtual ~GameTraceHandler() = default; 19 | 20 | virtual bool keyPressEvent(const PlatformKeyEvent *event) override; 21 | virtual bool keyReleaseEvent(const PlatformKeyEvent *event) override; 22 | 23 | private: 24 | bool isTriggerKey(const PlatformKeyEvent *event) const; 25 | bool isTriggerKeySequence(const PlatformKeyEvent *event) const; 26 | 27 | private: 28 | EngineTracer *_tracer = nullptr; 29 | bool _waitingForKeyRelease = false; 30 | }; 31 | -------------------------------------------------------------------------------- /resources/shaders/gldecalshader.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | in vec4 vertexColour; 4 | in vec2 texuv; 5 | //flat in float olayer; 6 | //in vec3 vsPos; 7 | //in vec3 vsNorm; 8 | //flat in int vsAttrib; 9 | in vec4 viewspace; 10 | 11 | out vec4 FragColour; 12 | 13 | struct FogParam { 14 | vec3 color; 15 | float fogstart; 16 | float fogmiddle; 17 | float fogend; 18 | }; 19 | 20 | uniform sampler2D texture0; 21 | uniform FogParam fog; 22 | 23 | float getFogRatio(FogParam fogpar, float dist); 24 | 25 | void main() { 26 | vec4 fragcol = texture(texture0, texuv) * vertexColour; 27 | if (fog.fogstart == fog.fogend) { 28 | FragColour = fragcol; 29 | return; 30 | } 31 | 32 | float fograt = getFogRatio(fog, abs(viewspace.z/ viewspace.w)); 33 | if (fragcol.a < 0.004) fograt = 0.0; 34 | 35 | FragColour = mix(fragcol, vec4(0.0), fograt); 36 | 37 | } 38 | 39 | float getFogRatio(FogParam fogpar, float dist) { 40 | float result = 0.0; 41 | if (fogpar.fogstart < fogpar.fogmiddle) { 42 | result = 0.25 + smoothstep(fogpar.fogstart, fogpar.fogmiddle, dist) * 0.75; 43 | } else { 44 | result = smoothstep(fogpar.fogstart, fogpar.fogend, dist); 45 | } 46 | return result; 47 | } 48 | -------------------------------------------------------------------------------- /src/Library/Serialization/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | set(SERIALIZATION_SOURCES SerializationExceptions.cpp 4 | EnumSerializer.cpp 5 | StandardSerialization.cpp) 6 | 7 | set(SERIALIZATION_HEADERS Serialization.h 8 | SerializationFwd.h 9 | EnumSerialization.h 10 | EnumSerializer.h 11 | SerializationExceptions.h 12 | StandardSerialization.h) 13 | 14 | add_library(serialization STATIC ${SERIALIZATION_SOURCES} ${SERIALIZATION_HEADERS}) 15 | target_link_libraries(serialization utility magic_enum::magic_enum FastFloat::fast_float) 16 | target_check_style(serialization) 17 | 18 | 19 | if(ENABLE_TESTS) 20 | set(TEST_SERIALIZATION_SOURCES Tests/Serialization_ut.cpp) 21 | 22 | add_library(test_serialization OBJECT ${TEST_SERIALIZATION_SOURCES}) 23 | target_compile_definitions(test_serialization PRIVATE TEST_GROUP=Serialization) 24 | target_link_libraries(test_serialization serialization) 25 | 26 | target_check_style(test_serialization) 27 | 28 | target_link_libraries(OpenEnroth_UnitTest test_serialization) 29 | endif() 30 | -------------------------------------------------------------------------------- /src/Utility/FileSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * This function handles home-relative paths, so this is the preferred method of constructing 8 | * absolute paths instead of calling `std::filesystem::path` constructor. 9 | * 10 | * @param path Path as a string. 11 | * @return Path as `std::filesystem::path`. 12 | */ 13 | std::filesystem::path ExpandUserPath(std::string path); 14 | 15 | /** 16 | * This function emulates the behavior of a case-insensitive filesystem. You pass in a path, this function traverses 17 | * it as if the underlying filesystem was case-insensitive, and returns a case-corrected path that actually exists. 18 | * 19 | * Case sensitivity is properly handled only for ascii characters. 20 | * 21 | * Note that this is not about Windows vs Linux. On Windows case sensitivity can be set per directory. On Linux it's 22 | * possible to mount case-insensitive partitions. 23 | * 24 | * @param path Requested path. 25 | * @return Case-corrected path if it exists, original path otherwise. 26 | */ 27 | std::filesystem::path MakeCaseInsensitivePath(std::filesystem::path path); 28 | -------------------------------------------------------------------------------- /src/Platform/PlatformEventHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PlatformEvents.h" 4 | 5 | /** 6 | * Event handler interface, to be implemented in user code. 7 | * 8 | * @see PlatformEventLoop 9 | * @see FilteringEventHandler 10 | */ 11 | class PlatformEventHandler { 12 | public: 13 | virtual ~PlatformEventHandler() = default; 14 | 15 | virtual void event(const PlatformEvent *event); 16 | 17 | protected: 18 | virtual void keyPressEvent(const PlatformKeyEvent *event); 19 | virtual void keyReleaseEvent(const PlatformKeyEvent *event); 20 | virtual void mouseMoveEvent(const PlatformMouseEvent *event); 21 | virtual void mousePressEvent(const PlatformMouseEvent *event); 22 | virtual void mouseReleaseEvent(const PlatformMouseEvent *event); 23 | virtual void wheelEvent(const PlatformWheelEvent *event); 24 | virtual void moveEvent(const PlatformMoveEvent *event); 25 | virtual void resizeEvent(const PlatformResizeEvent *event); 26 | virtual void activationEvent(const PlatformWindowEvent *event); 27 | virtual void closeEvent(const PlatformWindowEvent *event); 28 | virtual void gamepadDeviceEvent(const PlatformGamepadDeviceEvent *event); 29 | virtual void nativeEvent(const PlatformNativeEvent *event); 30 | }; 31 | -------------------------------------------------------------------------------- /src/Library/Lod/LodReader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Library/Lod/LodVersion.h" 8 | #include "Library/Lod/Internal/LodDirectory.h" 9 | #include "Library/Lod/Internal/LodFile.h" 10 | #include "Utility/Memory/Blob.h" 11 | 12 | 13 | /** 14 | * A single stop shop to read LOD files. 15 | * Even though LODs support a multi-directory structure, in reality vanilla games only ever had a single directory each. 16 | * 17 | * Given that we don't plan to expand the LOD format support, when resolving the files this class always looks 18 | * into the first available directory, which is consistent with the vanilla behaviour. 19 | */ 20 | class LodReader final { 21 | public: 22 | static std::unique_ptr open(const std::string &filename); 23 | 24 | inline ~LodReader() { 25 | if (nullptr != _fp) { 26 | fclose(_fp); 27 | } 28 | } 29 | 30 | bool exists(const std::string &filename) const; 31 | Blob read(const std::string &filename); 32 | 33 | private: 34 | bool _isFileCompressed(const LodFile &file); 35 | 36 | FILE *_fp; 37 | LodVersion _version; 38 | std::string _description; 39 | std::vector _index; 40 | }; 41 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlOpenGLContext.cpp: -------------------------------------------------------------------------------- 1 | #include "SdlOpenGLContext.h" 2 | 3 | #include 4 | 5 | #include "SdlPlatformSharedState.h" 6 | 7 | SdlOpenGLContext::SdlOpenGLContext(SdlPlatformSharedState *state, SDL_Window *window, SDL_GLContext context): _state(state), _window(window), _context(context) { 8 | assert(state); 9 | assert(window); 10 | assert(context); 11 | } 12 | 13 | SdlOpenGLContext::~SdlOpenGLContext() {} 14 | 15 | bool SdlOpenGLContext::bind() { 16 | bool succeeded = SDL_GL_MakeCurrent(_window, _context) == 0; 17 | 18 | if (!succeeded) 19 | _state->logSdlError("SDL_GL_MakeCurrent"); 20 | 21 | return succeeded; 22 | } 23 | 24 | bool SdlOpenGLContext::unbind() { 25 | bool succeeded = SDL_GL_MakeCurrent(_window, nullptr) == 0; 26 | 27 | if (!succeeded) 28 | _state->logSdlError("SDL_GL_MakeCurrent"); 29 | 30 | return succeeded; 31 | } 32 | 33 | void SdlOpenGLContext::swapBuffers() { 34 | SDL_GL_SwapWindow(_window); 35 | } 36 | 37 | void *SdlOpenGLContext::getProcAddress(const char* name) { 38 | if (SDL_GL_GetCurrentWindow() != _window || SDL_GL_GetCurrentContext() != _context) 39 | if (!bind()) 40 | return nullptr; 41 | 42 | return SDL_GL_GetProcAddress(name); 43 | } 44 | -------------------------------------------------------------------------------- /src/Utility/Streams/FileOutputStream.cpp: -------------------------------------------------------------------------------- 1 | #include "FileOutputStream.h" 2 | 3 | #include 4 | #include 5 | 6 | FileOutputStream::FileOutputStream(const std::string &path) : path_(path) { 7 | file_ = fopen(path_.c_str(), "wb"); 8 | if (!file_) 9 | ThrowFromErrno(); 10 | } 11 | 12 | FileOutputStream::~FileOutputStream() { 13 | CloseInternal(false); 14 | } 15 | 16 | void FileOutputStream::Write(const void *data, size_t size) { 17 | assert(file_); // Writing into a closed stream is UB. 18 | 19 | if (fwrite(data, size, 1, file_) != 1) 20 | ThrowFromErrno(); 21 | } 22 | 23 | void FileOutputStream::Flush() { 24 | assert(file_); // Flushing a closed stream is UB. 25 | 26 | if (fflush(file_) != 0) 27 | ThrowFromErrno(); 28 | } 29 | 30 | void FileOutputStream::Close() { 31 | CloseInternal(true); 32 | } 33 | 34 | void FileOutputStream::CloseInternal(bool canThrow) { 35 | if (!file_) 36 | return; 37 | 38 | int status = fclose(file_); 39 | file_ = nullptr; 40 | if (status != 0 && canThrow) 41 | ThrowFromErrno(); 42 | } 43 | 44 | void FileOutputStream::ThrowFromErrno() { 45 | assert(errno != 0); 46 | 47 | throw std::system_error(errno, std::generic_category(), path_); 48 | } 49 | -------------------------------------------------------------------------------- /src/Engine/Graphics/OpenGL/GLShaderLoader.cpp: -------------------------------------------------------------------------------- 1 | #include "GLShaderLoader.h" 2 | 3 | #include "Library/Serialization/EnumSerialization.h" 4 | 5 | namespace detail_extension { 6 | MM_DEFINE_ENUM_SERIALIZATION_FUNCTIONS(GLenum, CASE_SENSITIVE, { 7 | {GL_VERTEX_SHADER, "vert"}, 8 | {GL_FRAGMENT_SHADER, "frag"}, 9 | {GL_GEOMETRY_SHADER, "geom"}, 10 | {GL_COMPUTE_SHADER, "comp"}, 11 | {GL_TESS_CONTROL_SHADER, "tesc"}, 12 | {GL_TESS_EVALUATION_SHADER, "tese"} 13 | }) 14 | } // namespace detail_extension 15 | 16 | namespace detail_name { 17 | MM_DEFINE_ENUM_SERIALIZATION_FUNCTIONS(GLenum, CASE_SENSITIVE, { 18 | {GL_VERTEX_SHADER, "vertex"}, 19 | {GL_FRAGMENT_SHADER, "fragment"}, 20 | {GL_GEOMETRY_SHADER, "geometry"}, 21 | {GL_COMPUTE_SHADER, "compute"}, 22 | {GL_TESS_CONTROL_SHADER, "tessellation control"}, 23 | {GL_TESS_EVALUATION_SHADER, "tessellation evaluation"} 24 | }) 25 | } // namespace detail_name 26 | 27 | std::string GLShader::shaderTypeToExtension(GLenum type) { 28 | std::string result; 29 | detail_extension::serialize(type, &result); 30 | return result; 31 | } 32 | 33 | std::string GLShader::shaderTypeToName(GLenum type) { 34 | std::string result; 35 | detail_name::serialize(type, &result); 36 | return result; 37 | } 38 | -------------------------------------------------------------------------------- /src/GUI/UI/UICharacter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GUI/GUIWindow.h" 3 | 4 | class GUIWindow_CharacterRecord : public GUIWindow { 5 | public: 6 | GUIWindow_CharacterRecord(unsigned int uActiveCharacter, CURRENT_SCREEN screen); 7 | virtual ~GUIWindow_CharacterRecord() {} 8 | 9 | virtual void Update(); 10 | 11 | void ShowStatsTab(); 12 | void ShowSkillsTab(); 13 | void ShowInventoryTab(); 14 | void ShowAwardsTab(); 15 | void ToggleRingsOverlay(); 16 | 17 | protected: 18 | void CharacterUI_StatsTab_Draw(struct Player *); 19 | void CharacterUI_SkillsTab_Draw(struct Player *); 20 | void CharacterUI_AwardsTab_Draw(struct Player *); 21 | 22 | void CharacterUI_SkillsTab_CreateButtons(); 23 | }; 24 | 25 | bool ringscreenactive(); 26 | static void CharacterUI_DrawItem(int x, int y, ItemGen *item, int id, Texture *item_texture = nullptr, bool doZDraw = false); 27 | 28 | class Image; 29 | extern Image *ui_character_skills_background; 30 | extern Image *ui_character_awards_background; 31 | extern Image *ui_character_stats_background; 32 | extern Image *ui_character_inventory_background; 33 | extern Image *ui_character_inventory_background_strip; 34 | extern Image *ui_character_inventory_paperdoll_background; 35 | 36 | extern std::array paperdoll_dbrds; 37 | -------------------------------------------------------------------------------- /src/Utility/Streams/OutputStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /** 6 | * Abstract base class for all data output streams. 7 | * 8 | * Compared to `std::ostream` it is: 9 | * - Non-buffered. 10 | * - Uses exceptions for error handling. 11 | * - Has an extremely simple and intuitive interface consisting of exactly three methods. 12 | */ 13 | class OutputStream { 14 | public: 15 | virtual ~OutputStream() {} 16 | 17 | /** 18 | * Writes provided data into the output stream. 19 | * 20 | * @param data Pointer to the data to write. 21 | * @param size Data size. 22 | * @throws std::runtime_error On error. 23 | */ 24 | virtual void Write(const void *data, size_t size) = 0; 25 | 26 | /** 27 | * Flushes this output stream if it provides any kind of buffering. 28 | * 29 | * @throws std::runtime_error On error. 30 | */ 31 | virtual void Flush() = 0; 32 | 33 | /** 34 | * Closes this output stream. Writing into or flushing a closed stream will result in undefined behavior. 35 | * 36 | * Does nothing if the stream is already closed. 37 | * 38 | * @throws std::runtime_error On error. 39 | */ 40 | virtual void Close() = 0; 41 | }; 42 | -------------------------------------------------------------------------------- /src/Engine/IocContainer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct BloodsplatContainer; 6 | struct DecalBuilder; 7 | class LightmapBuilder; 8 | class Logger; 9 | namespace Io { 10 | class Mouse; 11 | } 12 | class Nuklear; 13 | class ParticleEngine; 14 | struct SpellFxRenderer; 15 | class Vis; 16 | 17 | namespace Engine_ { 18 | 19 | class IocContainer { 20 | public: 21 | static Logger *ResolveLogger(); 22 | static DecalBuilder *ResolveDecalBuilder(); 23 | static BloodsplatContainer *ResolveBloodsplatContainer(); 24 | static SpellFxRenderer *ResolveSpellFxRenderer(); 25 | static std::shared_ptr ResolveMouse(); 26 | static std::shared_ptr ResolveNuklear(); 27 | static std::shared_ptr ResolveParticleEngine(); 28 | static Vis *ResolveVis(); 29 | 30 | private: 31 | static DecalBuilder *decal_builder; 32 | static BloodsplatContainer *bloodspalt_container; 33 | static SpellFxRenderer *spell_fx_renderer; 34 | static LightmapBuilder *lightmap_builder; 35 | static std::shared_ptr mouse; 36 | static std::shared_ptr nuklear; 37 | static std::shared_ptr particle_engine; 38 | static Vis *vis; 39 | }; 40 | 41 | } // namespace Engine_ 42 | 43 | 44 | extern Logger *logger; 45 | -------------------------------------------------------------------------------- /src/Engine/ErrorHandling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | #define Warn(...) \ 7 | do { \ 8 | Error_impl_(__FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ 9 | } while (0) 10 | 11 | 12 | #define Error(...) \ 13 | do { \ 14 | Error_impl_(__FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \ 15 | assert(false); \ 16 | exit(0); \ 17 | } while (0) 18 | 19 | 20 | #define Assert(condition, ...) \ 21 | Assert_impl_(__FILE__, __FUNCTION__, __LINE__, condition, #condition __VA_OPT__(,) __VA_ARGS__) //NOLINT 22 | 23 | void Error_impl_(const char *filename, const char *functionname, 24 | int line, const char *format, ...); 25 | 26 | void Assert_impl_(const char *filename, const char *functionname, 27 | int line, bool condition, const char *condition_string = nullptr, 28 | const char *format = nullptr, ...); 29 | 30 | #ifndef _WINDOWS 31 | #define __debugbreak(...) assert(false); 32 | #endif 33 | 34 | -------------------------------------------------------------------------------- /resources/shaders/glforcepershader.frag: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | in vec4 colour; 4 | in vec4 texuv; 5 | in float screenspace; 6 | 7 | out vec4 FragColour; 8 | 9 | struct FogParam { 10 | vec3 color; 11 | float fogstart; 12 | float fogmiddle; 13 | float fogend; 14 | }; 15 | 16 | uniform sampler2D texture0; 17 | uniform FogParam fog; 18 | 19 | float getFogRatio(FogParam fogpar, float dist); 20 | 21 | void main() { 22 | vec4 fragcol = textureProj(texture0, texuv) * colour; 23 | 24 | // no fog early break 25 | if (fog.fogstart == fog.fogend) { 26 | FragColour = fragcol; 27 | return; 28 | } 29 | 30 | float fograt = getFogRatio(fog, screenspace); 31 | if (fragcol.a < 0.004) fograt = 0.0; 32 | //if (fragcol.r < 0.04 && fragcol.g < 0.04 && fragcol.b < 0.04) fograt = 0.0; 33 | 34 | float alpha = 0.0; 35 | // day fog 36 | if (fog.fogmiddle > fog.fogstart) alpha = 1.0; 37 | 38 | FragColour = mix(fragcol, vec4(fog.color, alpha), fograt); 39 | } 40 | 41 | float getFogRatio(FogParam fogpar, float dist) { 42 | 43 | float result = 0.0; 44 | if (fog.fogstart > fog.fogmiddle) { 45 | result = smoothstep(fogpar.fogstart, fogpar.fogend, dist); 46 | } else { 47 | result = 0.25 + smoothstep(fogpar.fogstart, fogpar.fogmiddle, dist) * 0.75; 48 | } 49 | return result; 50 | } 51 | -------------------------------------------------------------------------------- /src/Utility/Reversed.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace detail { 7 | template 8 | class ReversedRange { 9 | public: 10 | constexpr explicit ReversedRange(Range &&) = delete; // Constructing from rvalue will lead to dangling iterators. Need P2718R0 for this to work. 11 | constexpr explicit ReversedRange(Range &range) : _range(range) {} 12 | 13 | constexpr auto begin() const { 14 | using std::crbegin; 15 | return crbegin(_range); 16 | } 17 | 18 | constexpr auto end() const { 19 | using std::crend; 20 | return crend(_range); 21 | } 22 | 23 | constexpr auto begin() { 24 | using std::rbegin; 25 | return rbegin(_range); 26 | } 27 | 28 | constexpr auto end() { 29 | using std::rend; 30 | return rend(_range); 31 | } 32 | 33 | private: 34 | Range &_range; 35 | }; 36 | } // namespace detail 37 | 38 | /** 39 | * Provides a reversed view into a range. Can be handy in a range-based for loop. 40 | * 41 | * @param range Range to get a reversed view into. Must not be an rvalue. 42 | * @return Reversed view. 43 | */ 44 | template 45 | constexpr auto Reversed(Range&& range) { 46 | return detail::ReversedRange(std::forward(range)); 47 | } 48 | -------------------------------------------------------------------------------- /src/Engine/Graphics/PortalFunctions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Utility/Geometry/Vec.h" 4 | 5 | /* 127 */ 6 | #pragma pack(push, 1) 7 | struct stru10 { 8 | stru10(); 9 | virtual ~stru10(); 10 | bool CalcPortalShapePoly(struct BLVFace *pFace, struct RenderVertexSoft *pVertices, 11 | unsigned int *pNumVertices, struct IndoorCameraD3D_Vec4 *a5, 12 | struct RenderVertexSoft *pOutBounding); 13 | bool CalcPortalFrustum(struct RenderVertexSoft *pFaceBounding, struct IndoorCameraD3D_Vec4 *pPortalDataFrustum); 14 | bool CalcPortalFrustumPlane(struct RenderVertexSoft *pFaceBounding1, 15 | struct RenderVertexSoft *pFaceBounding2, 16 | Vec3f *pRayStart, 17 | struct IndoorCameraD3D_Vec4 *pPortalDataFrustum); 18 | bool CalcFaceBounding(struct BLVFace *pFace, 19 | struct RenderVertexSoft *pFaceLimits, 20 | unsigned int uNumVertices, 21 | struct RenderVertexSoft *pOutBounding); 22 | void CalcPolygonLimits(struct BLVFace *pFace, 23 | struct RenderVertexSoft pOutVertices[4]); 24 | void _49CE9E(struct BLVFace *pFace, struct RenderVertexSoft *pVertices, 25 | unsigned int uNumVertices, RenderVertexSoft *pOutLimits); 26 | }; 27 | #pragma pack(pop) 28 | -------------------------------------------------------------------------------- /src/Engine/Plugins/EngineTracePlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "EngineTracePlugin.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Library/Application/PlatformApplication.h" 8 | #include "Library/Random/Random.h" 9 | #include "Library/Trace/PaintEvent.h" 10 | 11 | EngineTracePlugin::EngineTracePlugin(): PlatformEventFilter(EVENTS_ALL) {} 12 | EngineTracePlugin::~EngineTracePlugin() = default; 13 | 14 | void EngineTracePlugin::start() { 15 | assert(!_tracing); 16 | _tracing = true; 17 | } 18 | 19 | EventTrace EngineTracePlugin::finish() { 20 | assert(_tracing); 21 | _tracing = false; 22 | return std::move(_trace); 23 | } 24 | 25 | void EngineTracePlugin::swapBuffers() { 26 | if (_tracing) { 27 | std::unique_ptr e = std::make_unique(); 28 | e->type = EVENT_PAINT; 29 | e->tickCount = application()->platform()->tickCount(); 30 | e->randomState = grng->Random(1024); 31 | _trace.events.push_back(std::move(e)); 32 | } 33 | 34 | // Tail calling is good practice - this way users can reason about the order of proxy execution. 35 | ProxyOpenGLContext::swapBuffers(); 36 | } 37 | 38 | bool EngineTracePlugin::event(const PlatformEvent *event) { 39 | if (_tracing && EventTrace::isTraceable(event)) 40 | _trace.events.push_back(EventTrace::cloneEvent(event)); 41 | return false; 42 | } 43 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlPlatform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Platform/Platform.h" 8 | 9 | class SdlWindow; 10 | class SdlGamepad; 11 | class SdlPlatformSharedState; 12 | 13 | class SdlPlatform: public Platform { 14 | public: 15 | explicit SdlPlatform(PlatformLogger *logger); 16 | virtual ~SdlPlatform(); 17 | 18 | virtual std::unique_ptr createWindow() override; 19 | virtual std::unique_ptr createEventLoop() override; 20 | virtual std::unique_ptr createGamepad(uint32_t id) override; 21 | 22 | virtual void setCursorShown(bool cursorShown) override; 23 | virtual bool isCursorShown() const override; 24 | 25 | virtual std::vector displayGeometries() const override; 26 | 27 | virtual void showMessageBox(const std::string& title, const std::string &message) const override; 28 | 29 | virtual int64_t tickCount() const override; 30 | 31 | virtual std::string winQueryRegistry(const std::wstring &path) const override; 32 | 33 | virtual std::string storagePath(const PlatformStorage type) const override; 34 | 35 | private: 36 | friend class SdlWindow; 37 | friend class SdlEventLoop; 38 | friend class SdlGamepad; 39 | 40 | private: 41 | bool _initialized = false; 42 | std::unique_ptr _state; 43 | }; 44 | -------------------------------------------------------------------------------- /src/Engine/Graphics/Level/Decoration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Utility/Geometry/Vec.h" 8 | #include "Utility/Flags.h" 9 | 10 | enum class LevelDecorationFlag : uint16_t { 11 | LEVEL_DECORATION_TRIGGERED_BY_TOUCH = 0x01, 12 | LEVEL_DECORATION_TRIGGERED_BY_MONSTER = 0x02, 13 | LEVEL_DECORATION_TRIGGERED_BY_OBJECT = 0x04, 14 | LEVEL_DECORATION_VISIBLE_ON_MAP = 0x08, 15 | LEVEL_DECORATION_CHEST = 0x10, 16 | LEVEL_DECORATION_INVISIBLE = 0x20, 17 | LEVEL_DECORATION_OBELISK_CHEST = 0x40, 18 | }; 19 | using enum LevelDecorationFlag; 20 | MM_DECLARE_FLAGS(LevelDecorationFlags, LevelDecorationFlag) 21 | MM_DECLARE_OPERATORS_FOR_FLAGS(LevelDecorationFlags) 22 | 23 | 24 | /* 74 */ 25 | #pragma pack(push, 1) 26 | struct LevelDecoration { 27 | LevelDecoration(); 28 | int GetGlobalEvent(); 29 | bool IsInteractive(); 30 | bool IsObeliskChestActive(); 31 | 32 | uint16_t uDecorationDescID; 33 | LevelDecorationFlags uFlags; 34 | Vec3i vPosition; 35 | int32_t field_10_y_rot; 36 | uint16_t uCog; 37 | uint16_t uEventID; 38 | uint16_t uTriggerRange; 39 | int16_t field_1A; 40 | int16_t _idx_in_stru123; 41 | int16_t field_1E; 42 | }; 43 | 44 | extern std::vector pLevelDecorations; 45 | extern LevelDecoration* activeLevelDecoration; // 5C3420 46 | #pragma pack(pop) 47 | -------------------------------------------------------------------------------- /src/Utility/Math/TrigLut.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /** 6 | * Lookup table for trigonometric functions. 7 | */ 8 | class TrigTableLookup { 9 | public: 10 | static const int uIntegerPi = 1024; 11 | static const int uIntegerHalfPi = 512; 12 | static const int uIntegerDoublePi = 2048; 13 | static const int uDoublePiMask = 2047; 14 | static const int uPiMask = 1023; 15 | static const int uHalfPiMask = 511; 16 | 17 | /** 18 | * @offset 0x00452969 19 | */ 20 | TrigTableLookup(); 21 | 22 | /** 23 | * @offset 0x00402CAE 24 | * 25 | * @param angle Angle in 1/2048ths of a full circle. 26 | * @return Cosine of the provided angle. 27 | */ 28 | float Cos(int angle) const; 29 | 30 | /** 31 | * @offset 0x0042EBDB 32 | * 33 | * @param angle Angle in 1/2048ths of a full circle. 34 | * @return Sine of the provided angle. 35 | */ 36 | float Sin(int angle) const; 37 | 38 | /** 39 | * @offset 0x0045281E 40 | * 41 | * @return Angle in 1/2048ths of a full circle. Actual result is in range [0, 2047]. 42 | */ 43 | int Atan2(int x, int y) const; 44 | 45 | private: 46 | std::array pCosTable; 47 | }; 48 | 49 | extern TrigTableLookup TrigLUT; 50 | -------------------------------------------------------------------------------- /test/Bin/GameTest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.4 FATAL_ERROR) 2 | 3 | if(ENABLE_TESTS) 4 | set(GAME_TEST_MAIN_SOURCES GameTestMain.cpp 5 | GameTestOptions.cpp) 6 | set(GAME_TEST_MAIN_HEADERS GameTestOptions.h) 7 | 8 | add_executable(OpenEnroth_GameTest ${GAME_TEST_MAIN_SOURCES} ${GAME_TEST_MAIN_HEADERS}) 9 | target_fix_libcxx_assertions(OpenEnroth_GameTest) 10 | target_link_libraries(OpenEnroth_GameTest game game_test GTest::gtest) 11 | target_compile_definitions(OpenEnroth_GameTest PRIVATE TEST_GROUP=None) 12 | 13 | target_check_style(OpenEnroth_GameTest) 14 | PREBUILT_DEPENDENCIES_RESOLVE(OpenEnroth_GameTest) 15 | 16 | 17 | # OpenEnroth_TestData 18 | ExternalProject_Add(OpenEnroth_TestData 19 | PREFIX ${CMAKE_CURRENT_BINARY_DIR}/test_data_tmp 20 | GIT_REPOSITORY https://github.com/OpenEnroth/OpenEnroth_TestData.git 21 | GIT_TAG 1433fce638059fb1e1f616a8c56cfd5bc35d6b63 22 | SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/test_data 23 | CONFIGURE_COMMAND "" 24 | BUILD_COMMAND "" 25 | INSTALL_COMMAND "" 26 | ) 27 | 28 | 29 | # GameTest 30 | add_custom_target(GameTest 31 | OpenEnroth_GameTest --test-data ${CMAKE_CURRENT_BINARY_DIR}/test_data/data 32 | DEPENDS OpenEnroth_GameTest OpenEnroth_TestData 33 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 34 | ) 35 | endif() 36 | -------------------------------------------------------------------------------- /src/Engine/AssetsManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Utility/Color.h" 7 | 8 | class Image; 9 | class Texture; 10 | 11 | class AssetsManager { 12 | public: 13 | AssetsManager() {} 14 | 15 | void ReleaseAllTextures(); 16 | 17 | bool ReleaseAllImages(); 18 | bool ReleaseAllSprites(); 19 | 20 | bool ReleaseImage(const std::string &name); 21 | bool ReleaseSprite(const std::string& name); 22 | 23 | Texture *GetImage_ColorKey(const std::string &name, uint16_t colorkey = colorTable.TealMask.C16()); 24 | Texture *GetImage_Paletted(const std::string &name); 25 | Texture *GetImage_Solid(const std::string &name); 26 | Texture *GetImage_Alpha(const std::string &name); 27 | 28 | Texture *GetImage_PCXFromFile(const std::string &name); 29 | Texture *GetImage_PCXFromIconsLOD(const std::string &name); 30 | Texture *GetImage_PCXFromNewLOD(const std::string &name); 31 | 32 | Texture *GetBitmap(const std::string &name); 33 | Texture *GetSprite(const std::string &name, unsigned int palette_id, 34 | unsigned int lod_sprite_id); 35 | 36 | // TODO(pskelton): Contain better 37 | Texture* WinnerCert{ nullptr }; 38 | 39 | protected: 40 | std::map bitmaps; 41 | std::map sprites; 42 | std::map images; 43 | }; 44 | 45 | extern AssetsManager *assets; 46 | -------------------------------------------------------------------------------- /src/Library/Serialization/Serialization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "SerializationFwd.h" 7 | #include "StandardSerialization.h" 8 | 9 | namespace detail { 10 | 11 | struct StringSerializer { 12 | template 13 | std::string operator()(const T &value) const { 14 | std::string result; 15 | serialize(value, &result); 16 | return result; 17 | } 18 | }; 19 | 20 | template 21 | struct StringDeserializer { 22 | T operator()(std::string_view string) const { 23 | T result; 24 | deserialize(string, &result); 25 | return result; 26 | } 27 | }; 28 | 29 | } // namespace detail 30 | 31 | /** 32 | * Ranges-friendly serialization object. 33 | * 34 | * Can be used as `range | std::views::transform(ToString)`. Or directly, as `return ToString(some_integer);`. 35 | * 36 | * Under the hood it's just calling the `serialize` function using argument-dependent lookup. 37 | */ 38 | constexpr detail::StringSerializer toString; 39 | 40 | /** 41 | * Ranges-friendly deserialization object. 42 | * 43 | * Can be used as `range | std::views::transform(FromString)`. Or directly, as `return FromString(some_string)`. 44 | * 45 | * Under the hood it's just calling the `deserialize` function using argument-dependent lookup. 46 | * 47 | * @see toString 48 | */ 49 | template 50 | constexpr detail::StringDeserializer fromString; 51 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | 3 | on: 4 | pull_request: 5 | push: 6 | release: 7 | types: [published] 8 | 9 | jobs: 10 | build_windows: 11 | runs-on: windows-2022 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | configuration: [Debug, Release] 16 | architecture: [x86, x64] 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v3 20 | with: 21 | submodules: 'recursive' 22 | 23 | - name: Setup environment 24 | uses: ilammy/msvc-dev-cmd@v1 25 | with: 26 | arch: ${{ matrix.architecture }} 27 | 28 | - name: Configure 29 | run: | 30 | cmake -B build -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.configuration }} -DENABLE_TESTS=On 31 | 32 | - name: Build 33 | working-directory: build 34 | shell: cmd 35 | run: | 36 | nmake 37 | 38 | - name: Tests 39 | working-directory: build 40 | run: | 41 | nmake UnitTest 42 | 43 | - name: Prepare artifact 44 | shell: cmd 45 | run: | 46 | mkdir dist 47 | copy build\OpenEnroth.exe dist\ /Y 48 | copy build\*.dll dist\ /Y 49 | xcopy resources dist\ /E/H/C/I 50 | 51 | - name: Upload artifact 52 | uses: actions/upload-artifact@v3 53 | with: 54 | name: OpenEnroth (Windows, ${{ matrix.configuration }}, ${{ matrix.architecture }}) 55 | path: | 56 | dist/** 57 | -------------------------------------------------------------------------------- /thirdparty/luajit/cmake/cmake/modules/DetectArchitecture.c: -------------------------------------------------------------------------------- 1 | #if defined(__aarch64__) || defined(__arm64__) 2 | const char *str = "ARCHITECTURE IS AArch64"; 3 | #elif defined(__arm__) || defined(__arm) || defined(__ARM__) || defined(__ARM) 4 | const char *str = "ARCHITECTURE IS ARM"; 5 | #elif defined(__alpha__) 6 | const char *str = "ARCHITECTURE IS Alpha"; 7 | #elif defined(__mips64__) || defined(__mips64) || defined(__MIPS64__) || defined(__MIPS64) 8 | const char *str = "ARCHITECTURE IS Mips64"; 9 | #elif defined(__mips__) || defined(__mips) || defined(__MIPS__) || defined(__MIPS) 10 | const char *str = "ARCHITECTURE IS Mips"; 11 | #elif defined(__ppc__) || defined(__ppc) || defined(__PPC__) || defined(__PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__POWERPC) || defined(_M_PPC) 12 | const char *str = "ARCHITECTURE IS PowerPC"; 13 | #elif defined(__s390__) 14 | const char *str = "ARCHITECTURE IS SystemZ"; 15 | #elif defined(__sparc__) 16 | const char *str = "ARCHITECTURE IS Sparc"; 17 | #elif defined(__xcore__) 18 | const char *str = "ARCHITECTURE IS XCore"; 19 | #elif defined(__i386__) || defined(__i686__) || defined(_M_IX86) 20 | const char *str = "ARCHITECTURE IS x86"; 21 | #elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) 22 | const char *str = "ARCHITECTURE IS x86_64"; 23 | #endif 24 | 25 | int main(int argc, char **argv) { 26 | int require = str[argc]; 27 | (void)argv; 28 | return require; 29 | } 30 | -------------------------------------------------------------------------------- /src/Engine/Graphics/IRenderFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "Engine/Graphics/IRenderFactory.h" 2 | 3 | #include "Engine/IocContainer.h" 4 | #include "Engine/Graphics/OpenGL/RenderOpenGL.h" 5 | 6 | using EngineIoc = Engine_::IocContainer; 7 | using Graphics::IRenderFactory; 8 | 9 | std::shared_ptr IRenderFactory::Create(std::shared_ptr config) { 10 | RendererType rendererType = config->graphics.Renderer.Get(); 11 | 12 | switch (rendererType) { 13 | case RendererType::OpenGL: 14 | logger->Info("Initializing OpenGL renderer..."); 15 | return std::make_shared( 16 | config, 17 | EngineIoc::ResolveDecalBuilder(), 18 | EngineIoc::ResolveSpellFxRenderer(), 19 | EngineIoc::ResolveParticleEngine(), 20 | EngineIoc::ResolveVis(), 21 | EngineIoc::ResolveLogger() 22 | ); 23 | 24 | case RendererType::OpenGLES: 25 | logger->Info("Initializing OpenGL ES renderer..."); 26 | return std::make_shared( 27 | config, 28 | EngineIoc::ResolveDecalBuilder(), 29 | EngineIoc::ResolveSpellFxRenderer(), 30 | EngineIoc::ResolveParticleEngine(), 31 | EngineIoc::ResolveVis(), 32 | EngineIoc::ResolveLogger() 33 | ); 34 | 35 | default: 36 | return nullptr; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: MacOS 2 | 3 | on: 4 | pull_request: 5 | push: 6 | release: 7 | types: [published] 8 | 9 | jobs: 10 | build_macos: 11 | runs-on: macos-12 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | configuration: [Debug, Release] 16 | architecture: [x64] 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v3 20 | with: 21 | submodules: 'recursive' 22 | 23 | - name: Install dependencies 24 | run: | 25 | brew install ffmpeg@4 26 | brew install sdl2 27 | 28 | - name: Configure 29 | run: | 30 | cmake -B build -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=${{ matrix.configuration }} -DENABLE_TESTS=On -DCMAKE_PREFIX_PATH="/usr/local/opt/ffmpeg@4" 31 | 32 | - name: Build 33 | working-directory: build 34 | run: | 35 | make -j$(sysctl -n hw.logicalcpu) 36 | 37 | - name: Tests 38 | working-directory: build 39 | run: | 40 | make UnitTest 41 | 42 | - name: Prepare artifact 43 | run: | 44 | mkdir dist 45 | cp -r build/OpenEnroth.app dist/ 46 | cp -r resources/* dist/ 47 | hdiutil create OpenEnroth.dmg -ov -volname "OpenEnroth" -fs HFS+ -srcfolder dist 48 | 49 | - name: Upload artifact 50 | uses: actions/upload-artifact@v3 51 | with: 52 | name: OpenEnroth (MacOS, ${{ matrix.configuration }}, ${{ matrix.architecture }}) 53 | path: OpenEnroth.dmg 54 | -------------------------------------------------------------------------------- /src/Engine/Graphics/Nuklear.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "GUI/GUIWindow.h" 6 | #include "Platform/PlatformEnums.h" 7 | 8 | #include 9 | #include "nuklear/nuklear_config.h" 10 | 11 | #define NUKLEAR_MAX_VERTEX_MEMORY 512 * 1024 12 | #define NUKLEAR_MAX_ELEMENT_MEMORY 128 * 1024 13 | 14 | class Nuklear { 15 | public: 16 | enum NUKLEAR_MODE: int32_t { 17 | NUKLEAR_MODE_SHARED = 1, 18 | NUKLEAR_MODE_EXCLUSIVE 19 | }; 20 | 21 | enum NUKLEAR_ACTION: int32_t { 22 | NUKLEAR_ACTION_CREATE = 1, 23 | NUKLEAR_ACTION_DRAW, 24 | NUKLEAR_ACTION_RELEASE 25 | }; 26 | 27 | enum NUKLEAR_STAGE: int32_t { 28 | NUKLEAR_STAGE_PRE = 1, 29 | NUKLEAR_STAGE_POST 30 | }; 31 | 32 | Nuklear(); 33 | 34 | static std::shared_ptr Initialize(); 35 | bool Create(enum WindowType winType); 36 | bool Draw(enum NUKLEAR_STAGE stage, enum WindowType winType, int type); 37 | int KeyEvent(PlatformKey key); 38 | bool Reload(); 39 | void Release(enum WindowType winType); 40 | void Destroy(); 41 | enum NUKLEAR_MODE Mode(enum WindowType winType); 42 | 43 | struct nk_context *ctx = nullptr; 44 | 45 | private: 46 | void Release(WindowType winType, bool reload); 47 | bool LuaInit(); 48 | void LuaRelease(); 49 | bool LuaLoadTemplate(enum WindowType winType); 50 | 51 | protected: 52 | }; 53 | 54 | extern std::shared_ptr nuklear; 55 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # General TODO list 2 | 3 | * Move all water anim to `TextureFrameTable` to avoid many duplication of water animation handling code. 4 | 5 | * Implement Quicksave / Quickload. 6 | 7 | * Add short term / long term project goals - expand milestones. 8 | 9 | * Are spiders not masking skull texture? 10 | 11 | * Rename unidentifed variables. 12 | * Remove all platform-dependant functions. 13 | 14 | * Is spirit resistance a thing or not? 15 | 16 | * Additional features: 17 | - Harden party logic so that team size can be varied. 18 | - Map editor? i think there was a semi complete example somewhere. 19 | - Fog should reduce ability of party to autoaim 20 | - 'Of light' items which add glow around party 21 | 22 | * QoL improvements: 23 | - global merchant / identify skills? 24 | 25 | * Possible graphics improvements: 26 | - keep track of light source intensity and add subtle flicker effect. proof of concept Engine/Graphics/Indoor.cpp line 115. 27 | 28 | * Optimization targets: 29 | - Currently engine fps is typically CPU bound - Any scope/need for threading? 30 | 31 | * Minor Projects: 32 | - Remove zdrawtexturealpha 33 | - Reduce logger spam 34 | - OpenGL shader structs - member types and padding 35 | 36 | * Major Projects: 37 | - New GUI/ window system 38 | - New sounds system 39 | - New (.WMM)?? save format with extended capabilites?? 40 | - Check OpenEnroth features all fixes of GrayFace patches 41 | - Add all GrayFace patch enchancements to OpenEnroth 42 | - Lua scripting 43 | - Debug logger improvements -------------------------------------------------------------------------------- /src/Library/Logger/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Logger.h" 5 | 6 | PlatformLogger *Logger::BaseLogger() const { 7 | return baseLogger_; 8 | } 9 | 10 | void Logger::SetBaseLogger(PlatformLogger *baseLogger) { 11 | baseLogger_ = baseLogger; 12 | } 13 | 14 | void Logger::Log(PlatformLogLevel logLevel, const char *format, ...) { 15 | if (baseLogger_ && baseLogger_->logLevel(APPLICATION_LOG) > logLevel) 16 | return; 17 | 18 | va_list args; 19 | va_start(args, format); 20 | LogV(logLevel, format, args); 21 | va_end(args); 22 | } 23 | 24 | void Logger::Info(const char *pFormat, ...) { 25 | if (baseLogger_ && baseLogger_->logLevel(APPLICATION_LOG) > LOG_INFO) 26 | return; 27 | 28 | va_list args; 29 | va_start(args, pFormat); 30 | LogV(LOG_INFO, pFormat, args); 31 | va_end(args); 32 | } 33 | 34 | void Logger::Warning(const char *pFormat, ...) { 35 | if (baseLogger_ && baseLogger_->logLevel(APPLICATION_LOG) > LOG_WARNING) 36 | return; 37 | 38 | va_list args; 39 | va_start(args, pFormat); 40 | LogV(LOG_WARNING, pFormat, args); 41 | va_end(args); 42 | } 43 | 44 | void Logger::LogV(PlatformLogLevel logLevel, const char *pFormat, va_list args) { 45 | char message[8192]; 46 | vsnprintf(message, 8192, pFormat, args); 47 | 48 | if (baseLogger_) { 49 | baseLogger_->log(APPLICATION_LOG, logLevel, message); 50 | } else { 51 | fprintf(stderr, "UNINITIALIZED LOGGER: %s\n", message); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /CMakeModules/Detection.cmake: -------------------------------------------------------------------------------- 1 | set(BUILD_COMPILER "unknown") 2 | set(BUILD_PLATFORM "unknown") 3 | set(BUILD_TYPE "unknown") 4 | 5 | if(WIN32) 6 | set(BUILD_PLATFORM "windows") 7 | elseif(MINGW) 8 | set(BUILD_PLATFORM "mingw") 9 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 10 | set(BUILD_PLATFORM "darwin") 11 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") 12 | set(BUILD_PLATFORM "linux") 13 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") 14 | set(BUILD_PLATFORM "android") 15 | elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") 16 | set(BUILD_PLATFORM "freebsd") 17 | elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") 18 | set(BUILD_PLATFORM "openbsd") 19 | elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") 20 | set(BUILD_PLATFORM "netbsd") 21 | elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS") 22 | set(BUILD_PLATFORM "ios") 23 | endif() 24 | 25 | # TODO: We should replace this with proper architecture detection like DetectArchitecture in luajit 26 | if (CMAKE_SIZEOF_VOID_P MATCHES 8) 27 | set(BUILD_TYPE "x64") 28 | elseif (CMAKE_SIZEOF_VOID_P MATCHES 4) 29 | set(BUILD_TYPE "x86") 30 | endif () 31 | 32 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 33 | set(BUILD_COMPILER "gcc") 34 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 35 | set(BUILD_COMPILER "clang") 36 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 37 | set(BUILD_COMPILER "msvc") 38 | endif() 39 | 40 | message(STATUS "Build compiler: ${BUILD_COMPILER}") 41 | message(STATUS "Build platform: ${BUILD_PLATFORM}") 42 | message(STATUS "Build type: ${BUILD_TYPE}") 43 | -------------------------------------------------------------------------------- /src/Platform/Filters/PlatformEventFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Platform/PlatformEvents.h" 6 | 7 | enum class PlatformEventWildcard { 8 | EVENTS_ALL 9 | }; 10 | using enum PlatformEventWildcard; 11 | 12 | class PlatformEventFilter { 13 | public: 14 | explicit PlatformEventFilter(std::initializer_list eventTypes); 15 | explicit PlatformEventFilter(PlatformEventWildcard eventTypes); 16 | 17 | virtual bool event(const PlatformEvent *event); 18 | 19 | const std::vector eventTypes() const { 20 | return _eventTypes; 21 | } 22 | 23 | protected: 24 | virtual bool keyPressEvent(const PlatformKeyEvent *event); 25 | virtual bool keyReleaseEvent(const PlatformKeyEvent *event); 26 | virtual bool mouseMoveEvent(const PlatformMouseEvent *event); 27 | virtual bool mousePressEvent(const PlatformMouseEvent *event); 28 | virtual bool mouseReleaseEvent(const PlatformMouseEvent *event); 29 | virtual bool wheelEvent(const PlatformWheelEvent *event); 30 | virtual bool moveEvent(const PlatformMoveEvent *event); 31 | virtual bool resizeEvent(const PlatformResizeEvent *event); 32 | virtual bool activationEvent(const PlatformWindowEvent *event); 33 | virtual bool closeEvent(const PlatformWindowEvent *event); 34 | virtual bool gamepadDeviceEvent(const PlatformGamepadDeviceEvent *event); 35 | virtual bool nativeEvent(const PlatformNativeEvent *event); 36 | 37 | private: 38 | std::vector _eventTypes; 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /src/GUI/UI/UIBooks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "GUI/GUIWindow.h" 6 | 7 | class GUIWindow_Book : public GUIWindow { 8 | public: 9 | GUIWindow_Book(); 10 | virtual ~GUIWindow_Book() {} 11 | 12 | virtual void Release(); 13 | 14 | protected: 15 | void BasicBookInitialization(); 16 | GUIWindow *pChildBooksOverlay{ nullptr }; 17 | 18 | private: 19 | void InitializeFonts(); 20 | }; 21 | 22 | 23 | class GUIWindow_BooksButtonOverlay : public GUIWindow { 24 | public: 25 | GUIWindow_BooksButtonOverlay(Pointi position, Sizei dimensions, GUIButton *button, const std::string &hint = std::string()) : 26 | GUIWindow(WINDOW_BooksButtonOverlay, position, dimensions, button, hint) 27 | {} 28 | virtual ~GUIWindow_BooksButtonOverlay() {} 29 | 30 | virtual void Update(); 31 | }; 32 | 33 | class Image; 34 | extern Image *ui_book_button8_off; 35 | extern Image *ui_book_button8_on; 36 | extern Image *ui_book_button7_off; 37 | extern Image *ui_book_button7_on; 38 | extern Image *ui_book_button6_off; 39 | extern Image *ui_book_button6_on; 40 | extern Image *ui_book_button5_off; 41 | extern Image *ui_book_button5_on; 42 | extern Image *ui_book_button4_off; 43 | extern Image *ui_book_button4_on; 44 | extern Image *ui_book_button3_off; 45 | extern Image *ui_book_button3_on; 46 | extern Image *ui_book_button2_off; 47 | extern Image *ui_book_button2_on; 48 | extern Image *ui_book_button1_off; 49 | extern Image *ui_book_button1_on; 50 | 51 | extern Image *ui_book_map_frame; 52 | extern Image *ui_book_quest_div_bar; 53 | -------------------------------------------------------------------------------- /thirdparty/luajit/cmake/src/host/cmake/buildvm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(buildvm) 4 | 5 | set(EXTRA_COMPILER_FLAGS_FILE "" CACHE PATH "Location of a file to specify extra compiler flags." ) 6 | set(EXTRA_COMPILER_FLAGS "") 7 | if (EXISTS ${EXTRA_COMPILER_FLAGS_FILE}) 8 | file(READ ${EXTRA_COMPILER_FLAGS_FILE} EXTRA_COMPILER_FLAGS) 9 | else() 10 | set(EXTRA_COMPILER_FLAGS ${BUILDVM_COMPILER_FLAGS}) 11 | endif() 12 | 13 | include(CheckTypeSize) 14 | if ("${EXTRA_COMPILER_FLAGS}" MATCHES "LUAJIT_ARCH_.*64") 15 | set(TARGET_SIZE_OF_P 8) 16 | else() 17 | set(TARGET_SIZE_OF_P 4) 18 | endif() 19 | 20 | set(CXX_ARCH_FLAGS "") 21 | if (NOT (CMAKE_SIZEOF_VOID_P EQUAL ${TARGET_SIZE_OF_P})) 22 | if (CMAKE_SIZEOF_VOID_P EQUAL 8) 23 | set(CXX_ARCH_FLAGS "-m32") 24 | else() 25 | set(CXX_ARCH_FLAGS "-m64") 26 | endif() 27 | endif() 28 | 29 | find_library(LIBM_LIBRARIES NAMES m) 30 | 31 | add_executable(buildvm 32 | ../../buildvm.c 33 | ../../buildvm_asm.c 34 | ../../buildvm_fold.c 35 | ../../buildvm_lib.c 36 | ../../buildvm_peobj.c) 37 | 38 | target_compile_options(buildvm PRIVATE 39 | ${EXTRA_COMPILER_FLAGS} ${CXX_ARCH_FLAGS}) 40 | target_link_libraries(buildvm PRIVATE ${CXX_ARCH_FLAGS}) 41 | if (LIBM) 42 | target_link_libraries(buildvm PRIVATE ${LIBM_LIBRARIES}) 43 | endif() 44 | 45 | target_include_directories(buildvm PRIVATE 46 | ${CMAKE_CURRENT_BINARY_DIR}/../../../ 47 | ${CMAKE_CURRENT_BINARY_DIR}/../ 48 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../ 49 | ${CMAKE_CURRENT_SOURCE_DIR}/../..) 50 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Platform/PlatformWindow.h" 7 | 8 | #include "ProxyBase.h" 9 | 10 | class ProxyWindow : public ProxyBase { 11 | public: 12 | explicit ProxyWindow(PlatformWindow *base = nullptr); 13 | virtual ~ProxyWindow() = default; 14 | 15 | virtual void setTitle(const std::string &title) override; 16 | virtual std::string title() const override; 17 | virtual void resize(const Sizei &size) override; 18 | virtual Sizei size() const override; 19 | virtual void setPosition(const Pointi &pos) override; 20 | virtual Pointi position() const override; 21 | virtual void setVisible(bool visible) override; 22 | virtual bool isVisible() const override; 23 | virtual void setResizable(bool resizable) override; 24 | virtual bool isResizable() const override; 25 | virtual void setWindowMode(PlatformWindowMode mode) override; 26 | virtual PlatformWindowMode windowMode() override; 27 | virtual void setGrabsMouse(bool grabsMouse) override; 28 | virtual bool grabsMouse() const override; 29 | virtual void setOrientations(PlatformWindowOrientations orientations) override; 30 | virtual PlatformWindowOrientations orientations() override; 31 | virtual Marginsi frameMargins() const override; 32 | virtual uintptr_t systemHandle() const override; 33 | virtual void activate() override; 34 | virtual std::unique_ptr createOpenGLContext(const PlatformOpenGLOptions &options) override; 35 | }; 36 | -------------------------------------------------------------------------------- /src/Engine/Tables/FactionTable.cpp: -------------------------------------------------------------------------------- 1 | #include "Engine/Tables/FactionTable.h" 2 | 3 | #include "Engine/Engine.h" 4 | 5 | #include "../LOD.h" 6 | 7 | //----- (004547E4) -------------------------------------------------------- 8 | void FactionTable::Initialize() { 9 | int i; 10 | char* test_string; 11 | unsigned char c; 12 | bool break_loop; 13 | unsigned int temp_str_len; 14 | char* tmp_pos; 15 | int decode_step; 16 | // int item_counter; 17 | 18 | pHostileTXT_Raw = pEvents_LOD->LoadCompressedTexture("hostile.txt").string_view(); 19 | strtok(pHostileTXT_Raw.data(), "\r"); 20 | for (i = 0; i < 89; ++i) { 21 | test_string = strtok(NULL, "\r") + 1; 22 | break_loop = false; 23 | decode_step = 0; 24 | do { 25 | c = *(unsigned char*)test_string; 26 | temp_str_len = 0; 27 | while ((c != '\t') && (c > 0)) { 28 | ++temp_str_len; 29 | c = test_string[temp_str_len]; 30 | } 31 | tmp_pos = test_string + temp_str_len; 32 | if (*tmp_pos == 0) break_loop = true; 33 | *tmp_pos = 0; 34 | if (temp_str_len) { 35 | if (decode_step >= 1 && decode_step < 90) 36 | relations[decode_step - 1][i] = atoi(test_string); 37 | } else { 38 | break_loop = true; 39 | } 40 | ++decode_step; 41 | test_string = tmp_pos + 1; 42 | } while ((decode_step < 92) && !break_loop); 43 | } 44 | pHostileTXT_Raw.clear(); 45 | } 46 | -------------------------------------------------------------------------------- /src/Library/Lod/Internal/LodFileHeader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include // memset 5 | #include 6 | 7 | 8 | #pragma pack(push, 1) 9 | struct LodFileHeader_Mm6 { 10 | inline LodFileHeader_Mm6() { 11 | memset(this, 0, sizeof(this)); 12 | } 13 | 14 | std::array name; 15 | std::uint32_t dataOffset; 16 | std::uint32_t size; 17 | std::uint32_t dword_000018; 18 | std::uint16_t numItems; 19 | std::uint16_t priority; 20 | }; 21 | #pragma pack(pop) 22 | 23 | 24 | #pragma pack(push, 1) 25 | struct LodFileHeader_Mm8 { 26 | inline LodFileHeader_Mm8() { 27 | memset(this, 0, sizeof(this)); 28 | } 29 | 30 | std::array name; 31 | std::int32_t unk_0; 32 | std::int32_t unk_1; 33 | std::int32_t unk_2; 34 | std::int32_t unk_3; 35 | std::int32_t unk_4; 36 | std::int32_t unk_5; 37 | std::int32_t unk_6; 38 | std::int32_t unk_7; 39 | std::int32_t unk_8; 40 | std::int32_t unk_9; 41 | std::int32_t unk_10; 42 | std::int32_t unk_11; 43 | std::int32_t dataOffset; 44 | std::int32_t dataSize; 45 | std::int32_t unk_14; 46 | }; 47 | #pragma pack(pop) 48 | 49 | 50 | #pragma pack(push, 1) 51 | struct LodFileCompressionHeader_Mm6 { 52 | inline LodFileCompressionHeader_Mm6() { 53 | memset(this, 0, sizeof(this)); 54 | } 55 | 56 | std::uint32_t version; 57 | std::array signature; 58 | std::uint32_t compressedSize; 59 | std::uint32_t decompressedSize; 60 | }; 61 | #pragma pack(pop) 62 | -------------------------------------------------------------------------------- /src/Platform/Sdl/SdlPlatformSharedState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class SdlWindow; 9 | class SdlPlatform; 10 | class SdlGamepad; 11 | class PlatformEvent; 12 | class PlatformEventHandler; 13 | class PlatformLogger; 14 | class PlatformGamepad; 15 | 16 | class SdlPlatformSharedState { 17 | public: 18 | explicit SdlPlatformSharedState(PlatformLogger *logger); 19 | ~SdlPlatformSharedState(); 20 | 21 | void logSdlError(const char *sdlFunctionName); 22 | 23 | void registerWindow(SdlWindow *window); 24 | void unregisterWindow(SdlWindow *window); 25 | 26 | void registerGamepad(SdlGamepad *gamepad); 27 | void unregisterGamepad(SdlGamepad *gamepad); 28 | 29 | /* We are using our own id numbering to prevent id jumping and also we can't rely on cdevice.which as SDL doesn't guarantee that it won't change. 30 | * In another words connection event can be received with one cdevice.which and disconnect event with completely different cdevice.which. 31 | * So these two functions and additionally SdlGamepad::JoystickId implements that. */ 32 | int32_t getGamepadIdBySdlId(uint32_t id); 33 | int32_t nextFreeGamepadId(); 34 | 35 | std::vector allWindowIds() const; 36 | SdlWindow *window(uint32_t id) const; 37 | SdlGamepad *gamepad(uint32_t id) const; 38 | 39 | private: 40 | PlatformLogger *_logger = nullptr; 41 | std::unordered_map _windowById; 42 | std::unordered_map _gamepadById; 43 | }; 44 | -------------------------------------------------------------------------------- /test/Testing/Game/TestController.cpp: -------------------------------------------------------------------------------- 1 | #include "TestController.h" 2 | 3 | #include 4 | 5 | #include "Library/Application/PlatformApplication.h" 6 | 7 | #include "Engine/Plugins/EngineTracer.h" 8 | #include "Engine/Plugins/EngineController.h" 9 | #include "Engine/Plugins/EngineDeterministicPlugin.h" 10 | #include "Engine/EngineGlobals.h" 11 | #include "Engine/Engine.h" 12 | 13 | #include "Application/GameKeyboardController.h" 14 | 15 | #include "TestConfig.h" 16 | 17 | TestController::TestController(EngineController *controller, const std::string &testDataPath): 18 | _controller(controller), 19 | _testDataPath(testDataPath) {} 20 | 21 | void TestController::loadGameFromTestData(const std::string &name) { 22 | _controller->loadGame((_testDataPath / name).string()); 23 | } 24 | 25 | void TestController::playTraceFromTestData(const std::string &saveName, const std::string &traceName, std::function postLoadCallback) { 26 | // TODO(captainurist): we need to overhaul our usage of path::string, path::u8string, path::generic_string, 27 | // pick one, and spell it out explicitly in HACKING 28 | ::application->get()->playTrace( 29 | _controller, 30 | (_testDataPath / saveName).string(), 31 | (_testDataPath / traceName).string(), 32 | std::move(postLoadCallback) 33 | ); 34 | } 35 | 36 | void TestController::prepareForNextTest() { 37 | ::application->get()->resetDeterministicState(); 38 | ::application->get()->reset(); 39 | 40 | ResetTestConfig(engine->config.get()); 41 | } 42 | -------------------------------------------------------------------------------- /src/Platform/PlatformEventLoop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class PlatformEventHandler; 4 | 5 | /** 6 | * Abstraction around a platform-specific event loop. 7 | */ 8 | class PlatformEventLoop { 9 | public: 10 | virtual ~PlatformEventLoop() = default; 11 | 12 | /** 13 | * Starts this event loop. 14 | * 15 | * This function blocks until either `quit` is called from inside the event handler code, or an application 16 | * is closed by the user (e.g. after the last window is closed, or `Command+Q` is pressed on Mac). 17 | * 18 | * @param eventHandler Callback for event processing. 19 | */ 20 | virtual void exec(PlatformEventHandler *eventHandler) = 0; 21 | 22 | /** 23 | * Tells this event loop to exit. Does nothing if the event loop is not running. 24 | */ 25 | virtual void quit() = 0; 26 | 27 | // TODO(captainurist): count parameter should be dropped. 28 | /** 29 | * Processes the messages that are currently in the message queue, and returns. Returns immediately if there are 30 | * no messages in the message queue. 31 | * 32 | * @param eventHandler Callback for event processing. 33 | * @param count Maximum number of messages to process, `-1` means unlimited. 34 | */ 35 | virtual void processMessages(PlatformEventHandler *eventHandler, int count = -1) = 0; 36 | 37 | // TODO(captainurist): this should be dropped. 38 | /** 39 | * Blocks until at least one message is delivered to the queue, and returns. 40 | */ 41 | virtual void waitForMessages() = 0; 42 | }; 43 | -------------------------------------------------------------------------------- /src/Platform/Proxy/ProxyPlatform.cpp: -------------------------------------------------------------------------------- 1 | #include "ProxyPlatform.h" 2 | 3 | #include 4 | 5 | #include "Platform/PlatformGamepad.h" 6 | #include "Platform/PlatformWindow.h" 7 | #include "Platform/PlatformEventLoop.h" 8 | 9 | ProxyPlatform::ProxyPlatform(Platform *base): ProxyBase(base) {} 10 | 11 | std::unique_ptr ProxyPlatform::createWindow() { 12 | return nonNullBase()->createWindow(); 13 | } 14 | 15 | std::unique_ptr ProxyPlatform::createEventLoop() { 16 | return nonNullBase()->createEventLoop(); 17 | } 18 | 19 | std::unique_ptr ProxyPlatform::createGamepad(uint32_t id) { 20 | return nonNullBase()->createGamepad(id); 21 | } 22 | 23 | void ProxyPlatform::setCursorShown(bool cursorShown) { 24 | return nonNullBase()->setCursorShown(cursorShown); 25 | } 26 | 27 | bool ProxyPlatform::isCursorShown() const { 28 | return nonNullBase()->isCursorShown(); 29 | } 30 | 31 | std::vector ProxyPlatform::displayGeometries() const { 32 | return nonNullBase()->displayGeometries(); 33 | } 34 | 35 | void ProxyPlatform::showMessageBox(const std::string& title, const std::string &message) const { 36 | nonNullBase()->showMessageBox(title, message); 37 | } 38 | 39 | int64_t ProxyPlatform::tickCount() const { 40 | return nonNullBase()->tickCount(); 41 | } 42 | 43 | std::string ProxyPlatform::winQueryRegistry(const std::wstring &path) const { 44 | return nonNullBase()->winQueryRegistry(path); 45 | } 46 | 47 | std::string ProxyPlatform::storagePath(const PlatformStorage type) const { 48 | return nonNullBase()->storagePath(type); 49 | } 50 | -------------------------------------------------------------------------------- /src/Engine/EngineGlobals.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Platform/Platform.h" 4 | #include "Platform/PlatformWindow.h" 5 | #include "Platform/PlatformOpenGLContext.h" 6 | #include "Platform/PlatformEventLoop.h" 7 | 8 | class PlatformApplication; 9 | 10 | namespace detail { 11 | void globalProcessMessages(); 12 | void globalWaitForMessages(); 13 | } // namespace detail 14 | 15 | extern int dword_6BE364_game_settings_1; // GAME_SETTINGS_* 16 | 17 | // TODO(captainurist): drop all of these, they are accessible through PlatformApplication 18 | extern Platform *platform; 19 | extern PlatformWindow *window; 20 | extern PlatformEventHandler *eventHandler; 21 | extern PlatformEventLoop *eventLoop; 22 | extern PlatformOpenGLContext *openGLContext; 23 | 24 | // TODO(captainurist): this global should go, together with this header file. 25 | extern PlatformApplication *application; 26 | 27 | #define MessageLoopWithWait() { \ 28 | detail::globalProcessMessages(); \ 29 | if (dword_6BE364_game_settings_1 & GAME_SETTINGS_APP_INACTIVE) { \ 30 | detail::globalWaitForMessages(); \ 31 | continue; \ 32 | } \ 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/doxygen.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen 2 | 3 | on: 4 | pull_request: 5 | push: 6 | release: 7 | types: [published] 8 | 9 | jobs: 10 | generate_documentation: 11 | runs-on: ubuntu-22.04 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | with: 16 | submodules: "recursive" 17 | 18 | - name: Install Doxygen 19 | run: | 20 | # sudo apt-get install doxygen -y 21 | curl https://www.doxygen.nl/files/doxygen-1.9.5.linux.bin.tar.gz | tar xzf - --strip-components=2 doxygen-1.9.5/bin/doxygen -C . 22 | 23 | - name: Generate Documentation 24 | run: | 25 | export PROJECT_NUMBER="$(git describe --always --tags --dirty)" 26 | ./doxygen Doxyfile 27 | touch docs/html/.nojekyll 28 | 29 | - name: Upload Artifact 30 | uses: actions/upload-artifact@v3 31 | with: 32 | name: Documentation 33 | path: docs/html 34 | 35 | deploy_documentation: 36 | if: github.ref == 'refs/heads/master' 37 | runs-on: ubuntu-22.04 38 | needs: generate_documentation 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v3 42 | with: 43 | submodules: "recursive" 44 | 45 | - name: Download Artifact 46 | uses: actions/download-artifact@v3 47 | with: 48 | name: Documentation 49 | path: docs/html 50 | 51 | - name: Deploy to GitHub Pages 52 | uses: JamesIves/github-pages-deploy-action@v4.4.0 53 | with: 54 | token: ${{ secrets.GITHUB_TOKEN }} 55 | branch: gh-pages 56 | folder: docs/html 57 | target-folder: . 58 | -------------------------------------------------------------------------------- /src/Utility/Streams/InputStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /** 6 | * Abstract base class for all data input streams. 7 | * 8 | * Compared to `std::istream` it is: 9 | * - Non-buffered. 10 | * - Uses exceptions for error handling. 11 | * - Has an extremely simple and intuitive interface consisting of exactly two methods. 12 | */ 13 | class InputStream { 14 | public: 15 | virtual ~InputStream() {} 16 | 17 | /** 18 | * @param data Output buffer to write read data into. 19 | * @param size Number of bytes to read. 20 | * @return Number of bytes actually read. A return value that's less than `size` signals 21 | * end of stream. 22 | * @throws std::runtime_error On error. 23 | */ 24 | virtual size_t Read(void *data, size_t size) = 0; 25 | 26 | /** 27 | * Reads the requested amount of data from the stream, or fails with an exception if unable to do so. 28 | * 29 | * @param data Output buffer to write read data into. 30 | * @param size Number of bytes to read. 31 | */ 32 | void ReadOrFail(void *data, size_t size); 33 | 34 | /** 35 | * @param size Number of bytes to skip. 36 | * @return Number of bytes actually skipped. A return value that's less than `size` signals 37 | * end of stream. 38 | * @throws std::runtime_error On error. 39 | */ 40 | virtual size_t Skip(size_t size) = 0; 41 | }; 42 | -------------------------------------------------------------------------------- /src/Engine/Graphics/PaletteManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Engine/Graphics/Sprites.h" 6 | 7 | /* 148 */ 8 | #pragma pack(push, 1) 9 | struct PaletteManager { 10 | PaletteManager(); 11 | 12 | /** 13 | * Resets the currently loaded Palettes and clears sprite indexes. 14 | */ 15 | void Reset(); 16 | 17 | int LoadPalette(unsigned int uPaletteID); 18 | int MakeBasePaletteLut(int uPaletteID, char *entries); 19 | int GetPaletteIndex(int paletteID); 20 | 21 | /** 22 | * @return Returns true if palette needs reloading to shader. 23 | */ 24 | bool GetGLPaletteNeedsUpdate(); 25 | /** 26 | * Resets the shader palette reload needed flag. 27 | */ 28 | void GLPaletteReset(); 29 | 30 | /** 31 | * @return Returns size of the shader palette store. 32 | */ 33 | size_t GetGLPaletteSize(); 34 | /** 35 | * @return Returns pointer to the palette data store for uploading to shader. 36 | */ 37 | uint32_t *GetGLPalettePtr(); 38 | 39 | private: 40 | int pPaletteIDs[50]; 41 | // palette / colour / rgb 42 | uint8_t pBaseColors[50][256][3]; 43 | uint32_t p32ARGBpalette[50][256]{}; 44 | bool palettestorechanged{ true }; 45 | }; 46 | #pragma pack(pop) 47 | 48 | bool HSV2RGB(float* redo, float* greeno, float* blueo, float hin, float sin, float vin); 49 | void RGB2HSV(float redin, float greenin, float bluein, float* outh, float* outs, float* outv); 50 | signed int ReplaceHSV(unsigned int uColor, float a2, float gamma, float a4); 51 | extern PaletteManager *pPaletteManager; 52 | --------------------------------------------------------------------------------