From 5ad1b2ef865ad6b686e7e90ac233fb93eb94287b Mon Sep 17 00:00:00 2001 From: FynnTW Date: Fri, 4 Oct 2024 11:08:20 +0300 Subject: [PATCH] break hidden resources limit --- M2TWEOP Code/M2TWEOP library/Injects.cpp | 188 ++++++++++++++++++ M2TWEOP Code/M2TWEOP library/Injects.h | 72 +++++++ M2TWEOP Code/M2TWEOP library/dataOffsets.cpp | 2 + M2TWEOP Code/M2TWEOP library/dataOffsets.h | 1 + .../M2TWEOP library/functionsOffsets.cpp | 2 + .../M2TWEOP library/functionsOffsets.h | 1 + M2TWEOP Code/M2TWEOP library/managerF.cpp | 36 ++++ .../M2TWEOP library/patchesForGame.cpp | 43 ++++ M2TWEOP Code/M2TWEOP library/patchesForGame.h | 4 + .../M2TWEOP library/types/eopBuildings.cpp | 61 ++++++ .../M2TWEOP library/types/eopBuildings.h | 20 ++ .../M2TWEOP library/types/strategyMap.h | 28 +++ 12 files changed, 458 insertions(+) diff --git a/M2TWEOP Code/M2TWEOP library/Injects.cpp b/M2TWEOP Code/M2TWEOP library/Injects.cpp index 2de9e83e..c93c74f2 100644 --- a/M2TWEOP Code/M2TWEOP library/Injects.cpp +++ b/M2TWEOP Code/M2TWEOP library/Injects.cpp @@ -5541,6 +5541,194 @@ void onSetKhakiText5::SetNewCode() delete a; } + +onSetRegionHiddenResources2::onSetRegionHiddenResources2(MemWork* mem, LPVOID addr, int ver) + :AATemplate(mem), funcAddress(addr) +{ + if (ver == 2)//steam + m_adress = 0x8D95A3; + + else if (ver == 1)//kingdoms + m_adress = 0x8D8B43; +} + +void onSetRegionHiddenResources2::SetNewCode() +{ + const auto a = new Assembler(); + a->pop(edx); + a->push(ecx); + a->push(edx); + a->push(ebx); + a->mov(ecx, edx); + a->mov(eax, reinterpret_cast(funcAddress)); + a->call(eax); + a->pop(ebx); + a->pop(edx); + a->pop(ecx); + a->cmp(eax, ebx); + a->ret(); + m_cheatBytes = static_cast(a->make()); + delete a; +} + + +onHiddenResourceConditionParse::onHiddenResourceConditionParse(MemWork* mem, LPVOID addr, int ver) + :AATemplate(mem), funcAddress(addr) +{ + if (ver == 2)//steam + m_adress = 0x8A79AA; + + else if (ver == 1)//kingdoms + m_adress = 0x8A6FCA; +} + +void onHiddenResourceConditionParse::SetNewCode() +{ + const auto a = new Assembler(); + a->pop(ecx); + a->push(edx); + a->push(ebp); + a->mov(eax, reinterpret_cast(funcAddress)); + a->call(eax); + a->pop(ebp); + a->pop(edx); + a->mov(edi, eax); + a->ret(); + m_cheatBytes = static_cast(a->make()); + delete a; +} + + +onHiddenResourceCheck::onHiddenResourceCheck(MemWork* mem, LPVOID addr, int ver) + :AATemplate(mem), funcAddress(addr) +{ + if (ver == 2)//steam + m_adress = 0x609E54; + + else if (ver == 1)//kingdoms + m_adress = 0x609AA4; +} + +void onHiddenResourceCheck::SetNewCode() +{ + const auto a = new Assembler(); + a->pop(esi); + a->mov(edx, eax); + a->mov(eax, reinterpret_cast(funcAddress)); + a->call(eax); + if (m_adress == 0x609E54) + a->mov(ecx, 0x609E84); + else + a->mov(ecx, 0x609AD4); + a->jmp(ecx); + a->ret(); + m_cheatBytes = static_cast(a->make()); + delete a; +} + +onHiddenResourceCheck2::onHiddenResourceCheck2(MemWork* mem, LPVOID addr, int ver) + :AATemplate(mem), funcAddress(addr) +{ + if (ver == 2)//steam + m_adress = 0x609F52; + + else if (ver == 1)//kingdoms + m_adress = 0x609BA2; +} + +void onHiddenResourceCheck2::SetNewCode() +{ + const auto a = new Assembler(); + a->pop(esi); + a->mov(ecx, edx); + a->mov(edx, eax); + a->mov(eax, reinterpret_cast(funcAddress)); + a->call(eax); + if (m_adress == 0x609F52) + a->mov(ecx, 0x609F81); + else + a->mov(ecx, 0x609BD1); + a->jmp(ecx); + a->ret(); + m_cheatBytes = static_cast(a->make()); + delete a; +} + + +onSetRegionHiddenResources::onSetRegionHiddenResources(MemWork* mem, LPVOID addr, int ver) + :AATemplate(mem), funcAddress(addr) +{ + if (ver == 2)//steam + m_adress = 0x8D964B; + + else if (ver == 1)//kingdoms + m_adress = 0x8D8BEB; +} + +void onSetRegionHiddenResources::SetNewCode() +{ + const auto a = new Assembler(); + const auto label = a->newLabel(); + a->push(eax); + a->mov(edx, esi); + a->mov(ecx, eax); + a->mov(eax, reinterpret_cast(funcAddress)); + a->call(eax); + a->cmp(eax, 0); + a->pop(eax); + a->jbe(label); + if (m_adress == 0x8D964B) + a->mov(eax, 0x008D9677); + else + a->mov(eax, 0x008D8C17); + a->jmp(eax); + a->bind(label); + a->mov(ecx, eax); + a->mov(edx, eax); + a->and_(eax, 0x1F); + a->ret(); + m_cheatBytes = static_cast(a->make()); + delete a; +} + + +onReadHiddenResources::onReadHiddenResources(MemWork* mem, LPVOID addr, int ver) + :AATemplate(mem), funcAddress(addr) +{ + if (ver == 2)//steam + m_adress = 0x8AD0AD; + + else if (ver == 1)//kingdoms + m_adress = 0x8AC6BD; +} + +void onReadHiddenResources::SetNewCode() +{ + const auto a = new Assembler(); + const auto label = a->newLabel(); + a->push(ecx); + a->push(edx); + a->push(eax); + a->mov(edx, ecx); + a->mov(ecx, esi); + a->mov(eax, reinterpret_cast(funcAddress)); + a->call(eax); + a->cmp(eax, 0); + a->pop(eax); + a->pop(edx); + a->pop(ecx); + a->jbe(label); + if (m_adress == 0x8AD0AD) + a->mov(eax, 0x8AD0CA); + else + a->mov(eax, 0x8AC6DA); + a->jmp(eax); + a->bind(label); + a->ret(); + m_cheatBytes = static_cast(a->make()); + delete a; +} + onIsBuildingTypePresentAtMinLevel::onIsBuildingTypePresentAtMinLevel(MemWork* mem, LPVOID addr, int ver) :AATemplate(mem), funcAddress(addr) { diff --git a/M2TWEOP Code/M2TWEOP library/Injects.h b/M2TWEOP Code/M2TWEOP library/Injects.h index 929cc6e4..abcfefa8 100644 --- a/M2TWEOP Code/M2TWEOP library/Injects.h +++ b/M2TWEOP Code/M2TWEOP library/Injects.h @@ -2045,6 +2045,78 @@ class onSetKhakiText5 LPVOID funcAddress; }; +class onSetRegionHiddenResources + :public AATemplate +{ +public: + onSetRegionHiddenResources(MemWork* mem, LPVOID addr, int ver); + ~onSetRegionHiddenResources() = default; + + void SetNewCode(); +private: + LPVOID funcAddress; +}; + +class onSetRegionHiddenResources2 + :public AATemplate +{ +public: + onSetRegionHiddenResources2(MemWork* mem, LPVOID addr, int ver); + ~onSetRegionHiddenResources2() = default; + + void SetNewCode(); +private: + LPVOID funcAddress; +}; + +class onHiddenResourceConditionParse + :public AATemplate +{ +public: + onHiddenResourceConditionParse(MemWork* mem, LPVOID addr, int ver); + ~onHiddenResourceConditionParse() = default; + + void SetNewCode(); +private: + LPVOID funcAddress; +}; + +class onHiddenResourceCheck + :public AATemplate +{ +public: + onHiddenResourceCheck(MemWork* mem, LPVOID addr, int ver); + ~onHiddenResourceCheck() = default; + + void SetNewCode(); +private: + LPVOID funcAddress; +}; + +class onHiddenResourceCheck2 + :public AATemplate +{ +public: + onHiddenResourceCheck2(MemWork* mem, LPVOID addr, int ver); + ~onHiddenResourceCheck2() = default; + + void SetNewCode(); +private: + LPVOID funcAddress; +}; + +class onReadHiddenResources + :public AATemplate +{ +public: + onReadHiddenResources(MemWork* mem, LPVOID addr, int ver); + ~onReadHiddenResources() = default; + + void SetNewCode(); +private: + LPVOID funcAddress; +}; + class onIsBuildingTypePresentAtMinLevel :public AATemplate diff --git a/M2TWEOP Code/M2TWEOP library/dataOffsets.cpp b/M2TWEOP Code/M2TWEOP library/dataOffsets.cpp index b647b2f6..c81c707b 100644 --- a/M2TWEOP Code/M2TWEOP library/dataOffsets.cpp +++ b/M2TWEOP Code/M2TWEOP library/dataOffsets.cpp @@ -95,6 +95,7 @@ void dataOffsets::initDataOffsets(int gameVer) offsets.descrRebels = 0x16673F0; offsets.eventManager = 0x16F0BC8; offsets.uiStratUiV2 = 0x2CB62FC; + offsets.currentRegion = 0x18FD970; offsets.fortVtbl = 0x13362F4; @@ -192,6 +193,7 @@ void dataOffsets::initDataOffsets(int gameVer) offsets.ltgdConfig = 0x01605134; offsets.descrRebels = 0x161F518; offsets.eventManager = 0x16A7A30; + offsets.currentRegion = 0x18B4800; offsets.uiStratUiV2 = 0x2C6D1B0; offsets.audioEnable = reinterpret_cast(0x01639f1d); diff --git a/M2TWEOP Code/M2TWEOP library/dataOffsets.h b/M2TWEOP Code/M2TWEOP library/dataOffsets.h index 73e41122..a373df15 100644 --- a/M2TWEOP Code/M2TWEOP library/dataOffsets.h +++ b/M2TWEOP Code/M2TWEOP library/dataOffsets.h @@ -61,6 +61,7 @@ class dataOffsets DWORD cultureDatabase = NULL; DWORD loadGameHandler = NULL; DWORD selectedEra = NULL; + DWORD currentRegion = NULL; DWORD campaignDb = NULL; DWORD campaignDbExtra = NULL; DWORD groupLabels = NULL; diff --git a/M2TWEOP Code/M2TWEOP library/functionsOffsets.cpp b/M2TWEOP Code/M2TWEOP library/functionsOffsets.cpp index 3cb1dfd9..0abb39f5 100644 --- a/M2TWEOP Code/M2TWEOP library/functionsOffsets.cpp +++ b/M2TWEOP Code/M2TWEOP library/functionsOffsets.cpp @@ -329,6 +329,7 @@ void codes::initCodes(int gameVer) offsets.createBuildingSett = 0x5FAB60; offsets.buildQueueConflictTest = 0x5EB100; offsets.removeBuildingSelection = 0x5FA3A0; + offsets.getNextWord = 0xD4F060; } @@ -660,5 +661,6 @@ void codes::initCodes(int gameVer) offsets.createBuildingSett = 0x005FAF50; offsets.buildQueueConflictTest = 0x005EB560; offsets.removeBuildingSelection = 0x005FA790; + offsets.getNextWord = 0xD493C0; } } \ No newline at end of file diff --git a/M2TWEOP Code/M2TWEOP library/functionsOffsets.h b/M2TWEOP Code/M2TWEOP library/functionsOffsets.h index fe4d3f4c..c38e828d 100644 --- a/M2TWEOP Code/M2TWEOP library/functionsOffsets.h +++ b/M2TWEOP Code/M2TWEOP library/functionsOffsets.h @@ -209,6 +209,7 @@ class codes DWORD switchArmyFaction = NULL; DWORD changeCharacterTileStuff = NULL; DWORD initPlaceCharacter = NULL; + DWORD getNextWord = NULL; DWORD getResidenceCharacterNum = NULL; DWORD getResidenceCharacterAtIndex = NULL; DWORD removeSieges = NULL; diff --git a/M2TWEOP Code/M2TWEOP library/managerF.cpp b/M2TWEOP Code/M2TWEOP library/managerF.cpp index ce242c8a..a2f4c88a 100644 --- a/M2TWEOP Code/M2TWEOP library/managerF.cpp +++ b/M2TWEOP Code/M2TWEOP library/managerF.cpp @@ -873,6 +873,42 @@ void managerF::execPatches() toSetKhakiText5->Enable(); f1 << "Done" << '\n'; + f1 << "Start applying onReadHiddenResources patch" << '\n'; + onReadHiddenResources* toReadHiddenResources = new onReadHiddenResources(mem, (LPVOID)patchesForGame::onReadHiddenResources, globals::dataS.gameVersion); + toReadHiddenResources->SetNewCode(); + toReadHiddenResources->Enable(); + f1 << "Done" << '\n'; + + f1 << "Start applying onSetRegionHiddenResources patch" << '\n'; + onSetRegionHiddenResources* toSetRegionHiddenResources = new onSetRegionHiddenResources(mem, (LPVOID)patchesForGame::onSetRegionHiddenResources, globals::dataS.gameVersion); + toSetRegionHiddenResources->SetNewCode(); + toSetRegionHiddenResources->Enable(); + f1 << "Done" << '\n'; + + f1 << "Start applying onSetRegionHiddenResources2 patch" << '\n'; + onSetRegionHiddenResources2* toSetRegionHiddenResources2 = new onSetRegionHiddenResources2(mem, (LPVOID)patchesForGame::onGetHiddenResource, globals::dataS.gameVersion); + toSetRegionHiddenResources2->SetNewCode(); + toSetRegionHiddenResources2->Enable(); + f1 << "Done" << '\n'; + + f1 << "Start applying onHiddenResourceConditionParse patch" << '\n'; + onHiddenResourceConditionParse* toHiddenResourceConditionParse = new onHiddenResourceConditionParse(mem, (LPVOID)patchesForGame::onGetHiddenResource, globals::dataS.gameVersion); + toHiddenResourceConditionParse->SetNewCode(); + toHiddenResourceConditionParse->Enable(); + f1 << "Done" << '\n'; + + f1 << "Start applying toHiddenResourceCheck patch" << '\n'; + onHiddenResourceCheck* toHiddenResourceCheck = new onHiddenResourceCheck(mem, (LPVOID)patchesForGame::onCheckHiddenResource, globals::dataS.gameVersion); + toHiddenResourceCheck->SetNewCode(); + toHiddenResourceCheck->Enable(); + f1 << "Done" << '\n'; + + f1 << "Start applying toHiddenResourceCheck2 patch" << '\n'; + onHiddenResourceCheck2* toHiddenResourceCheck2 = new onHiddenResourceCheck2(mem, (LPVOID)patchesForGame::onCheckHiddenResource, globals::dataS.gameVersion); + toHiddenResourceCheck2->SetNewCode(); + toHiddenResourceCheck2->Enable(); + f1 << "Done" << '\n'; + f1 << "Start applying onSetArmyGeneralsUnit patch" << '\n'; onSetArmyGeneralsUnit* toSetArmyGeneralsUnit = new onSetArmyGeneralsUnit(mem, (LPVOID)patchesForGame::onSetArmyGeneralsUnit, globals::dataS.gameVersion); toSetArmyGeneralsUnit->SetNewCode(); diff --git a/M2TWEOP Code/M2TWEOP library/patchesForGame.cpp b/M2TWEOP Code/M2TWEOP library/patchesForGame.cpp index 6fc9906c..2b045fce 100644 --- a/M2TWEOP Code/M2TWEOP library/patchesForGame.cpp +++ b/M2TWEOP Code/M2TWEOP library/patchesForGame.cpp @@ -809,6 +809,46 @@ void __fastcall patchesForGame::onWriteSoldiersToStrat(unit* unit) unit->markedToKill = 1; } +int patchesForGame::onSetRegionHiddenResources(const int hiddenResourceId, const mapRegion* region) +{ + eopHiddenResources::setInitialized(false); + eopHiddenResources::addHiddenResourceToRegionIndex(region->name, hiddenResourceId); + if (hiddenResourceId < 64) + return 0; + //gameHelpers::logStringGame("EOP Hidden resource with id: " + std::to_string(hiddenResourceId) + " added to region: " + region->name); + return 1; +} + +int patchesForGame::onReadHiddenResources(const int hiddenResourceId, void* textBuffer) +{ + //gameHelpers::logStringGame("Hidden resource with id: " + std::to_string(hiddenResourceId)); + if (hiddenResourceId > 63) + { + if (hiddenResourceId == 64) + { + const auto edb = eopBuildings::getEdb(); + for (int i = 0; i < edb->hiddenResourceCount; i++) + { + eopHiddenResources::addHiddenResourceWithId(edb->hiddenResources[i].hiddenResName, i); + } + } + const char* name = GAME_FUNC(const char*(__thiscall*)(void*), getNextWord)(textBuffer); + eopHiddenResources::addHiddenResource(name); + return 1; + } + return 0; +} + +int patchesForGame::onGetHiddenResource(const stringWithHash* name) +{ + return eopHiddenResources::getHiddenResourceIndex(name->name); +} + +int patchesForGame::onCheckHiddenResource(const int id, const int region) +{ + return eopHiddenResources::hasHiddenResource(region, id); +} + void patchesForGame::onSetSettlementModel(settlementStruct* settlement) { bool changed = false; @@ -1624,6 +1664,8 @@ void __fastcall patchesForGame::clickAtTile(coordPair* xy) void __stdcall patchesForGame::afterCampaignMapLoaded() { + if (!eopHiddenResources::isInitialized()) + eopHiddenResources::initialize(); discordManager::onCampaignMapLoaded(); globals::dataS.Modules.tacticalMapViewer.unView(); plugData::data.luaAll.fillHashMaps(); @@ -1660,6 +1702,7 @@ void __stdcall patchesForGame::onGameInit() cultures::eopPortraitDb::createEopPortraitDb(); discordManager::menuLoaded(); gameEvents::onGameInit(); + const auto edb = eopBuildings::getEdb(); } void __stdcall patchesForGame::onUnloadCampaign() diff --git a/M2TWEOP Code/M2TWEOP library/patchesForGame.h b/M2TWEOP Code/M2TWEOP library/patchesForGame.h index afd73e82..6c4c9f6f 100644 --- a/M2TWEOP Code/M2TWEOP library/patchesForGame.h +++ b/M2TWEOP Code/M2TWEOP library/patchesForGame.h @@ -45,6 +45,10 @@ class patchesForGame static int __fastcall onCalculateMiningIncome(int value, const settlementStruct* settlement); static int __fastcall onCreateMercUnitCheck(char** entryName, int eduIndex); static void __fastcall onWriteSoldiersToStrat(unit* unit); + static int __fastcall onSetRegionHiddenResources(int hiddenResourceId, const mapRegion* region); + static int __fastcall onReadHiddenResources(int hiddenResourceId, void* textBuffer); + static int __fastcall onGetHiddenResource(const stringWithHash* name); + static int __fastcall onCheckHiddenResource(int id, int region); static void __fastcall onSetSettlementModel(settlementStruct* settlement); static int __fastcall onAddSettlementToDiplomacyScroll(const settlementStruct* settlement); static settlementStruct* __fastcall onDecideMissionTarget(settlementStruct* settlement, factionStruct* faction); diff --git a/M2TWEOP Code/M2TWEOP library/types/eopBuildings.cpp b/M2TWEOP Code/M2TWEOP library/types/eopBuildings.cpp index 81811ec9..022900c6 100644 --- a/M2TWEOP Code/M2TWEOP library/types/eopBuildings.cpp +++ b/M2TWEOP Code/M2TWEOP library/types/eopBuildings.cpp @@ -13,6 +13,10 @@ #include "techFuncs.h" std::vector> buildEntryDB::eopEdb = {}; +std::array, 200> eopHiddenResources::m_HiddenResources = {}; +unordered_map eopHiddenResources::m_HiddenResourcesLookup = {}; +unordered_map> eopHiddenResources::m_NamesToIndexes = {}; +bool eopHiddenResources::m_Initialized = false; edbEntry* buildEntryDB::addEopBuildEntry(edbEntry* oldEntry, const int newIndex) { @@ -100,6 +104,63 @@ edbEntry* exportDescrBuildings::getBuildingByName(const std::string& name) return nullptr; } +int eopHiddenResources::getHiddenResourceIndex(const std::string& name) +{ + if (const auto res = m_HiddenResourcesLookup.find(name); + res != m_HiddenResourcesLookup.end()) + return res->second; + const auto edb = eopBuildings::getEdb(); + if (!edb) + return -1; + return edb->getHiddenResourceIndex(name.c_str()); +} + +void eopHiddenResources::addHiddenResource(const std::string& name) +{ + m_HiddenResourcesLookup[name] = m_HiddenResourcesLookup.size(); +} + +void eopHiddenResources::addHiddenResourceWithId(const std::string& name, const int id) +{ + m_HiddenResourcesLookup[name] = id; +} + +void eopHiddenResources::addHiddenResourceToRegion(const int regionId, const std::string& name) +{ + m_HiddenResources[regionId].push_back(getHiddenResourceIndex(name)); +} + +void eopHiddenResources::addHiddenResourceToRegionIndex(const std::string& name, const int id) +{ + if (m_NamesToIndexes.find(name) == m_NamesToIndexes.end()) + m_NamesToIndexes[name] = {}; + m_NamesToIndexes[name].push_back(id); +} + +bool eopHiddenResources::hasHiddenResource(const int regionId, const int id) +{ + if (regionId >= static_cast(m_HiddenResources.size())) + return false; + const auto& res = m_HiddenResources[regionId]; + return std::find(res.begin(), res.end(), id) != res.end(); +} + +void eopHiddenResources::initialize() +{ + const auto mapData = stratMapHelpers::getStratMap(); + const auto n = mapData->regionsNum; + for (int i = 0; i < n; i++) + { + if (const auto region = &mapData->regions[i]; m_NamesToIndexes.find(region->regionName) != m_NamesToIndexes.end()) + { + const auto& res = m_NamesToIndexes[region->regionName]; + for (const auto id : res) + m_HiddenResources[i].push_back(id); + } + } + m_Initialized = true; +} + //add new building capability, bonus refers to bonus keyboard in edb void buildingLevel::addCapability(int capability, int16_t value, bool bonus, const std::string& condition) diff --git a/M2TWEOP Code/M2TWEOP library/types/eopBuildings.h b/M2TWEOP Code/M2TWEOP library/types/eopBuildings.h index 9a673866..262a1c5e 100644 --- a/M2TWEOP Code/M2TWEOP library/types/eopBuildings.h +++ b/M2TWEOP Code/M2TWEOP library/types/eopBuildings.h @@ -479,6 +479,24 @@ struct exportDescrBuildings }; //Size: 0x0350 +class eopHiddenResources +{ +public: + static int getHiddenResourceIndex(const std::string& name); + static void addHiddenResource(const std::string& name); + static void addHiddenResourceWithId(const std::string& name, int id); + static void addHiddenResourceToRegion(int regionId, const std::string& name); + static void addHiddenResourceToRegionIndex(const std::string& name, int id); + static bool hasHiddenResource(int regionId, int id); + static bool isInitialized() { return m_Initialized; } + static void setInitialized(const bool value) { m_Initialized = value; } + static void initialize(); +private: + static std::array, 200> m_HiddenResources; + static unordered_map m_HiddenResourcesLookup; + static unordered_map> m_NamesToIndexes; + static bool m_Initialized; +}; namespace eopBuildings { @@ -562,6 +580,8 @@ namespace eopBuildings #pragma endregion }; + + namespace buildingHelpers { void addToLua(sol::state& luaState); diff --git a/M2TWEOP Code/M2TWEOP library/types/strategyMap.h b/M2TWEOP Code/M2TWEOP library/types/strategyMap.h index 19c1b075..6e5f0d02 100644 --- a/M2TWEOP Code/M2TWEOP library/types/strategyMap.h +++ b/M2TWEOP Code/M2TWEOP library/types/strategyMap.h @@ -305,6 +305,34 @@ struct coastLine int regionsNum; }; +struct mapRegion +{ + char* name; //0x0000 + int nameHash; //0x0004 + uint8_t blue; //0x0008 + uint8_t green; //0x0009 + uint8_t red; //0x000A + uint8_t pad; //0x000B + UNICODE_STRING*** regionName; //0x000C + char* legio; //0x0010 + int legioHash; //0x0014 + char* settlementName; //0x0018 + int settlementNameHash; //0x001C + UNICODE_STRING*** localSettlementName; //0x0020 + char* rebelName; //0x0024 + int rebelNameHash; //0x0028 + int factionId; //0x002C + uint32_t padResMask; //0x0030 + uint32_t resourceMask; //0x0034 + uint32_t padHResMask; //0x0038 + uint32_t hiddenResourceMask1; //0x003C + uint32_t hiddenResourceMask2; //0x0040 + uint32_t padHResMask2; //0x0044 + int triumph; //0x0048 + int baseFarm; //0x004C + float* religions; //0x0050 +}; + struct gameStratRect { int minX;