diff --git a/.gitmodules b/.gitmodules index 2480c9c..e752491 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "genieutils"] - path = genieutils + path = 3rd-party/genieutils url = https://github.com/Tapsa/genieutils.git [submodule "pcrio"] - path = pcrio + path = 3rd-party/pcrio url = https://github.com/Tapsa/pcrio.git diff --git a/genieutils b/3rd-party/genieutils similarity index 100% rename from genieutils rename to 3rd-party/genieutils diff --git a/pcrio b/3rd-party/pcrio similarity index 100% rename from pcrio rename to 3rd-party/pcrio diff --git a/CMakeLists.txt b/CMakeLists.txt index f17787c..cde099d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,22 @@ cmake_minimum_required(VERSION 3.10) project(create-data-mod VERSION 1.0) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++") -add_subdirectory(genieutils EXCLUDE_FROM_ALL) +add_subdirectory(3rd-party/genieutils EXCLUDE_FROM_ALL) include_directories( - "genieutils/include" + "3rd-party/genieutils/include" + "." ) -add_executable(create-data-mod create-data-mod.cpp patches.cpp ids.h) +add_executable( + create-data-mod + create-data-mod.cpp + patches/community_games.cpp + patches/exploding_villagers.cpp + patches/flying_dutchman.cpp + patches/kidnap.cpp + patches/no_wall.cpp + patches/random_costs.cpp + patches/duplicate_techs.cpp + ids.h +) +set_property(TARGET create-data-mod PROPERTY CXX_STANDARD 17) target_link_libraries(create-data-mod genieutils) diff --git a/README.md b/README.md index 07e34cf..8920ed1 100644 --- a/README.md +++ b/README.md @@ -29,37 +29,8 @@ git clone --recurse-submodules https://github.com/SiegeEngineers/auto-mods.git cd auto-mods ``` -### Installing dependencies - -You'll need: -- `cmake` -- `gcc`, `g++` -- `libboost-iostreams-dev` -- `libboost-program-options` -- `zlib` - -#### Dependencies on Ubuntu (e.g. WSL) - -```sh -sudo apt update -sudo apt install --fix-missing gcc g++ cmake \ -libboost-iostreams-dev libboost-program-options-dev \ -zlib1g-dev -``` - -### Compiling - -Inside the `repository root` use the following commands: - -```sh -./patchGenieutils.sh -mkdir build -cd build -cmake .. -cmake --build . -``` - -You should now have an executable `create-data-mod` in the `build` folder. Hooray! +Please read the [build instructions](./docs/build-instructions.md) +for your corresponding platform. ## Usage diff --git a/create-data-mod.cpp b/create-data-mod.cpp index e291e42..a5874a5 100644 --- a/create-data-mod.cpp +++ b/create-data-mod.cpp @@ -1,5 +1,11 @@ #include "genie/dat/DatFile.h" -#include "patches.h" +#include "patches/community_games.h" +#include "patches/duplicate_techs.h" +#include "patches/exploding_villagers.h" +#include "patches/flying_dutchman.h" +#include "patches/kidnap.h" +#include "patches/no_wall.h" +#include "patches/random_costs.h" #include using namespace std; diff --git a/docs/build-instructions.md b/docs/build-instructions.md new file mode 100644 index 0000000..1552931 --- /dev/null +++ b/docs/build-instructions.md @@ -0,0 +1,62 @@ +# Build instructions + +## Dependencies + +### Installing dependencies + +You'll need: +- `cmake` +- `gcc`, `g++` +- `libiconv` +- `libboost-iostreams-dev` +- `libboost-program-options` +- `zlib` + + +### MSYS2 (MingW64) on Windows +Download and follow the install instructions for [MSYS2](https://www.msys2.org/) + - if you have [Chocolatey](chocolatey.org/) installed you can install MSYS2 as follows + + `choco install msys2` + +After installing start a MSYS2-shell from `/msys2_shell.cmd` + +Update the preinstalled packages: `pacman -Syuu` + +Install gcc: `pacman -Syu --needed mingw-w64-x86_64-gcc ` + +And these dependencies: +`pacman -Syu --needed mingw-w64-x86_64-cmake mingw-w64-x86_64-make mingw-w64-x86_64-libiconv mingw-w64-x86_64-boost mingw-w64-x86_64-zlib` + +### WSL (Ubuntu) on Windows + +Please [install WSL on your Windows 10 System](https://docs.microsoft.com/en-us/windows/wsl/install-win10), install the Ubuntu distribution from the Microsoft Store and continue with [Ubuntu](#ubuntu) + +### Ubuntu + +```sh +sudo apt update +sudo apt install --fix-missing gcc g++ cmake \ +libboost-iostreams-dev libboost-program-options-dev \ +zlib1g-dev +``` + +## Compiling + +Inside the `repository root` use the following commands: + +```sh +./patchGenieutils.sh +mkdir build +cd build +cmake .. +// Note: if you are using MingW64 use the following command instead +// cmake -G "CodeBlocks - MinGW Makefiles" .. +// and continue with +cmake --build . +``` + + + + +You should now have an executable `create-data-mod` in the `build` folder. Hooray! diff --git a/patchGenieutils.sh b/patchGenieutils.sh index 18723dc..4590307 100755 --- a/patchGenieutils.sh +++ b/patchGenieutils.sh @@ -1,5 +1,5 @@ #! /bin/bash -sed -i 's/#set(Boost_USE_STATIC_LIBS ON)/set(Boost_USE_STATIC_LIBS ON)/' genieutils/CMakeLists.txt -sed -i 's/add_library(${Genieutils_LIBRARY} SHARED/add_library(${Genieutils_LIBRARY} STATIC/' genieutils/CMakeLists.txt -sed -i 's/target_link_libraries(${Genieutils_LIBRARY} ${ZLIB_LIBRARIES} ${Boost_LIBRARIES} ${ICONV_LIBRARIES})/target_link_libraries(${Genieutils_LIBRARY} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${ICONV_LIBRARIES})/' genieutils/CMakeLists.txt +sed -i 's/#set(Boost_USE_STATIC_LIBS ON)/set(Boost_USE_STATIC_LIBS ON)/' 3rd-party/genieutils/CMakeLists.txt +sed -i 's/add_library(${Genieutils_LIBRARY} SHARED/add_library(${Genieutils_LIBRARY} STATIC/' 3rd-party/genieutils/CMakeLists.txt +sed -i 's/target_link_libraries(${Genieutils_LIBRARY} ${ZLIB_LIBRARIES} ${Boost_LIBRARIES} ${ICONV_LIBRARIES})/target_link_libraries(${Genieutils_LIBRARY} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${ICONV_LIBRARIES})/' 3rd-party/genieutils/CMakeLists.txt diff --git a/patches.cpp b/patches.cpp deleted file mode 100644 index 26f627e..0000000 --- a/patches.cpp +++ /dev/null @@ -1,765 +0,0 @@ -#include "genie/dat/DatFile.h" -#include "genie/dat/TechageEffect.h" -#include "patches.h" -#include "ids.h" -#include -#include -#include -#include - -using namespace std; - - -typedef genie::ResourceUsage ResourceCost; -typedef genie::ResourceUsage ResearchResourceCost; - -void copyResourceCostAt(int unitId, int index, vector &target, const genie::Civ &civ); - -bool bothRequirePopulationHeadroom(int unitId, vector &resourceCosts, const genie::Civ &civ); - -bool isNaturalResourceCost(const ResourceCost &cost); - -bool isNaturalResearchResourceCost(const ResearchResourceCost &cost); - -bool hasNaturalResourceCost(const genie::Unit &unit); - -bool hasNaturalResearchResourceCost(vector costs); - -string costToString(const vector &costs); - -string costToString(const vector &costs); - -int getSumOfNaturalResourceCosts(const vector& resourceCosts); - -ResearchResourceCost toResearchResourceCost(const ResourceCost &resourceCost); - -ResourceCost toResourceCost(const ResearchResourceCost &researchResourceCost); - -vector toResearchResourceCosts(const vector &resourceCosts); - -vector toResourceCosts(const vector &researchResourceCosts); - - -void configureCommunityGamesMod(genie::DatFile *df) { - addPopulationCostToBombardTower(df); - addGreatHallTech(df); - addElitePetard(df); - modifyCaravanCost(df, 800, 200); - makeTreesContain200Wood(df); -} - -void addPopulationCostToBombardTower(genie::DatFile *df) { - cout << "Adding population cost to bombard towers of all civs" << endl; - for (genie::Civ &civ : df->Civs) { - genie::Unit &bombard_tower = civ.Units.at(BOMBARD_TOWER); - genie::ResourceUsage &resourceCosts = bombard_tower.Creatable.ResourceCosts.at(2); - resourceCosts.Type = TYPE_POPULATION_HEADROOM; - resourceCosts.Amount = 1; - resourceCosts.Flag = 0; - - bombard_tower.ResourceStorages.at(0).Type = TYPE_POPULATION_HEADROOM; - bombard_tower.ResourceStorages.at(0).Amount = -1; - bombard_tower.ResourceStorages.at(0).Flag = 2; - - bombard_tower.ResourceStorages.at(1).Type = TYPE_CURRENT_POPULATION; - bombard_tower.ResourceStorages.at(1).Amount = 1; - bombard_tower.ResourceStorages.at(1).Flag = 2; - - bombard_tower.ResourceStorages.at(2).Type = TYPE_TOTAL_UNITS_OWNED; - bombard_tower.ResourceStorages.at(2).Amount = 1; - bombard_tower.ResourceStorages.at(2).Flag = 1; - } -} - -void addGreatHallTech(genie::DatFile *df) { - cout << "Adding great hall tech" << endl; - auto effectCommand = new genie::EffectCommand(); - effectCommand->Type = 1; // Resource Modifier - effectCommand->A = 32; // Resource: Bonus Population Cap - effectCommand->B = 1; // Mode: +/- - effectCommand->D = 10; // Amount +/- - - auto effect = new genie::Effect(); - effect->Name = "Great Hall"; - effect->EffectCommands.push_back(*effectCommand); - - df->Effects.push_back(*effect); - size_t greatHallEffectId = df->Effects.size() - 1; - - auto tech = new genie::Tech(); - tech->Name = "The Great Hall"; - tech->RequiredTechs.push_back(BOMBARD_TOWER_TECH); - tech->ResearchTime = 5; - tech->IconID = 103; - tech->ButtonID = 1; - tech->EffectID = greatHallEffectId; - tech->ResearchLocation = BOMBARD_TOWER; - - tech->ResourceCosts.at(0).Type = TYPE_WOOD; - tech->ResourceCosts.at(0).Amount = 400; - tech->ResourceCosts.at(0).Flag = 1; - - tech->ResourceCosts.at(1).Type = TYPE_GOLD; - tech->ResourceCosts.at(1).Amount = 600; - tech->ResourceCosts.at(1).Flag = 1; - - df->Techs.push_back(*tech); -} - -void addElitePetard(genie::DatFile *df) { - int elitePetardId = -1; - for (genie::Civ &civ : df->Civs) { - genie::Unit elitePetard = civ.Units.at(PETARD); - elitePetard.Enabled = 0; - elitePetard.Name = "Elite Petard"; - elitePetard.HitPoints = 60; - elitePetard.Speed = 1.05; - elitePetard.Type50.DisplayedAttack = 45; - elitePetard.Type50.BlastWidth = 1.5; - elitePetard.Type50.BlastAttackLevel = 1; - elitePetard.Type50.Attacks.at(0).Amount = 150; - elitePetard.Type50.Attacks.at(1).Amount = 650; - elitePetard.Type50.Attacks.at(2).Amount = 45; - elitePetard.Type50.Attacks.at(3).Amount = 70; - elitePetard.Type50.Attacks.at(4).Amount = 1000; - elitePetard.Type50.Armours.at(1).Amount = 3; - elitePetard.Creatable.DisplayedPierceArmour = 3; - elitePetardId = civ.Units.size(); - cout << "Adding elite petard for civ " << civ.Name << " with ID " << elitePetardId << endl; - civ.Units.push_back(elitePetard); - civ.UnitPointers.push_back(1); - } - - auto effectCommand = new genie::EffectCommand(); - effectCommand->Type = 3; // Upgrade Unit - effectCommand->A = PETARD; - effectCommand->B = elitePetardId; - - auto effect = new genie::Effect(); - effect->Name = "Elite Petard"; - effect->EffectCommands.push_back(*effectCommand); - int elitePetardEffectId = df->Effects.size(); - df->Effects.push_back(*effect); - - auto tech = new genie::Tech(); - tech->Name = "Elite Petard"; - tech->RequiredTechs.push_back(CHEMISTRY); - tech->RequiredTechCount = 1; - tech->ResearchTime = 40; - tech->IconID = 105; - tech->ButtonID = 9; - tech->EffectID = elitePetardEffectId; - tech->ResearchLocation = CASTLE; - - tech->ResourceCosts.at(0).Type = TYPE_FOOD; - tech->ResourceCosts.at(0).Amount = 450; - tech->ResourceCosts.at(0).Flag = 1; - - tech->ResourceCosts.at(1).Type = TYPE_GOLD; - tech->ResourceCosts.at(1).Amount = 450; - tech->ResourceCosts.at(1).Flag = 1; - - cout << "Adding Elite Petard Tech with id " << df->Techs.size() << endl; - df->Techs.push_back(*tech); -} - -void modifyCaravanCost(genie::DatFile *df, int amountFood, int amountGold) { - cout << "Setting the cost of Caravan (" << TECH_CARAVAN << ") to " << amountFood << " Food, " << amountGold - << " Gold" << endl; - genie::Tech &caravan = df->Techs.at(TECH_CARAVAN); - caravan.ResourceCosts.at(0).Type = TYPE_FOOD; - caravan.ResourceCosts.at(0).Amount = amountFood; - caravan.ResourceCosts.at(0).Flag = 1; - - caravan.ResourceCosts.at(1).Type = TYPE_GOLD; - caravan.ResourceCosts.at(1).Amount = amountGold; - caravan.ResourceCosts.at(1).Flag = 1; -} - -void makeTreesContain200Wood(genie::DatFile *df) { - for (genie::Civ &civ : df->Civs) { - for (genie::Unit &unit: civ.Units) { - for (auto storage : unit.ResourceStorages) { - if (storage.Type == TYPE_WOOD && storage.Amount > 50) { - cout << "Setting amount of wood in " << unit.Name << " (" << unit.ID << ") to 200" << endl; - storage.Amount = 200; - } - } - } - } -} - -void configureExplodingVillagers(genie::DatFile *df) { - set villagers = { - ID_FISHING_SHIP, - ID_TRADE_COG, - ID_TRADE_CART_EMPTY, - ID_TRADE_CART_FULL, - ID_VILLAGER_BASE_M, - ID_VILLAGER_BASE_F, - ID_VILLAGER_FARMER_M, - ID_VILLAGER_FARMER_F, - ID_VILLAGER_SHEPHERD_M, - ID_VILLAGER_SHEPHERD_F, - ID_VILLAGER_FORAGER_M, - ID_VILLAGER_FORAGER_F, - ID_VILLAGER_HUNTER_M, - ID_VILLAGER_HUNTER_F, - ID_VILLAGER_FISHER_M, - ID_VILLAGER_FISHER_F, - ID_VILLAGER_WOOD_M, - ID_VILLAGER_WOOD_F, - ID_VILLAGER_GOLD_M, - ID_VILLAGER_GOLD_F, - ID_VILLAGER_STONE_M, - ID_VILLAGER_STONE_F, - ID_VILLAGER_BUILDER_M, - ID_VILLAGER_BUILDER_F, - ID_VILLAGER_REPAIRER_M, - ID_VILLAGER_REPAIRER_F, - }; - - for (genie::Civ &civ : df->Civs) { - for (int villager_id : villagers) { - civ.Units.at(villager_id).DeadUnitID = ID_SABOTEUR; - cout << "Patched Villager unit " << villager_id << " for civ " << civ.Name << "\n"; - } - genie::Unit &saboteur = civ.Units.at(ID_SABOTEUR); - saboteur.HitPoints = 0; - saboteur.Type50.Attacks.at(0).Amount = 50; - saboteur.Type50.Attacks.at(1).Amount = 90; - saboteur.Type50.Attacks.at(2).Amount = 0; - saboteur.Type50.MaxRange = 2; - saboteur.Type50.BlastAttackLevel = 1; // cut trees - saboteur.TrainSound = -1; - saboteur.WwiseTrainSoundID = 0; // prevent melee unit train sound from playing - cout << "Patched Saboteur unit for civ " << civ.Name << "\n"; - } -} - -void duplicateTechs(genie::DatFile *df, int totalCount) { - - const list techsToDuplicate = { - YEOMEN, - EL_DORADO, - FUROR_CELTICA, - DRILL, - MAHOUTS, - TOWN_WATCH, - ZEALOTRY, - ARTILLERY, - CRENELLATIONS, - CROP_ROTATION, - HEAVY_PLOW, - HORSE_COLLAR, - GUILDS, - BANKING, - ATHEISM, - LOOM, - GARLAND_WARS, - HUSBANDRY, - FAITH, - CHEMISTRY, - CARAVAN, - BERSERKERGANG, - MASONRY, - ARCHITECTURE, - ROCKETRY, - TREADMILL_CRANE, - GOLD_MINING, - KATAPARUTO, - LOGISTICA, - GILLNETS, - FORGING, - IRON_CASTING, - SCALE_MAIL_ARMOR, - BLAST_FURNACE, - CHAIN_MAIL_ARMOR, - PLATE_MAIL_ARMOR, - PLATE_BARDING_ARMOR, - SCALE_BARDING_ARMOR, - CHAIN_BARDING_ARMOR, - BEARDED_AXE, - GOLD_SHAFT_MINING, - FLETCHING, - BODKIN_ARROW, - BRACER, - DOUBLE_BIT_AXE, - BOW_SAW, - PADDED_ARCHER_ARMOR, - LEATHER_ARCHER_ARMOR, - WHEELBARROW, - SQUIRES, - RING_ARCHER_ARMOR, - TWO_MAN_SAW, - BLOCK_PRINTING, - SANCTITY, - ILLUMINATION, - HAND_CART, - FERVOR, - STONE_MINING, - STONE_SHAFT_MINING, - TOWN_PATROL, - CONSCRIPTION, - SAPPERS, - SHIPWRIGHT, - CAREENING, - DRY_DOCK, - SIEGE_ENGINEERS, - HOARDINGS, - HEATED_SHOT, - BLOODLINES, - PARTHIAN_TACTICS, - THUMB_RING, - SUPREMACY, - HERBAL_MEDICINE, - SHINKICHON, - PERFUSION, - ATLATL, - WARWOLF, - GREAT_WALL, - CHIEFTAINS, - GREEK_FIRE, - STRONGHOLD, - YASAMA, - OBSIDIAN_ARROWS, - PANOKSEON, - KAMANDARAN, - IRONCLAD, - SIPAHI, - INQUISITION, - CHIVALRY, - PAVISE, - SILK_ROAD, - SULTANS, - SHATAGNI, - ORTHODOXY, - DRUZHINA, - RECURVE_BOW, - FABRIC_SHIELDS, - CARRACK, - ARQUEBUS, - ROYAL_HEIRS, - TORSION_ENGINES, - TIGUI, - FARIMBA, - KASBAH, - MAGHRABI_CAMELS, - ARSON, - ARROWSLITS, - TUSK_SWORDS, - DOUBLE_CROSSBOW, - FORCED_LEVY, - HOWDAH, - MANIPUR_CAVALRY, - CHATRAS, - PAPER_MONEY, - STIRRUPS, - BAGAINS, - SILK_ARMOR, - TIMURID_SIEGECRAFT, - STEPPE_HUSBANDRY, - CUMAN_MERCENARIES, - HILL_FORTS, - TOWER_SHIELDS, - SUPPLIES, - }; - - for (int techId: techsToDuplicate) { - genie::Tech tech = df->Techs.at(techId); - duplicateTech(df, tech, totalCount); - } - -} - -void duplicateTech(genie::DatFile *df, const genie::Tech &tech, int totalCount) { - for (int i = 0; i < (totalCount - 1); ++i) { - df->Techs.push_back(tech); - } - cout << "Added Tech '" << tech.Name << "' for a total of " << totalCount << " instances" << endl; -} - -void makeTransportShipsFly(genie::DatFile *df) { - for (genie::Civ &civ : df->Civs) { - genie::Unit &transport_ship = civ.Units.at(ID_TRANSPORT_SHIP); - transport_ship.FlyMode = 1; // true - transport_ship.TerrainRestriction = 0; // All - transport_ship.CollisionSize = {0, 0, 0}; // walk through everything, like flying - cout << "Patched Transport Ship unit for civ " << civ.Name << "\n"; - } -} - -void configureKidnap(genie::DatFile *df) { - const list scoutIds = { - ID_SCOUT, - ID_EAGLE_SCOUT, - }; - for (genie::Civ &civ : df->Civs) { - for (int scoutId : scoutIds) { - genie::Unit &scout = civ.Units.at(scoutId); - cout << "Setting Scout (" << scoutId << ") properties for civ " << civ.Name << endl; - scout.Type50.Attacks.clear(); - scout.Type50.DisplayedAttack = 0; - scout.GarrisonCapacity = 1; - scout.Bird.TaskList.erase(scout.Bird.TaskList.begin()); - - cout << "Adding Kidnap Task to scout (" << scoutId << ") for civ " << civ.Name << endl; - auto kidnapTask = new genie::Task(); - kidnapTask->ActionType = ACTION_KIDNAP_UNIT; - kidnapTask->ClassID = CLASS_CIVILIAN; - kidnapTask->WorkRange = 0.25; - kidnapTask->ProceedingGraphicID = 1966; // SCOUT_AN - kidnapTask->TargetDiplomacy = 2; - kidnapTask->GatherType = 2; - scout.Bird.TaskList.push_back(*kidnapTask); - - cout << "Adding Loot Task to scout (" << scoutId << ") for civ " << civ.Name << endl; - auto lootTask = new genie::Task(); - lootTask->ActionType = ACTION_LOOT; - lootTask->ClassID = CLASS_BUILDING; - lootTask->WorkRange = 0.25; - lootTask->ProceedingGraphicID = 1966; // SCOUT_AN - lootTask->TargetDiplomacy = 2; - lootTask->GatherType = 1; - scout.Bird.TaskList.push_back(*lootTask); - } - } -} - -void disableWalls(genie::DatFile *df) { - const list unitsToDisable = { - PALISADE_WALL, - }; - - const list techsToDisable = { - TECH_PALISADE_GATE, - TECH_STONE_WALLS, - }; - - const list techsToHide = { - TECH_FORTIFIED_WALL, - }; - - for (int unitId: unitsToDisable) { - cout << "Disabling unit with id " << unitId << " for all civs" << endl; - for (genie::Civ &civ : df->Civs) { - civ.Units.at(unitId).Enabled = 0; - } - } - - for (int techId: techsToDisable) { - genie::Tech *tech = &df->Techs.at(techId); - cout << "Disabling the effect of tech with id " << techId << " ('" << tech->Name << "')" << endl; - disableTechEffect(tech); - } - - for (int techId: techsToHide) { - genie::Tech *tech = &df->Techs.at(techId); - cout << "Disabling the research location of tech with id " << techId << " ('" << tech->Name << "')" << endl; - disableTechResearchLocation(tech); - } -} - -void disableTechEffect(genie::Tech *tech) { - tech->EffectID = -1; -} - -void disableTechResearchLocation(genie::Tech *tech) { - tech->ResearchLocation = -1; -} - -void preventRamsAndSiegeTowersFromBoardingTransportShips(genie::DatFile *df) { - for (genie::Civ &civ : df->Civs) { - for (genie::Unit &unit : civ.Units) { - if (unit.ID == ID_RAM || unit.ID == ID_CAPPED_RAM || unit.ID == ID_SIEGE_RAM || unit.ID == ID_SIEGE_TOWER) { - list toDelete; - for (int i = 0; i < unit.Bird.TaskList.size(); i++) { - genie::Task task = unit.Bird.TaskList.at(i); - if (task.ActionType == ACTION_TYPE_GARRISON && task.ClassID == CLASS_TRANSPORT_BOAT) { - toDelete.push_front(i); - } - } - - for (int i:toDelete) { - unit.Bird.TaskList.erase(unit.Bird.TaskList.begin() + i); - } - cout << "Patched unit " << unit.Name << " (" << unit.ID << ") unit for civ " << civ.Name << "\n"; - } - } - } -} - -ResearchResourceCost toResearchResourceCost(const ResourceCost &resourceCost) { - ResearchResourceCost researchResourceCost; - researchResourceCost.Type = resourceCost.Type; - researchResourceCost.Amount = resourceCost.Amount; - researchResourceCost.Flag = (bool) resourceCost.Flag; - return researchResourceCost; -} - -ResourceCost toResourceCost(const ResearchResourceCost &researchResourceCost) { - ResourceCost resourceCost; - resourceCost.Type = researchResourceCost.Type; - resourceCost.Amount = researchResourceCost.Amount; - resourceCost.Flag = (bool) researchResourceCost.Flag; - return resourceCost; -} - - -vector toResearchResourceCosts(const vector &resourceCosts) { - vector researchResourceCosts; - researchResourceCosts.reserve(resourceCosts.size()); - for (const ResourceCost &resourceCost : resourceCosts) { - researchResourceCosts.push_back(toResearchResourceCost(resourceCost)); - } - return researchResourceCosts; -} - -vector toResourceCosts(const vector &researchResourceCosts) { - vector resourceCosts; - resourceCosts.reserve(researchResourceCosts.size()); - for (const ResearchResourceCost &researchResourceCost : researchResourceCosts) { - resourceCosts.push_back(toResourceCost(researchResourceCost)); - } - return resourceCosts; -} - - -void jumbleCosts(genie::DatFile *df) { - vector unitIds; - for (genie::Unit unit : df->Civs.at(0).Units) { - if (hasNaturalResourceCost(unit)) { - unitIds.push_back(unit.ID); - } - } - - vector techIds; - size_t index = 0; - for (const genie::Tech &tech : df->Techs) { - vector resourceCopy = tech.ResourceCosts; - if (hasNaturalResearchResourceCost(resourceCopy)) { - techIds.push_back(index); - } - index++; - } - - vector> allTheCosts; - for (int unitId: unitIds) { - vector resourceCopy = df->Civs.at(0).Units.at(unitId).Creatable.ResourceCosts; - allTheCosts.push_back(resourceCopy); - } - - for (int techId: techIds) { - vector resourceCopy = toResourceCosts(df->Techs.at(techId).ResourceCosts); - allTheCosts.push_back(resourceCopy); - } - - for (int i = 0; i < 10; i++) { - unsigned int seed = std::random_device()(); - cout << "Seed for shuffling unit and tech costs is: " << to_string(seed) << endl; - shuffle(allTheCosts.begin(), allTheCosts.end(), std::mt19937(seed)); - - size_t costIndex = 0; - for (int techId: techIds) { - vector researchResourceCosts = toResearchResourceCosts(allTheCosts.at(costIndex)); - cout << "Setting cost of tech with id " << techId << " to " << costToString(researchResourceCosts) << endl; - df->Techs.at(techId).ResourceCosts = researchResourceCosts; - costIndex++; - } - for (int unitId: unitIds) { - vector &resourceCosts = allTheCosts.at(costIndex); - cout << "Setting cost of unit with id " << unitId << " to " << costToString(resourceCosts) << endl; - if (!bothRequirePopulationHeadroom(unitId, resourceCosts, df->Civs.at(0))) { - copyResourceCostAt(unitId, 2, resourceCosts, df->Civs.at(0)); - } - for (genie::Civ &civ : df->Civs) { - civ.Units.at(unitId).Creatable.ResourceCosts = resourceCosts; - } - costIndex++; - } - - int maleVillagerCost = getSumOfNaturalResourceCosts( - df->Civs.at(0).Units.at(ID_VILLAGER_BASE_M).Creatable.ResourceCosts); - int femaleVillagerCost = getSumOfNaturalResourceCosts( - df->Civs.at(0).Units.at(ID_VILLAGER_BASE_F).Creatable.ResourceCosts); - if (maleVillagerCost <= 200 && femaleVillagerCost <= 200) { - return; - } - cout << "Villagers are too expensive, reshuffling…" << endl; - } - cout << "Giving up, villagers stay expensive, sorry." << endl; -} - -void jumbleUnitCosts(genie::DatFile *df) { - vector unitIds; - - for (genie::Unit unit : df->Civs.at(0).Units) { - if (hasNaturalResourceCost(unit)) { - unitIds.push_back(unit.ID); - } - } - - vector> allTheCosts; - for (int unitId: unitIds) { - vector resourceCopy = df->Civs.at(0).Units.at(unitId).Creatable.ResourceCosts; - allTheCosts.push_back(resourceCopy); - } - - for (int i = 0; i < 10; i++) { - unsigned int seed = std::random_device()(); - cout << "Seed for shuffling unit costs is: " << to_string(seed) << endl; - shuffle(allTheCosts.begin(), allTheCosts.end(), std::mt19937(seed)); - - size_t index = 0; - for (int unitId: unitIds) { - vector &resourceCosts = allTheCosts.at(index); - cout << "Setting cost of unit with id " << unitId << " to " << costToString(resourceCosts) << endl; - if (!bothRequirePopulationHeadroom(unitId, resourceCosts, df->Civs.at(0))) { - copyResourceCostAt(unitId, 2, resourceCosts, df->Civs.at(0)); - } - for (genie::Civ &civ : df->Civs) { - civ.Units.at(unitId).Creatable.ResourceCosts = resourceCosts; - } - index++; - } - - int maleVillagerCost = getSumOfNaturalResourceCosts( - df->Civs.at(0).Units.at(ID_VILLAGER_BASE_M).Creatable.ResourceCosts); - int femaleVillagerCost = getSumOfNaturalResourceCosts( - df->Civs.at(0).Units.at(ID_VILLAGER_BASE_F).Creatable.ResourceCosts); - if (maleVillagerCost <= 200 && femaleVillagerCost <= 200) { - return; - } - cout << "Villagers are too expensive, reshuffling…" << endl; - } - cout << "Giving up, villagers stay expensive, sorry." << endl; -} - -void jumbleTechCosts(genie::DatFile *df) { - vector techIds; - - vector> allTheCosts; - size_t index = 0; - for (const genie::Tech &tech : df->Techs) { - vector resourceCopy = tech.ResourceCosts; - if (hasNaturalResearchResourceCost(resourceCopy)) { - allTheCosts.push_back(resourceCopy); - techIds.push_back(index); - } - index++; - } - - unsigned int seed = std::random_device()(); - cout << "Seed for shuffling tech costs is: " << to_string(seed) << endl; - shuffle(allTheCosts.begin(), allTheCosts.end(), std::mt19937(seed)); - - index = 0; - for (size_t techId : techIds) { - vector &resourceCosts = allTheCosts.at(index); - cout << "Setting cost of tech with id " << techId << " to " << costToString(resourceCosts) << endl; - df->Techs.at(techId).ResourceCosts = resourceCosts; - index++; - } - -} - -int getSumOfNaturalResourceCosts(const vector& resourceCosts) { - int16_t sum = 0; - for (const ResourceCost& cost : resourceCosts) { - if (cost.Type > -1 && cost.Type < 4) { - sum += cost.Amount; - } - } - return sum; -} - -bool isNaturalResourceCost(const ResourceCost &cost) { - return cost.Type != -1 && cost.Type < 4 && cost.Amount > 0; -} - -bool isNaturalResearchResourceCost(const ResearchResourceCost &cost) { - return cost.Type != -1 && cost.Type < 4 && cost.Amount > 0; -} - -bool hasNaturalResourceCost(const genie::Unit &unit) { - vector costs = unit.Creatable.ResourceCosts; - return any_of(costs.begin(), costs.end(), isNaturalResourceCost); -} - -bool hasNaturalResearchResourceCost(vector costs) { - return any_of(costs.begin(), costs.end(), isNaturalResearchResourceCost); -} - -string costToString(const vector &costs) { - string s; - for (const ResourceCost &cost : costs) { - if (cost.Flag == 1) { - s += to_string(cost.Amount); - s += " "; - switch (cost.Type) { - case TYPE_FOOD: - s += "Food "; - break; - case TYPE_WOOD: - s += "Wood "; - break; - case TYPE_GOLD: - s += "Gold "; - break; - case TYPE_STONE: - s += "Stone "; - break; - case TYPE_POPULATION_HEADROOM: - s += "Pop "; - break; - default: - s += "vat?"; - } - } - } - return s; -} - -string costToString(const vector &costs) { - string s; - for (const ResearchResourceCost &cost : costs) { - if (cost.Flag == 1) { - s += to_string(cost.Amount); - s += " "; - switch (cost.Type) { - case TYPE_FOOD: - s += "Food "; - break; - case TYPE_WOOD: - s += "Wood "; - break; - case TYPE_GOLD: - s += "Gold "; - break; - case TYPE_STONE: - s += "Stone "; - break; - case TYPE_POPULATION_HEADROOM: - s += "Pop "; - break; - default: - s += "vat?"; - } - } - } - return s; -} - -bool bothRequirePopulationHeadroom(int unitId, vector &resourceCosts, const genie::Civ &civ) { - return ((civ.Units.at(unitId).Creatable.ResourceCosts.at(2).Type == TYPE_POPULATION_HEADROOM && - resourceCosts.at(2).Type == TYPE_POPULATION_HEADROOM) || - (civ.Units.at(unitId).Creatable.ResourceCosts.at(2).Type != TYPE_POPULATION_HEADROOM && - resourceCosts.at(2).Type != TYPE_POPULATION_HEADROOM)); -} - -void copyResourceCostAt(int unitId, int index, vector &target, const genie::Civ &civ) { - genie::ResourceUsage source = civ.Units.at(unitId).Creatable.ResourceCosts.at(index); - target.at(index).Type = source.Type; - target.at(index).Amount = source.Amount; - target.at(index).Flag = source.Flag; -} diff --git a/patches.h b/patches.h deleted file mode 100644 index a5dd3c2..0000000 --- a/patches.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CREATE_DATA_MOD_PATCHES_H -#define CREATE_DATA_MOD_PATCHES_H - -void configureCommunityGamesMod(genie::DatFile *df); -void configureExplodingVillagers(genie::DatFile *df); -void makeTransportShipsFly(genie::DatFile *df); -void duplicateTechs(genie::DatFile *df, int totalCount); -void configureKidnap(genie::DatFile *df); -void disableWalls(genie::DatFile *df); -void preventRamsAndSiegeTowersFromBoardingTransportShips(genie::DatFile *df); -void duplicateTech(genie::DatFile *df, const genie::Tech &tech, int totalCount); -void disableTechEffect(genie::Tech *tech); -void disableTechResearchLocation(genie::Tech *tech); -void addPopulationCostToBombardTower(genie::DatFile *df); -void addGreatHallTech(genie::DatFile *df); -void addElitePetard(genie::DatFile *df); -void modifyCaravanCost(genie::DatFile *df, int amountFood, int amountGold); -void makeTreesContain200Wood(genie::DatFile *df); -void jumbleCosts(genie::DatFile *df); -void jumbleUnitCosts(genie::DatFile *df); -void jumbleTechCosts(genie::DatFile *df); - -#endif //CREATE_DATA_MOD_PATCHES_H diff --git a/patches/community_games.cpp b/patches/community_games.cpp new file mode 100644 index 0000000..acb689a --- /dev/null +++ b/patches/community_games.cpp @@ -0,0 +1,153 @@ +#include +#include "genie/dat/DatFile.h" +#include "ids.h" + + +void addPopulationCostToBombardTower(genie::DatFile *df) { + std::cout << "Adding population cost to bombard towers of all civs" << std::endl; + for (genie::Civ &civ : df->Civs) { + genie::Unit &bombard_tower = civ.Units.at(BOMBARD_TOWER); + genie::ResourceUsage &resourceCosts = bombard_tower.Creatable.ResourceCosts.at(2); + resourceCosts.Type = TYPE_POPULATION_HEADROOM; + resourceCosts.Amount = 1; + resourceCosts.Flag = 0; + + bombard_tower.ResourceStorages.at(0).Type = TYPE_POPULATION_HEADROOM; + bombard_tower.ResourceStorages.at(0).Amount = -1; + bombard_tower.ResourceStorages.at(0).Flag = 2; + + bombard_tower.ResourceStorages.at(1).Type = TYPE_CURRENT_POPULATION; + bombard_tower.ResourceStorages.at(1).Amount = 1; + bombard_tower.ResourceStorages.at(1).Flag = 2; + + bombard_tower.ResourceStorages.at(2).Type = TYPE_TOTAL_UNITS_OWNED; + bombard_tower.ResourceStorages.at(2).Amount = 1; + bombard_tower.ResourceStorages.at(2).Flag = 1; + } +} + +void addGreatHallTech(genie::DatFile *df) { + std::cout << "Adding great hall tech" << std::endl; + auto effectCommand = new genie::EffectCommand(); + effectCommand->Type = 1; // Resource Modifier + effectCommand->A = 32; // Resource: Bonus Population Cap + effectCommand->B = 1; // Mode: +/- + effectCommand->D = 10; // Amount +/- + + auto effect = new genie::Effect(); + effect->Name = "Great Hall"; + effect->EffectCommands.push_back(*effectCommand); + + df->Effects.push_back(*effect); + size_t greatHallEffectId = df->Effects.size() - 1; + + auto tech = new genie::Tech(); + tech->Name = "The Great Hall"; + tech->RequiredTechs.push_back(BOMBARD_TOWER_TECH); + tech->ResearchTime = 5; + tech->IconID = 103; + tech->ButtonID = 1; + tech->EffectID = greatHallEffectId; + tech->ResearchLocation = BOMBARD_TOWER; + + tech->ResourceCosts.at(0).Type = TYPE_WOOD; + tech->ResourceCosts.at(0).Amount = 400; + tech->ResourceCosts.at(0).Flag = 1; + + tech->ResourceCosts.at(1).Type = TYPE_GOLD; + tech->ResourceCosts.at(1).Amount = 600; + tech->ResourceCosts.at(1).Flag = 1; + + df->Techs.push_back(*tech); +} + +void addElitePetard(genie::DatFile *df) { + int elitePetardId = -1; + for (genie::Civ &civ : df->Civs) { + genie::Unit elitePetard = civ.Units.at(PETARD); + elitePetard.Enabled = 0; + elitePetard.Name = "Elite Petard"; + elitePetard.HitPoints = 60; + elitePetard.Speed = 1.05; + elitePetard.Type50.DisplayedAttack = 45; + elitePetard.Type50.BlastWidth = 1.5; + elitePetard.Type50.BlastAttackLevel = 1; + elitePetard.Type50.Attacks.at(0).Amount = 150; + elitePetard.Type50.Attacks.at(1).Amount = 650; + elitePetard.Type50.Attacks.at(2).Amount = 45; + elitePetard.Type50.Attacks.at(3).Amount = 70; + elitePetard.Type50.Attacks.at(4).Amount = 1000; + elitePetard.Type50.Armours.at(1).Amount = 3; + elitePetard.Creatable.DisplayedPierceArmour = 3; + elitePetardId = civ.Units.size(); + std::cout << "Adding elite petard for civ " << civ.Name << " with ID " << elitePetardId << std::endl; + civ.Units.push_back(elitePetard); + civ.UnitPointers.push_back(1); + } + + auto effectCommand = new genie::EffectCommand(); + effectCommand->Type = 3; // Upgrade Unit + effectCommand->A = PETARD; + effectCommand->B = elitePetardId; + + auto effect = new genie::Effect(); + effect->Name = "Elite Petard"; + effect->EffectCommands.push_back(*effectCommand); + int elitePetardEffectId = df->Effects.size(); + df->Effects.push_back(*effect); + + auto tech = new genie::Tech(); + tech->Name = "Elite Petard"; + tech->RequiredTechs.push_back(CHEMISTRY); + tech->RequiredTechCount = 1; + tech->ResearchTime = 40; + tech->IconID = 105; + tech->ButtonID = 9; + tech->EffectID = elitePetardEffectId; + tech->ResearchLocation = CASTLE; + + tech->ResourceCosts.at(0).Type = TYPE_FOOD; + tech->ResourceCosts.at(0).Amount = 450; + tech->ResourceCosts.at(0).Flag = 1; + + tech->ResourceCosts.at(1).Type = TYPE_GOLD; + tech->ResourceCosts.at(1).Amount = 450; + tech->ResourceCosts.at(1).Flag = 1; + + std::cout << "Adding Elite Petard Tech with id " << df->Techs.size() << std::endl; + df->Techs.push_back(*tech); +} + +void modifyCaravanCost(genie::DatFile *df, int amountFood, int amountGold) { + std::cout << "Setting the cost of Caravan (" << TECH_CARAVAN << ") to " << amountFood << " Food, " << amountGold + << " Gold" << std::endl; + genie::Tech &caravan = df->Techs.at(TECH_CARAVAN); + caravan.ResourceCosts.at(0).Type = TYPE_FOOD; + caravan.ResourceCosts.at(0).Amount = amountFood; + caravan.ResourceCosts.at(0).Flag = 1; + + caravan.ResourceCosts.at(1).Type = TYPE_GOLD; + caravan.ResourceCosts.at(1).Amount = amountGold; + caravan.ResourceCosts.at(1).Flag = 1; +} + +void makeTreesContain200Wood(genie::DatFile *df) { + for (genie::Civ &civ : df->Civs) { + for (genie::Unit &unit: civ.Units) { + for (auto storage : unit.ResourceStorages) { + if (storage.Type == TYPE_WOOD && storage.Amount > 50) { + std::cout << "Setting amount of wood in " << unit.Name << " (" << unit.ID << ") to 200" << std::endl; + storage.Amount = 200; + } + } + } + } +} + +void configureCommunityGamesMod(genie::DatFile *df) { + addPopulationCostToBombardTower(df); + addGreatHallTech(df); + addElitePetard(df); + modifyCaravanCost(df, 800, 200); + makeTreesContain200Wood(df); +} diff --git a/patches/community_games.h b/patches/community_games.h new file mode 100644 index 0000000..3c058fb --- /dev/null +++ b/patches/community_games.h @@ -0,0 +1,9 @@ +#ifndef COMMUNITY_GAMES_H +#define COMMUNITY_GAMES_H + +#include "genie/dat/DatFile.h" + + +void configureCommunityGamesMod(genie::DatFile *df); + +#endif // COMMUNITY_GAMES_H diff --git a/patches/duplicate_techs.cpp b/patches/duplicate_techs.cpp new file mode 100644 index 0000000..6bfda7f --- /dev/null +++ b/patches/duplicate_techs.cpp @@ -0,0 +1,146 @@ +#include +#include +#include "genie/dat/DatFile.h" +#include "ids.h" + + +void duplicateTech(genie::DatFile *df, const genie::Tech &tech, int totalCount) { + for (int i = 0; i < (totalCount - 1); ++i) { + df->Techs.push_back(tech); + } + std::cout << "Added Tech '" << tech.Name << "' for a total of " << totalCount << " instances" << std::endl; +} + +void duplicateTechs(genie::DatFile *df, int totalCount) { + const std::list techsToDuplicate = { + YEOMEN, + EL_DORADO, + FUROR_CELTICA, + DRILL, + MAHOUTS, + TOWN_WATCH, + ZEALOTRY, + ARTILLERY, + CRENELLATIONS, + CROP_ROTATION, + HEAVY_PLOW, + HORSE_COLLAR, + GUILDS, + BANKING, + ATHEISM, + LOOM, + GARLAND_WARS, + HUSBANDRY, + FAITH, + CHEMISTRY, + CARAVAN, + BERSERKERGANG, + MASONRY, + ARCHITECTURE, + ROCKETRY, + TREADMILL_CRANE, + GOLD_MINING, + KATAPARUTO, + LOGISTICA, + GILLNETS, + FORGING, + IRON_CASTING, + SCALE_MAIL_ARMOR, + BLAST_FURNACE, + CHAIN_MAIL_ARMOR, + PLATE_MAIL_ARMOR, + PLATE_BARDING_ARMOR, + SCALE_BARDING_ARMOR, + CHAIN_BARDING_ARMOR, + BEARDED_AXE, + GOLD_SHAFT_MINING, + FLETCHING, + BODKIN_ARROW, + BRACER, + DOUBLE_BIT_AXE, + BOW_SAW, + PADDED_ARCHER_ARMOR, + LEATHER_ARCHER_ARMOR, + WHEELBARROW, + SQUIRES, + RING_ARCHER_ARMOR, + TWO_MAN_SAW, + BLOCK_PRINTING, + SANCTITY, + ILLUMINATION, + HAND_CART, + FERVOR, + STONE_MINING, + STONE_SHAFT_MINING, + TOWN_PATROL, + CONSCRIPTION, + SAPPERS, + SHIPWRIGHT, + CAREENING, + DRY_DOCK, + SIEGE_ENGINEERS, + HOARDINGS, + HEATED_SHOT, + BLOODLINES, + PARTHIAN_TACTICS, + THUMB_RING, + SUPREMACY, + HERBAL_MEDICINE, + SHINKICHON, + PERFUSION, + ATLATL, + WARWOLF, + GREAT_WALL, + CHIEFTAINS, + GREEK_FIRE, + STRONGHOLD, + YASAMA, + OBSIDIAN_ARROWS, + PANOKSEON, + KAMANDARAN, + IRONCLAD, + SIPAHI, + INQUISITION, + CHIVALRY, + PAVISE, + SILK_ROAD, + SULTANS, + SHATAGNI, + ORTHODOXY, + DRUZHINA, + RECURVE_BOW, + FABRIC_SHIELDS, + CARRACK, + ARQUEBUS, + ROYAL_HEIRS, + TORSION_ENGINES, + TIGUI, + FARIMBA, + KASBAH, + MAGHRABI_CAMELS, + ARSON, + ARROWSLITS, + TUSK_SWORDS, + DOUBLE_CROSSBOW, + FORCED_LEVY, + HOWDAH, + MANIPUR_CAVALRY, + CHATRAS, + PAPER_MONEY, + STIRRUPS, + BAGAINS, + SILK_ARMOR, + TIMURID_SIEGECRAFT, + STEPPE_HUSBANDRY, + CUMAN_MERCENARIES, + HILL_FORTS, + TOWER_SHIELDS, + SUPPLIES, + }; + + for (int techId: techsToDuplicate) { + genie::Tech tech = df->Techs.at(techId); + duplicateTech(df, tech, totalCount); + } + +} diff --git a/patches/duplicate_techs.h b/patches/duplicate_techs.h new file mode 100644 index 0000000..0a34054 --- /dev/null +++ b/patches/duplicate_techs.h @@ -0,0 +1,8 @@ +#ifndef DUPLICATE_TECHS_H +#define DUPLICATE_TECHS_H + +#include "genie/dat/DatFile.h" + +void duplicateTechs(genie::DatFile *df, int totalCount); + +#endif // DUPLICATE_TECHS_H diff --git a/patches/exploding_villagers.cpp b/patches/exploding_villagers.cpp new file mode 100644 index 0000000..1d44d04 --- /dev/null +++ b/patches/exploding_villagers.cpp @@ -0,0 +1,52 @@ +#include +#include "genie/dat/DatFile.h" +#include "ids.h" + + +void configureExplodingVillagers(genie::DatFile *df) { + std::set villagers = { + ID_FISHING_SHIP, + ID_TRADE_COG, + ID_TRADE_CART_EMPTY, + ID_TRADE_CART_FULL, + ID_VILLAGER_BASE_M, + ID_VILLAGER_BASE_F, + ID_VILLAGER_FARMER_M, + ID_VILLAGER_FARMER_F, + ID_VILLAGER_SHEPHERD_M, + ID_VILLAGER_SHEPHERD_F, + ID_VILLAGER_FORAGER_M, + ID_VILLAGER_FORAGER_F, + ID_VILLAGER_HUNTER_M, + ID_VILLAGER_HUNTER_F, + ID_VILLAGER_FISHER_M, + ID_VILLAGER_FISHER_F, + ID_VILLAGER_WOOD_M, + ID_VILLAGER_WOOD_F, + ID_VILLAGER_GOLD_M, + ID_VILLAGER_GOLD_F, + ID_VILLAGER_STONE_M, + ID_VILLAGER_STONE_F, + ID_VILLAGER_BUILDER_M, + ID_VILLAGER_BUILDER_F, + ID_VILLAGER_REPAIRER_M, + ID_VILLAGER_REPAIRER_F, + }; + + for (genie::Civ &civ : df->Civs) { + for (int villager_id : villagers) { + civ.Units.at(villager_id).DeadUnitID = ID_SABOTEUR; + std::cout << "Patched Villager unit " << villager_id << " for civ " << civ.Name << "\n"; + } + genie::Unit &saboteur = civ.Units.at(ID_SABOTEUR); + saboteur.HitPoints = 0; + saboteur.Type50.Attacks.at(0).Amount = 50; + saboteur.Type50.Attacks.at(1).Amount = 90; + saboteur.Type50.Attacks.at(2).Amount = 0; + saboteur.Type50.MaxRange = 2; + saboteur.Type50.BlastAttackLevel = 1; // cut trees + saboteur.TrainSound = -1; + saboteur.WwiseTrainSoundID = 0; // prevent melee unit train sound from playing + std::cout << "Patched Saboteur unit for civ " << civ.Name << "\n"; + } +} diff --git a/patches/exploding_villagers.h b/patches/exploding_villagers.h new file mode 100644 index 0000000..3b42a89 --- /dev/null +++ b/patches/exploding_villagers.h @@ -0,0 +1,8 @@ +#ifndef EXPLODING_VILLAGERS_H +#define EXPLODING_VILLAGERS_H + +#include "genie/dat/DatFile.h" + +void configureExplodingVillagers(genie::DatFile *df); + +#endif // EXPLODING_VILLAGERS_H diff --git a/patches/flying_dutchman.cpp b/patches/flying_dutchman.cpp new file mode 100644 index 0000000..d5abfac --- /dev/null +++ b/patches/flying_dutchman.cpp @@ -0,0 +1,14 @@ +#include +#include "genie/dat/DatFile.h" +#include "ids.h" + + +void makeTransportShipsFly(genie::DatFile *df) { + for (genie::Civ &civ : df->Civs) { + genie::Unit &transport_ship = civ.Units.at(ID_TRANSPORT_SHIP); + transport_ship.FlyMode = 1; // true + transport_ship.TerrainRestriction = 0; // All + transport_ship.CollisionSize = {0, 0, 0}; // walk through everything, like flying + std::cout << "Patched Transport Ship unit for civ " << civ.Name << "\n"; + } +} diff --git a/patches/flying_dutchman.h b/patches/flying_dutchman.h new file mode 100644 index 0000000..fd8c7f7 --- /dev/null +++ b/patches/flying_dutchman.h @@ -0,0 +1,8 @@ +#ifndef FLYING_DUTCHMAN_H +#define FLYING_DUTCHMAN_H + +#include "genie/dat/DatFile.h" + +void makeTransportShipsFly(genie::DatFile *df); + +#endif // FLYING_DUTCHMAN_H diff --git a/patches/kidnap.cpp b/patches/kidnap.cpp new file mode 100644 index 0000000..f2ea52c --- /dev/null +++ b/patches/kidnap.cpp @@ -0,0 +1,41 @@ +#include +#include "genie/dat/DatFile.h" +#include "ids.h" + + +void configureKidnap(genie::DatFile *df) { + const std::list scoutIds = { + ID_SCOUT, + ID_EAGLE_SCOUT, + }; + for (genie::Civ &civ : df->Civs) { + for (int scoutId : scoutIds) { + genie::Unit &scout = civ.Units.at(scoutId); + std::cout << "Setting Scout (" << scoutId << ") properties for civ " << civ.Name << std::endl; + scout.Type50.Attacks.clear(); + scout.Type50.DisplayedAttack = 0; + scout.GarrisonCapacity = 1; + scout.Bird.TaskList.erase(scout.Bird.TaskList.begin()); + + std::cout << "Adding Kidnap Task to scout (" << scoutId << ") for civ " << civ.Name << std::endl; + auto kidnapTask = new genie::Task(); + kidnapTask->ActionType = ACTION_KIDNAP_UNIT; + kidnapTask->ClassID = CLASS_CIVILIAN; + kidnapTask->WorkRange = 0.25; + kidnapTask->ProceedingGraphicID = 1966; // SCOUT_AN + kidnapTask->TargetDiplomacy = 2; + kidnapTask->GatherType = 2; + scout.Bird.TaskList.push_back(*kidnapTask); + + std::cout << "Adding Loot Task to scout (" << scoutId << ") for civ " << civ.Name << std::endl; + auto lootTask = new genie::Task(); + lootTask->ActionType = ACTION_LOOT; + lootTask->ClassID = CLASS_BUILDING; + lootTask->WorkRange = 0.25; + lootTask->ProceedingGraphicID = 1966; // SCOUT_AN + lootTask->TargetDiplomacy = 2; + lootTask->GatherType = 1; + scout.Bird.TaskList.push_back(*lootTask); + } + } +} diff --git a/patches/kidnap.h b/patches/kidnap.h new file mode 100644 index 0000000..fc74858 --- /dev/null +++ b/patches/kidnap.h @@ -0,0 +1,8 @@ +#ifndef KIDNAP_H +#define KIDNAP_H + +#include "genie/dat/DatFile.h" + +void configureKidnap(genie::DatFile *df); + +#endif // KIDNAP_H diff --git a/patches/no_wall.cpp b/patches/no_wall.cpp new file mode 100644 index 0000000..7e217ee --- /dev/null +++ b/patches/no_wall.cpp @@ -0,0 +1,46 @@ +#include +#include "genie/dat/DatFile.h" +#include "ids.h" + + +void disableTechEffect(genie::Tech *tech) { + tech->EffectID = -1; +} + +void disableTechResearchLocation(genie::Tech *tech) { + tech->ResearchLocation = -1; +} + +void disableWalls(genie::DatFile *df) { + const std::list unitsToDisable = { + PALISADE_WALL, + }; + + const std::list techsToDisable = { + TECH_PALISADE_GATE, + TECH_STONE_WALLS, + }; + + const std::list techsToHide = { + TECH_FORTIFIED_WALL, + }; + + for (int unitId: unitsToDisable) { + std::cout << "Disabling unit with id " << unitId << " for all civs" << std::endl; + for (genie::Civ &civ : df->Civs) { + civ.Units.at(unitId).Enabled = 0; + } + } + + for (int techId: techsToDisable) { + genie::Tech *tech = &df->Techs.at(techId); + std::cout << "Disabling the effect of tech with id " << techId << " ('" << tech->Name << "')" << std::endl; + disableTechEffect(tech); + } + + for (int techId: techsToHide) { + genie::Tech *tech = &df->Techs.at(techId); + std::cout << "Disabling the research location of tech with id " << techId << " ('" << tech->Name << "')" << std::endl; + disableTechResearchLocation(tech); + } +} diff --git a/patches/no_wall.h b/patches/no_wall.h new file mode 100644 index 0000000..93897cf --- /dev/null +++ b/patches/no_wall.h @@ -0,0 +1,8 @@ +#ifndef NO_WALL_H +#define NO_WALL_H + +#include "genie/dat/DatFile.h" + +void disableWalls(genie::DatFile *df); + +#endif // NO_WALL_H diff --git a/patches/random_costs.cpp b/patches/random_costs.cpp new file mode 100644 index 0000000..38a2566 --- /dev/null +++ b/patches/random_costs.cpp @@ -0,0 +1,284 @@ +#include +#include +#include +#include +#include "genie/dat/DatFile.h" +#include "ids.h" + + +typedef genie::ResourceUsage ResourceCost; +typedef genie::ResourceUsage ResearchResourceCost; + +bool isNaturalResourceCost(const ResourceCost &cost) { + return cost.Type != -1 && cost.Type < 4 && cost.Amount > 0; +} + +bool isNaturalResearchResourceCost(const ResearchResourceCost &cost) { + return cost.Type != -1 && cost.Type < 4 && cost.Amount > 0; +} + +bool hasNaturalResourceCost(const genie::Unit &unit) { + std::vector costs = unit.Creatable.ResourceCosts; + return std::any_of(costs.begin(), costs.end(), isNaturalResourceCost); +} + +bool hasNaturalResearchResourceCost(std::vector costs) { + return std::any_of(costs.begin(), costs.end(), isNaturalResearchResourceCost); +} + +int getSumOfNaturalResourceCosts(const std::vector& resourceCosts) { + int16_t sum = 0; + for (const ResourceCost& cost : resourceCosts) { + if (cost.Type > -1 && cost.Type < 4) { + sum += cost.Amount; + } + } + return sum; +} + +ResearchResourceCost toResearchResourceCost(const ResourceCost &resourceCost) { + ResearchResourceCost researchResourceCost; + researchResourceCost.Type = resourceCost.Type; + researchResourceCost.Amount = resourceCost.Amount; + researchResourceCost.Flag = (bool) resourceCost.Flag; + return researchResourceCost; +} + +ResourceCost toResourceCost(const ResearchResourceCost &researchResourceCost) { + ResourceCost resourceCost; + resourceCost.Type = researchResourceCost.Type; + resourceCost.Amount = researchResourceCost.Amount; + resourceCost.Flag = (bool) researchResourceCost.Flag; + return resourceCost; +} + + +std::vector toResearchResourceCosts(const std::vector &resourceCosts) { + std::vector researchResourceCosts; + researchResourceCosts.reserve(resourceCosts.size()); + for (const ResourceCost &resourceCost : resourceCosts) { + researchResourceCosts.push_back(toResearchResourceCost(resourceCost)); + } + return researchResourceCosts; +} + +std::vector toResourceCosts(const std::vector &researchResourceCosts) { + std::vector resourceCosts; + resourceCosts.reserve(researchResourceCosts.size()); + for (const ResearchResourceCost &researchResourceCost : researchResourceCosts) { + resourceCosts.push_back(toResourceCost(researchResourceCost)); + } + return resourceCosts; +} + +std::string costToString(const std::vector &costs) { + std::string s; + for (const ResourceCost &cost : costs) { + if (cost.Flag == 1) { + s += std::to_string(cost.Amount); + s += " "; + switch (cost.Type) { + case TYPE_FOOD: + s += "Food "; + break; + case TYPE_WOOD: + s += "Wood "; + break; + case TYPE_GOLD: + s += "Gold "; + break; + case TYPE_STONE: + s += "Stone "; + break; + case TYPE_POPULATION_HEADROOM: + s += "Pop "; + break; + default: + s += "vat?"; + } + } + } + return s; +} + +std::string costToString(const std::vector &costs) { + std::string s; + for (const ResearchResourceCost &cost : costs) { + if (cost.Flag == 1) { + s += std::to_string(cost.Amount); + s += " "; + switch (cost.Type) { + case TYPE_FOOD: + s += "Food "; + break; + case TYPE_WOOD: + s += "Wood "; + break; + case TYPE_GOLD: + s += "Gold "; + break; + case TYPE_STONE: + s += "Stone "; + break; + case TYPE_POPULATION_HEADROOM: + s += "Pop "; + break; + default: + s += "vat?"; + } + } + } + return s; +} + +bool bothRequirePopulationHeadroom(int unitId, std::vector &resourceCosts, const genie::Civ &civ) { + return ((civ.Units.at(unitId).Creatable.ResourceCosts.at(2).Type == TYPE_POPULATION_HEADROOM && + resourceCosts.at(2).Type == TYPE_POPULATION_HEADROOM) || + (civ.Units.at(unitId).Creatable.ResourceCosts.at(2).Type != TYPE_POPULATION_HEADROOM && + resourceCosts.at(2).Type != TYPE_POPULATION_HEADROOM)); +} + +void copyResourceCostAt(int unitId, int index, std::vector &target, const genie::Civ &civ) { + genie::ResourceUsage source = civ.Units.at(unitId).Creatable.ResourceCosts.at(index); + target.at(index).Type = source.Type; + target.at(index).Amount = source.Amount; + target.at(index).Flag = source.Flag; +} + +void jumbleCosts(genie::DatFile *df) { + std::vector unitIds; + for (genie::Unit unit : df->Civs.at(0).Units) { + if (hasNaturalResourceCost(unit)) { + unitIds.push_back(unit.ID); + } + } + + std::vector techIds; + size_t index = 0; + for (const genie::Tech &tech : df->Techs) { + std::vector resourceCopy = tech.ResourceCosts; + if (hasNaturalResearchResourceCost(resourceCopy)) { + techIds.push_back(index); + } + index++; + } + + std::vector> allTheCosts; + for (int unitId: unitIds) { + std::vector resourceCopy = df->Civs.at(0).Units.at(unitId).Creatable.ResourceCosts; + allTheCosts.push_back(resourceCopy); + } + + for (int techId: techIds) { + std::vector resourceCopy = toResourceCosts(df->Techs.at(techId).ResourceCosts); + allTheCosts.push_back(resourceCopy); + } + + for (int i = 0; i < 10; i++) { + unsigned int seed = std::random_device()(); + std::cout << "Seed for shuffling unit and tech costs is: " << std::to_string(seed) << std::endl; + shuffle(allTheCosts.begin(), allTheCosts.end(), std::mt19937(seed)); + + size_t costIndex = 0; + for (int techId: techIds) { + std::vector researchResourceCosts = toResearchResourceCosts(allTheCosts.at(costIndex)); + std::cout << "Setting cost of tech with id " << techId << " to " << costToString(researchResourceCosts) << std::endl; + df->Techs.at(techId).ResourceCosts = researchResourceCosts; + costIndex++; + } + for (int unitId: unitIds) { + std::vector &resourceCosts = allTheCosts.at(costIndex); + std::cout << "Setting cost of unit with id " << unitId << " to " << costToString(resourceCosts) << std::endl; + if (!bothRequirePopulationHeadroom(unitId, resourceCosts, df->Civs.at(0))) { + copyResourceCostAt(unitId, 2, resourceCosts, df->Civs.at(0)); + } + for (genie::Civ &civ : df->Civs) { + civ.Units.at(unitId).Creatable.ResourceCosts = resourceCosts; + } + costIndex++; + } + + int maleVillagerCost = getSumOfNaturalResourceCosts( + df->Civs.at(0).Units.at(ID_VILLAGER_BASE_M).Creatable.ResourceCosts); + int femaleVillagerCost = getSumOfNaturalResourceCosts( + df->Civs.at(0).Units.at(ID_VILLAGER_BASE_F).Creatable.ResourceCosts); + if (maleVillagerCost <= 200 && femaleVillagerCost <= 200) { + return; + } + std::cout << "Villagers are too expensive, reshuffling…" << std::endl; + } + std::cout << "Giving up, villagers stay expensive, sorry." << std::endl; +} + +void jumbleUnitCosts(genie::DatFile *df) { + std::vector unitIds; + + for (genie::Unit unit : df->Civs.at(0).Units) { + if (hasNaturalResourceCost(unit)) { + unitIds.push_back(unit.ID); + } + } + + std::vector> allTheCosts; + for (int unitId: unitIds) { + std::vector resourceCopy = df->Civs.at(0).Units.at(unitId).Creatable.ResourceCosts; + allTheCosts.push_back(resourceCopy); + } + + for (int i = 0; i < 10; i++) { + unsigned int seed = std::random_device()(); + std::cout << "Seed for shuffling unit costs is: " << std::to_string(seed) << std::endl; + std::shuffle(allTheCosts.begin(), allTheCosts.end(), std::mt19937(seed)); + + size_t index = 0; + for (int unitId: unitIds) { + std::vector &resourceCosts = allTheCosts.at(index); + std::cout << "Setting cost of unit with id " << unitId << " to " << costToString(resourceCosts) << std::endl; + if (!bothRequirePopulationHeadroom(unitId, resourceCosts, df->Civs.at(0))) { + copyResourceCostAt(unitId, 2, resourceCosts, df->Civs.at(0)); + } + for (genie::Civ &civ : df->Civs) { + civ.Units.at(unitId).Creatable.ResourceCosts = resourceCosts; + } + index++; + } + + int maleVillagerCost = getSumOfNaturalResourceCosts( + df->Civs.at(0).Units.at(ID_VILLAGER_BASE_M).Creatable.ResourceCosts); + int femaleVillagerCost = getSumOfNaturalResourceCosts( + df->Civs.at(0).Units.at(ID_VILLAGER_BASE_F).Creatable.ResourceCosts); + if (maleVillagerCost <= 200 && femaleVillagerCost <= 200) { + return; + } + std::cout << "Villagers are too expensive, reshuffling…" << std::endl; + } + std::cout << "Giving up, villagers stay expensive, sorry." << std::endl; +} + +void jumbleTechCosts(genie::DatFile *df) { + std::vector techIds; + + std::vector> allTheCosts; + size_t index = 0; + for (const genie::Tech &tech : df->Techs) { + std::vector resourceCopy = tech.ResourceCosts; + if (hasNaturalResearchResourceCost(resourceCopy)) { + allTheCosts.push_back(resourceCopy); + techIds.push_back(index); + } + index++; + } + + unsigned int seed = std::random_device()(); + std::cout << "Seed for shuffling tech costs is: " << std::to_string(seed) << std::endl; + shuffle(allTheCosts.begin(), allTheCosts.end(), std::mt19937(seed)); + + index = 0; + for (size_t techId : techIds) { + std::vector &resourceCosts = allTheCosts.at(index); + std::cout << "Setting cost of tech with id " << techId << " to " << costToString(resourceCosts) << std::endl; + df->Techs.at(techId).ResourceCosts = resourceCosts; + index++; + } + +} diff --git a/patches/random_costs.h b/patches/random_costs.h new file mode 100644 index 0000000..179eac2 --- /dev/null +++ b/patches/random_costs.h @@ -0,0 +1,10 @@ +#ifndef RANDOM_COSTS_H +#define RANDOM_COSTS_H + +#include "genie/dat/DatFile.h" + +void jumbleCosts(genie::DatFile *df); +void jumbleUnitCosts(genie::DatFile *df); +void jumbleTechCosts(genie::DatFile *df); + +#endif // RANDOM_COSTS_H