diff --git a/IMPLEMENTATION_CHEAT_SHEET.md b/IMPLEMENTATION_CHEAT_SHEET.md index e27f53a1..b6bfe58c 100644 --- a/IMPLEMENTATION_CHEAT_SHEET.md +++ b/IMPLEMENTATION_CHEAT_SHEET.md @@ -289,7 +289,7 @@ do { #### Known special cases -- `memset` so far was seen optimizing a "set all bytes to zero" case, if it was smaller then a unknown amount. In all known cases it used `EAX` for this. Would still recommend to try `memset` for cases with a register filling multiple memory locations. +- `memset` so far was seen optimizing a "set all bytes to zero" case, if it was smaller then a unknown amount. In all known cases it used `EAX` for this. Would still recommend to try `memset` for cases with a register filling multiple **byte-sized** memory locations. ### CRT Functions @@ -322,3 +322,13 @@ If the value is assigned to another object, the compiler tries to avoid creating **This only works if the function is called directly. Any form of indirection via pointer or resolver will not optimize. This is a fundamental limitation of the MSVC2005 compiler.** As a result, such cases do not use the resolver. The limitation through this is accepted, although, it should be noted in the status entry for the caller. + +### Stack + +The stack of the function is an important orientation for decompilation. +The reference point is the `esp` register, which points to the top of the stack. The stack grows **downwards** from the top, so actions that grow the stack reduce the `esp` register, for example `push` reduces the `esp` register by 4 and grows the stack by 4. + +Naturally, the stack reserved for the function indicated by `sub esp, ` at the start and `add esp, ` at the end of the function, need to match. This can be achieved by adding or removing locals or shrinking or growing arrays within the logical boundaries of the function. **It must never break the logic**. +At best, not only the stack fits, but variables are also at the correct positions and sizes within. + +If the stack usage shows a proper order in the function (i.e. the initial array occupies the first part in the allocated function stack, which means it requires the highest `[esp + ]` to reach), it might be sometimes good to fit one "side" of the stack first and then experiment with the rest of the function that has a non-fitting stack usage. diff --git a/src/OpenSHC/Game/GameCore.hpp b/src/OpenSHC/Game/GameCore.hpp index ee9117a3..7372af7d 100644 --- a/src/OpenSHC/Game/GameCore.hpp +++ b/src/OpenSHC/Game/GameCore.hpp @@ -25,6 +25,13 @@ namespace OpenSHC { namespace Game { + struct ScenarioProgress { + int progressCallToArms; + int progressSaladinsConquest; + int progressTheKingsCrusade; + int progressCrusaderStates; + }; + using OpenSHC::Game::GameMode2Int; using OpenSHC::Game::TrailTypeInt; using OpenSHC::Map::MapLockStateInt; @@ -59,10 +66,7 @@ namespace Game { BuildMenuTabTypeShort tabTypeSiegeSubset; // 0x00000038 length: 4 dword historicCampaignNumber; // 0x0000003C length: 4 int missionNumber1to20; // 0x00000040 length: 4 - int progressCallToArms; // 0x00000044 length: 4 - int progressSaladinsConquest; // 0x00000048 length: 4 - int progressTheKingsCrusade; // 0x0000004C length: 4 - int progressCrusaderStates; // 0x00000050 length: 4 + ScenarioProgress scenarioProgress; // 0x00000044 length: 16 dword furthestMission; // 0x00000054 length: 4 dword unlockAllHistoricalCampaigns; // 0x00000058 length: 4 dword unused1; // 0x0000005C length: 4 diff --git a/src/OpenSHC/IO/SettingsFileState/readUserConfig.cpp b/src/OpenSHC/IO/SettingsFileState/readUserConfig.cpp new file mode 100644 index 00000000..b00d0228 --- /dev/null +++ b/src/OpenSHC/IO/SettingsFileState/readUserConfig.cpp @@ -0,0 +1,308 @@ +// disable deprecation warnings for strcpy and strcat +#pragma warning(disable : 4996) + +#include "../SettingsFileState.func.hpp" + +#include "OpenSHC/Game/GameCore.func.hpp" +#include "OpenSHC/IO/ResourceManager.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Text/UserTextHandler.func.hpp" +#include "OpenSHC/Util/WideCharMultiByteState.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" +#include "OpenSHC/Globals/DAT_ResourceManager.hpp" +#include "OpenSHC/Globals/DAT_ScrollingHandler.hpp" +#include "OpenSHC/Globals/DAT_SoundSystemState.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" +#include "OpenSHC/Globals/DAT_WindowAndDirectDraw.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00495A30 + void SettingsFileState::readUserConfig() + { + DAT_GameCore::instance.missionDifficulty = 1; + DAT_GameCore::instance.missionDifficulty2 = 1; + DAT_GameCore::instance.missionDifficulty_2 = 1; + DAT_GameCore::instance.missionDifficulty_3 = 1; + DAT_GameCore::instance.missionDifficulty_1 = 1; + DAT_GameCore::instance.missionDifficulty_0 = 1; + + MACRO_CALL(OS_Func::_memset)(DAT_GameSynchronyState::instance.ipRelatedArray, 0, + sizeof(DAT_GameSynchronyState::instance.ipRelatedArray)); + + DAT_GameCore::instance.furthestSkirmishTrailMission = 0; + DAT_GameCore::instance.furthestWarchestTrailMission = 0; + DAT_GameCore::instance.furthestExtremeTrailMission = 0; + + DAT_GameCore::instance.skirmishTrailProgress = 0; + DAT_GameCore::instance.warchestTrailProgress = 0; + DAT_GameCore::instance.extremeTrailProgress = 0; + + DAT_GameCore::instance.lordIconUnk = 2; + DAT_GameCore::instance.selectedLordTypeUnk = 0; + + DAT_GameCore::instance.genieVoiceActive = TRUE; + DAT_GameCore::instance.tacticalPowersDisplayFlag = 0; + DAT_GameCore::instance.unusedOption1 = 0; + + DAT_GameCore::instance.skirmishTrailYearReached = 13200; + DAT_GameCore::instance.warchestTrailYearReached = 13560; + DAT_GameCore::instance.extremeTrailYearReached = 13920; + + for (int i = 0; i < sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken) + / sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken[0]); + ++i) { + DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken[i] = -1; + } + + for (int i = 0; i < 30; ++i) { + DAT_GameCore::instance.warchestTrailMonthsTakenOrChicken[i] = -1; + } + + for (int i = 0; i < 20; ++i) { + DAT_GameCore::instance.extremeTrailMonthsTakenOrChicken[i] = -1; + } + + char configPath[1000]; + // NOTE: Requires direct, non-resolved call due to copy elision. + strcpy(configPath, DAT_ResourceManager::ptr->paths_getDocumentsFolderString(true).c_str()); + strcat(configPath, s_crusader_cfg_005a75bc); + FILE* _File = MACRO_CALL(OS_Func::_fopen)(configPath, s_rb_005a4e18); + + unsigned int local_9cc = 0xffffffff; + + // NOTE: Weird stack sizes. No idea if this were truly the sizes or if something is missing here, but the + // function fits. + WCHAR wideCharBuffer[266]; + char charBuffer[512]; + if (_File) { + MACRO_CALL(OS_Func::_fseek)(_File, 0, FILE_END); + long _fileLength = MACRO_CALL(OS_Func::_ftell)(_File); + MACRO_CALL(OS_Func::_fseek)(_File, 0, FILE_BEGIN); + + char multiByteBuffer[268]; + if (_fileLength < 1000) { + + memset(charBuffer, 0, 20); + MACRO_CALL(OS_Func::_fread)(charBuffer, sizeof(char), 15, _File); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(5); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + charBuffer); + + memset(charBuffer, 0, 20); + MACRO_CALL(OS_Func::_fread)(charBuffer, sizeof(char), 5, _File); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(6); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + charBuffer); + + memset(charBuffer, 0, 20); + MACRO_CALL(OS_Func::_fread)(charBuffer, sizeof(char), 15, _File); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(7); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + charBuffer); + + memset(charBuffer, 0, 20); + MACRO_CALL(OS_Func::_fread)(charBuffer, sizeof(char), 256, _File); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(0); + + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + charBuffer); + } else { + + memset(wideCharBuffer, 0, 20 * sizeof(WCHAR)); + MACRO_CALL(OS_Func::_fread)(wideCharBuffer, sizeof(WCHAR), 15, _File); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(multiByteBuffer, wideCharBuffer, 15); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(5); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + multiByteBuffer); + + memset(wideCharBuffer, 0, 20 * sizeof(WCHAR)); + MACRO_CALL(OS_Func::_fread)(wideCharBuffer, sizeof(WCHAR), 5, _File); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(multiByteBuffer, wideCharBuffer, 5); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(6); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + multiByteBuffer); + + memset(wideCharBuffer, 0, 20 * sizeof(WCHAR)); + MACRO_CALL(OS_Func::_fread)(wideCharBuffer, sizeof(WCHAR), 15, _File); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(multiByteBuffer, wideCharBuffer, 15); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(7); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + multiByteBuffer); + + memset(wideCharBuffer, 0, 20 * sizeof(WCHAR)); + MACRO_CALL(OS_Func::_fread)(wideCharBuffer, sizeof(WCHAR), 256, _File); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(multiByteBuffer, wideCharBuffer, 256); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(0); + + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)( + multiByteBuffer); + } + + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.gameSpeedLevel, sizeof(DAT_GameCore::instance.gameSpeedLevel), 1, _File); + + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.settingBubbleHelp, sizeof(DAT_GameCore::instance.settingBubbleHelp), 1, _File); + MACRO_CALL(OS_Func::_fread)(&local_9cc, sizeof(local_9cc), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_ViewportRenderState::instance.viewportState.isZoomedOutUnk, + sizeof(DAT_ViewportRenderState::instance.viewportState.isZoomedOutUnk), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_ScrollingHandler::instance.scrollSpeedSetting_0x38, + sizeof(DAT_ScrollingHandler::instance.scrollSpeedSetting_0x38), 1, _File); + + MACRO_CALL(OS_Func::_fread)(&DAT_SoundSystemState::instance.soundActiveUnk_0x0, + sizeof(DAT_SoundSystemState::instance.soundActiveUnk_0x0), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_SoundSystemState::instance.streamVolume[0], + sizeof(DAT_SoundSystemState::instance.streamVolume[0]), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_SoundSystemState::instance.streamVolume[1], + sizeof(DAT_SoundSystemState::instance.streamVolume[1]), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_SoundSystemState::instance.streamVolume[3], + sizeof(DAT_SoundSystemState::instance.streamVolume[3]), 1, _File); + DAT_SoundSystemState::instance.streamVolume[4] = DAT_SoundSystemState::instance.streamVolume[3]; + DAT_SoundSystemState::instance.sampleVolume = DAT_SoundSystemState::instance.streamVolume[3]; + + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.scenarioProgress, sizeof(DAT_GameCore::instance.scenarioProgress), 1, _File); + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.furthestMission, sizeof(DAT_GameCore::instance.furthestMission), 1, _File); + + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.unused1, sizeof(DAT_GameCore::instance.unused1), 1, _File); + + MACRO_CALL(OS_Func::_fread)(&DAT_GameSynchronyState::instance.skirmishAutoSaveEveryMinutes, + sizeof(DAT_GameSynchronyState::instance.skirmishAutoSaveEveryMinutes), 1, _File); + + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.missionDifficulty, sizeof(DAT_GameCore::instance.missionDifficulty), 1, _File); + + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.missionDifficulty2, + sizeof(DAT_GameCore::instance.missionDifficulty2), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.missionDifficulty_2, + sizeof(DAT_GameCore::instance.missionDifficulty_2), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.missionDifficulty_3, + sizeof(DAT_GameCore::instance.missionDifficulty_3), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.missionDifficulty_1, + sizeof(DAT_GameCore::instance.missionDifficulty_1), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.missionDifficulty_0, + sizeof(DAT_GameCore::instance.missionDifficulty_0), 1, _File); + + MACRO_CALL(OS_Func::_fread)( + &DAT_MouseState::instance.cursorType, sizeof(DAT_MouseState::instance.cursorType), 1, _File); + + if (_fileLength < 1000) { + MACRO_CALL(OS_Func::_fread)(DAT_GameSynchronyState::instance.ipRelatedArray, 1, + sizeof(DAT_GameSynchronyState::instance.ipRelatedArray), _File); + } else { + WCHAR ipRelatedArrayWideChar[4][20]; + + MACRO_CALL(OS_Func::_fread)( + ipRelatedArrayWideChar, sizeof(WCHAR), sizeof(ipRelatedArrayWideChar) / sizeof(WCHAR), _File); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(DAT_GameSynchronyState::instance.ipRelatedArray[0], + ipRelatedArrayWideChar[0], sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[0])); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(DAT_GameSynchronyState::instance.ipRelatedArray[1], + ipRelatedArrayWideChar[1], sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[1])); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(DAT_GameSynchronyState::instance.ipRelatedArray[2], + ipRelatedArrayWideChar[2], sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[2])); + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::wideCharToMultiByteWithSize, + DAT_WideCharMultiByteState::ptr)(DAT_GameSynchronyState::instance.ipRelatedArray[3], + ipRelatedArrayWideChar[3], sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[3])); + } + + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.furthestSkirmishTrailMission, + sizeof(DAT_GameCore::instance.furthestSkirmishTrailMission), 1, _File); + + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.lordIconUnk, sizeof(DAT_GameCore::instance.lordIconUnk), 1, _File); + if (DAT_GameCore::instance.lordIconUnk < 2) { + DAT_GameCore::instance.lordIconUnk = 2; + } + + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.skirmishTrailProgress, + sizeof(DAT_GameCore::instance.skirmishTrailProgress), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.selectedLordTypeUnk, + sizeof(DAT_GameCore::instance.selectedLordTypeUnk), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.skirmishTrailYearReached, + sizeof(DAT_GameCore::instance.skirmishTrailYearReached), 1, _File); + + MACRO_CALL(OS_Func::_fread)(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken, + sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken[0]), + sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken) + / sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken[0]), + _File); + + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.genieVoiceActive, sizeof(DAT_GameCore::instance.genieVoiceActive), 1, _File); + + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.furthestWarchestTrailMission, + sizeof(DAT_GameCore::instance.furthestWarchestTrailMission), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.warchestTrailProgress, + sizeof(DAT_GameCore::instance.warchestTrailProgress), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.warchestTrailYearReached, + sizeof(DAT_GameCore::instance.warchestTrailYearReached), 1, _File); + MACRO_CALL(OS_Func::_fread)(DAT_GameCore::instance.warchestTrailMonthsTakenOrChicken, + sizeof(DAT_GameCore::instance.warchestTrailMonthsTakenOrChicken[0]), 30, _File); + + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.furthestExtremeTrailMission, + sizeof(DAT_GameCore::instance.furthestExtremeTrailMission), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.extremeTrailProgress, + sizeof(DAT_GameCore::instance.extremeTrailProgress), 1, _File); + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.extremeTrailYearReached, + sizeof(DAT_GameCore::instance.extremeTrailYearReached), 1, _File); + MACRO_CALL(OS_Func::_fread)(DAT_GameCore::instance.extremeTrailMonthsTakenOrChicken, + sizeof(DAT_GameCore::instance.extremeTrailMonthsTakenOrChicken[0]), 30, _File); + + MACRO_CALL(OS_Func::_fread)(&DAT_GameCore::instance.tacticalPowersDisplayFlag, + sizeof(DAT_GameCore::instance.tacticalPowersDisplayFlag), 1, _File); + MACRO_CALL(OS_Func::_fread)( + &DAT_GameCore::instance.unusedOption1, sizeof(DAT_GameCore::instance.unusedOption1), 1, _File); + + MACRO_CALL(OS_Func::_fread)(&DAT_WindowAndDirectDraw::instance.currentGameResolution, + sizeof(DAT_WindowAndDirectDraw::instance.currentGameResolution), 1, _File); + + MACRO_CALL(OS_Func::_fclose)(_File); + DAT_SoundSystemState::instance.streamVolume[2] = DAT_SoundSystemState::instance.streamVolume[1]; + } else { + MACRO_CALL(OS_Func::_memset)(charBuffer, 0, 256); + + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(5); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)(charBuffer); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(6); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)(charBuffer); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(7); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)(charBuffer); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(0); + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::copyIntoTextArray, DAT_UserTextHandlerState::ptr)(charBuffer); + + DAT_SoundSystemState::instance.streamVolume[2] = 80; + DAT_SoundSystemState::instance.streamVolume[1] = 80; + DAT_SoundSystemState::instance.streamVolume[0] = 90; + DAT_SoundSystemState::instance.streamVolume[3] = 85; + DAT_SoundSystemState::instance.streamVolume[4] = 85; + DAT_SoundSystemState::instance.sampleVolume = 100; + + DAT_GameSynchronyState::instance.skirmishAutoSaveEveryMinutes = 10; + DAT_MouseState::instance.cursorType = 0; + DAT_SoundSystemState::instance.soundActiveUnk_0x0 = 1; + } + DAT_GameCore::instance.unusedOption1 = 0; + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::resetToTextIndex, DAT_UserTextHandlerState::ptr)(9); + DAT_ViewportRenderState::instance.viewportState.isZoomedOutUnk = 0; + MACRO_CALL_MEMBER(Game::GameCore_Func::setStartDateUnk, DAT_GameCore::ptr)(0); + } + +} +} diff --git a/src/OpenSHC/IO/SettingsFileState/writeUserConfig.cpp b/src/OpenSHC/IO/SettingsFileState/writeUserConfig.cpp new file mode 100644 index 00000000..fafa41db --- /dev/null +++ b/src/OpenSHC/IO/SettingsFileState/writeUserConfig.cpp @@ -0,0 +1,183 @@ +// disable deprecation warnings for strcpy and strcat +#pragma warning(disable : 4996) + +#include "../SettingsFileState.func.hpp" + +#include "OpenSHC/IO/ResourceManager.func.hpp" +#include "OpenSHC/OS.func.hpp" +#include "OpenSHC/Text/UserTextHandler.func.hpp" +#include "OpenSHC/Util/WideCharMultiByteState.func.hpp" +#include "OpenSHC/string-literals.hpp" + +#include "OpenSHC/Globals/DAT_GameCore.hpp" +#include "OpenSHC/Globals/DAT_GameSynchronyState.hpp" +#include "OpenSHC/Globals/DAT_MouseState.hpp" +#include "OpenSHC/Globals/DAT_ResourceManager.hpp" +#include "OpenSHC/Globals/DAT_ScrollingHandler.hpp" +#include "OpenSHC/Globals/DAT_SoundSystemState.hpp" +#include "OpenSHC/Globals/DAT_UserTextHandlerState.hpp" +#include "OpenSHC/Globals/DAT_ViewportRenderState.hpp" +#include "OpenSHC/Globals/DAT_WideCharMultiByteState.hpp" +#include "OpenSHC/Globals/DAT_WindowAndDirectDraw.hpp" + +namespace OpenSHC { +namespace IO { + + // FUNCTION: STRONGHOLDCRUSADER 0x00496400 + void SettingsFileState::writeUserConfig() + { + char configPath[1000]; + // NOTE: Requires direct, non-resolved call due to copy elision. + strcpy(configPath, DAT_ResourceManager::ptr->paths_getDocumentsFolderString(true).c_str()); + strcat(configPath, s_crusader_cfg_005a75bc); + + FILE* _File = MACRO_CALL(OS_Func::_fopen)(configPath, s_wb_005a5510); + if (!_File) { + return; + } + WCHAR _wideCharBuffer[265]; + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::getTextArrayPointer, DAT_UserTextHandlerState::ptr)(5), 15); + MACRO_CALL(OS_Func::_fwrite)(_wideCharBuffer, sizeof(WCHAR), 15, _File); + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::getTextArrayPointer, DAT_UserTextHandlerState::ptr)(6), 5); + MACRO_CALL(OS_Func::_fwrite)(_wideCharBuffer, sizeof(WCHAR), 5, _File); + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::getTextArrayPointer, DAT_UserTextHandlerState::ptr)(7), 15); + MACRO_CALL(OS_Func::_fwrite)(_wideCharBuffer, sizeof(WCHAR), 15, _File); + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, + MACRO_CALL_MEMBER(Text::UserTextHandler_Func::getTextArrayPointer, DAT_UserTextHandlerState::ptr)(0), 256); + MACRO_CALL(OS_Func::_fwrite)(_wideCharBuffer, sizeof(WCHAR), 256, _File); + + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.gameSpeedLevel, sizeof(DAT_GameCore::instance.gameSpeedLevel), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.settingBubbleHelp, sizeof(DAT_GameCore::instance.settingBubbleHelp), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_WindowAndDirectDraw::instance.currentGameResolution, + sizeof(DAT_WindowAndDirectDraw::instance.currentGameResolution), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_ViewportRenderState::instance.viewportState.isZoomedOutUnk, + sizeof(DAT_ViewportRenderState::instance.viewportState.isZoomedOutUnk), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_ScrollingHandler::instance.scrollSpeedSetting_0x38, + sizeof(DAT_ScrollingHandler::instance.scrollSpeedSetting_0x38), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_SoundSystemState::instance.soundActiveUnk_0x0, + sizeof(DAT_SoundSystemState::instance.soundActiveUnk_0x0), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_SoundSystemState::instance.streamVolume[0], + sizeof(DAT_SoundSystemState::instance.streamVolume[0]), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_SoundSystemState::instance.streamVolume[1], + sizeof(DAT_SoundSystemState::instance.streamVolume[1]), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_SoundSystemState::instance.streamVolume[3], + sizeof(DAT_SoundSystemState::instance.streamVolume[3]), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.scenarioProgress, sizeof(DAT_GameCore::instance.scenarioProgress), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.furthestMission, sizeof(DAT_GameCore::instance.furthestMission), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.unused1, sizeof(DAT_GameCore::instance.unused1), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameSynchronyState::instance.skirmishAutoSaveEveryMinutes, + sizeof(DAT_GameSynchronyState::instance.skirmishAutoSaveEveryMinutes), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.missionDifficulty, sizeof(DAT_GameCore::instance.missionDifficulty), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.missionDifficulty2, sizeof(DAT_GameCore::instance.missionDifficulty2), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.missionDifficulty_2, sizeof(DAT_GameCore::instance.missionDifficulty_2), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.missionDifficulty_3, sizeof(DAT_GameCore::instance.missionDifficulty_3), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.missionDifficulty_1, sizeof(DAT_GameCore::instance.missionDifficulty_1), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.missionDifficulty_0, sizeof(DAT_GameCore::instance.missionDifficulty_0), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)( + &DAT_MouseState::instance.cursorType, sizeof(DAT_MouseState::instance.cursorType), 1, _File); + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, DAT_GameSynchronyState::instance.ipRelatedArray[0], + sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[0])); + MACRO_CALL(OS_Func::_fwrite)( + _wideCharBuffer, sizeof(WCHAR), sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[0]), _File); + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, DAT_GameSynchronyState::instance.ipRelatedArray[1], + sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[1])); + MACRO_CALL(OS_Func::_fwrite)( + _wideCharBuffer, sizeof(WCHAR), sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[1]), _File); + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, DAT_GameSynchronyState::instance.ipRelatedArray[2], + sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[2])); + MACRO_CALL(OS_Func::_fwrite)( + _wideCharBuffer, sizeof(WCHAR), sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[2]), _File); + + MACRO_CALL_MEMBER(Util::WideCharMultiByteState_Func::multiByteToWideCharThunk, DAT_WideCharMultiByteState::ptr)( + _wideCharBuffer, DAT_GameSynchronyState::instance.ipRelatedArray[3], + sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[3])); + MACRO_CALL(OS_Func::_fwrite)( + _wideCharBuffer, sizeof(WCHAR), sizeof(DAT_GameSynchronyState::instance.ipRelatedArray[3]), _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.furthestSkirmishTrailMission, + sizeof(DAT_GameCore::instance.furthestSkirmishTrailMission), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.lordIconUnk, sizeof(DAT_GameCore::instance.lordIconUnk), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.skirmishTrailProgress, + sizeof(DAT_GameCore::instance.skirmishTrailProgress), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.selectedLordTypeUnk, sizeof(DAT_GameCore::instance.selectedLordTypeUnk), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.skirmishTrailYearReached, + sizeof(DAT_GameCore::instance.skirmishTrailYearReached), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken, + sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken[0]), + sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken) + / sizeof(DAT_GameCore::instance.skirmishTrailMonthsTakenOrChicken[0]), + _File); + + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.genieVoiceActive, sizeof(DAT_GameCore::instance.genieVoiceActive), 1, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.furthestWarchestTrailMission, + sizeof(DAT_GameCore::instance.furthestWarchestTrailMission), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.warchestTrailProgress, + sizeof(DAT_GameCore::instance.warchestTrailProgress), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.warchestTrailYearReached, + sizeof(DAT_GameCore::instance.warchestTrailYearReached), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(DAT_GameCore::instance.warchestTrailMonthsTakenOrChicken, + sizeof(DAT_GameCore::instance.warchestTrailMonthsTakenOrChicken[0]), 30, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.furthestExtremeTrailMission, + sizeof(DAT_GameCore::instance.furthestExtremeTrailMission), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.extremeTrailProgress, + sizeof(DAT_GameCore::instance.extremeTrailProgress), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.extremeTrailYearReached, + sizeof(DAT_GameCore::instance.extremeTrailYearReached), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(DAT_GameCore::instance.extremeTrailMonthsTakenOrChicken, + sizeof(DAT_GameCore::instance.extremeTrailMonthsTakenOrChicken[0]), 30, _File); + + MACRO_CALL(OS_Func::_fwrite)(&DAT_GameCore::instance.tacticalPowersDisplayFlag, + sizeof(DAT_GameCore::instance.tacticalPowersDisplayFlag), 1, _File); + MACRO_CALL(OS_Func::_fwrite)( + &DAT_GameCore::instance.unusedOption1, sizeof(DAT_GameCore::instance.unusedOption1), 1, _File); + MACRO_CALL(OS_Func::_fwrite)(&DAT_WindowAndDirectDraw::instance.currentGameResolution, + sizeof(DAT_WindowAndDirectDraw::instance.currentGameResolution), 1, _File); + + MACRO_CALL(OS_Func::_fclose)(_File); + } + +} +} diff --git a/src/OpenSHC/Synchrony/GameSynchronyState.hpp b/src/OpenSHC/Synchrony/GameSynchronyState.hpp index f832e055..ecbceea2 100644 --- a/src/OpenSHC/Synchrony/GameSynchronyState.hpp +++ b/src/OpenSHC/Synchrony/GameSynchronyState.hpp @@ -303,10 +303,7 @@ namespace Synchrony { int unknownPlayerInfoArray_01[9]; // 0x001092D0 length: 36 int DAT_ReceivedAIVFileAvailabilityPerAIArray[9][20]; // 0x001092F4 length: 720 SkirmishStatistics finalResults; // 0x001095C4 length: 1912 - char ipRelatedArray[20]; // 0x00109D3C length: 20 - char ipRelatedArray2[20]; // 0x00109D50 length: 20 - char ipRelatedArray3[20]; // 0x00109D64 length: 20 - char ipRelatedArray4[20]; // 0x00109D78 length: 20 + char ipRelatedArray[4][20]; // 0x00109D3C length: 80 int ipArrayIndex; // 0x00109D8C length: 4 undefined4 DAT_TwoIfNotHost; // 0x00109D90 length: 4 undefined4 DAT_MapFileReceivingState; // 0x00109D94 length: 4 diff --git a/src/OpenSHC/Text/UserTextHandler.func.hpp b/src/OpenSHC/Text/UserTextHandler.func.hpp index 84ac0da0..f8cc3d8c 100644 --- a/src/OpenSHC/Text/UserTextHandler.func.hpp +++ b/src/OpenSHC/Text/UserTextHandler.func.hpp @@ -19,7 +19,7 @@ namespace Text { char* (UserTextHandler::*)(), false, Address::SHC_3BB0A8C1_0x004697C0, &UserTextHandler::getCurrentText) getCurrentText; - MACRO_FUNCTION_RESOLVER(int (UserTextHandler::*)(int), false, Address::SHC_3BB0A8C1_0x004697E0, + MACRO_FUNCTION_RESOLVER(char* (UserTextHandler::*)(int), false, Address::SHC_3BB0A8C1_0x004697E0, &UserTextHandler::getTextArrayPointer) getTextArrayPointer; diff --git a/src/OpenSHC/Text/UserTextHandler.hpp b/src/OpenSHC/Text/UserTextHandler.hpp index 3c136a9b..c4ab47d0 100644 --- a/src/OpenSHC/Text/UserTextHandler.hpp +++ b/src/OpenSHC/Text/UserTextHandler.hpp @@ -48,7 +48,7 @@ namespace Text { char* getCurrentText(); - int getTextArrayPointer(int param_1); + char* getTextArrayPointer(int param_1); void setTextEntryAndUpdateCursor(undefined4 param_1, undefined4 param_2); diff --git a/status/addresses-SHC-3BB0A8C1.txt b/status/addresses-SHC-3BB0A8C1.txt index c00bd8f3..77e4a192 100644 --- a/status/addresses-SHC-3BB0A8C1.txt +++ b/status/addresses-SHC-3BB0A8C1.txt @@ -24229,9 +24229,9 @@ SHC_3BB0A8C1_0x00495A20 | 0.0% | Pending SHC_3BB0A8C1_0x00495A24 | 0.0% | Pending -SHC_3BB0A8C1_0x00495A30 | 0.0% | Pending +SHC_3BB0A8C1_0x00495A30 | 100.0% | Reimplemented -SHC_3BB0A8C1_0x00496400 | 0.0% | Pending +SHC_3BB0A8C1_0x00496400 | 100.0% | Reimplemented SHC_3BB0A8C1_0x004968A0 | 0.0% | Pending