diff --git a/.clang_complete b/.clang_complete new file mode 100644 index 0000000..baaa89c --- /dev/null +++ b/.clang_complete @@ -0,0 +1 @@ +-I./genieutils/include diff --git a/.gitignore b/.gitignore index d4d8afe..5f67bee 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ build *.exe *.out *.app + +# vs code +.vscode \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index f17787c..8d8a7a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,20 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++") add_subdirectory(genieutils EXCLUDE_FROM_ALL) include_directories( "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 + patches/duplicate_civ_bonuses.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 9f9bb96..ca74d9a 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Just install stuff until it stops complaining I guess, sorry. ```sh git clone --recurse-submodules https://github.com/SiegeEngineers/auto-mods.git cd auto-mods -./patchGenieutils.sh +patch -d genieutils is one of the following, or multiple of the following joi x3 x9 x256 + x3-civ-bonus + x9-civ-bonus ``` For example, in order to patch the current dat file with the Flying Dutchman modifications, one might execute diff --git a/create-data-mod.cpp b/create-data-mod.cpp index e291e42..368839e 100644 --- a/create-data-mod.cpp +++ b/create-data-mod.cpp @@ -1,7 +1,17 @@ #include "genie/dat/DatFile.h" -#include "patches.h" + +#include "patches/community_games.h" +#include "patches/duplicate_civ_bonuses.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; const char *const COMMUNITY_GAMES = "community-games"; const char *const EXPLODING_VILLAGERS = "exploding-villagers"; @@ -14,6 +24,8 @@ const char *const RANDOM_UNIT_COSTS = "random-unit-costs"; const char *const X_256_TECH = "x256"; const char *const X_3_TECH = "x3"; const char *const X_9_TECH = "x9"; +const char *const X_3_CIV_BONUS = "x3-civ-bonus"; +const char *const X_9_CIV_BONUS = "x9-civ-bonus"; vector getModIdentifiers(char *const *argv); @@ -38,6 +50,8 @@ int main(int argc, char **argv) { cout << " " << X_3_TECH << endl; cout << " " << X_9_TECH << endl; cout << " " << X_256_TECH << endl; + cout << " " << X_3_CIV_BONUS << endl; + cout << " " << X_9_CIV_BONUS << endl; return 1; } @@ -86,6 +100,10 @@ void applyModifications(genie::DatFile *df, const string &modIdentifier) { duplicateTechs(df, 9); } else if (X_256_TECH == modIdentifier) { duplicateTechs(df, 256); + } else if (X_3_CIV_BONUS == modIdentifier) { + multiplyCivilizationBonuses(df, 3); + } else if (X_9_CIV_BONUS == modIdentifier) { + multiplyCivilizationBonuses(df, 9); } else { cout << "Unknown mod identifier: '" << modIdentifier << "'" << endl; } diff --git a/genieutils.patch b/genieutils.patch new file mode 100644 index 0000000..c79a7f2 --- /dev/null +++ b/genieutils.patch @@ -0,0 +1,30 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b4b3abb..760a912 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -12,11 +12,11 @@ project(genieutils) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake/) + #set(CMAKE_CXX_FLAGS "-std=gnu++0x") + +-#set(Boost_USE_STATIC_LIBS ON) ++set(Boost_USE_STATIC_LIBS ON) + #set(Boost_USE_STATIC_RUNTIME ON) + set(Boost_USE_MULTITHREADED ON) + +-find_library(iconv REQUIRED) ++find_library(iconv iconv REQUIRED) + + # dependencies: + +@@ -158,9 +158,9 @@ set(BINCOMP_SRC src/tools/bincompare/bincomp.cpp + # Executeable: + #------------------------------------------------------------------------------# + +-add_library(${Genieutils_LIBRARY} SHARED ${FILE_SRC} ${LANG_SRC} ${DAT_SRC} ++add_library(${Genieutils_LIBRARY} STATIC ${FILE_SRC} ${LANG_SRC} ${DAT_SRC} + ${RESOURCE_SRC} ${UTIL_SRC} ${SCRIPT_SRC} ) +-target_link_libraries(${Genieutils_LIBRARY} ${ZLIB_LIBRARIES} ${Boost_LIBRARIES} ${ICONV_LIBRARIES}) ++target_link_libraries(${Genieutils_LIBRARY} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES} ${ICONV_LIBRARIES}) + + #add_executable(main main.cpp) + #target_link_libraries(main ${Genieutils_LIBRARY}) diff --git a/ids.h b/ids.h index 236000b..4d0197c 100644 --- a/ids.h +++ b/ids.h @@ -203,12 +203,45 @@ static const int TYPE_FOOD = 0; static const int TYPE_WOOD = 1; static const int TYPE_STONE = 2; static const int TYPE_GOLD = 3; +static const int TYPE_RESEARCH_COST_MODIFIER = 85; +static const int TYPE_RESEARCH_TIME_MODIFIER = 86; +static const int TYPE_GOLD_MINING_PRODUCTIVITY = 47; +static const int TYPE_STONE_MINING_PRODUCTIVITY = 79; +static const int TYPE_WOOD_CHOPPING_PRODUCTIVITY = 189; +static const int TYPE_FOOD_GATHERING_PRODUCTIVITY = 190; +static const int TYPE_FOOD_HERDING_PRODUCTIVITY = 216; static const int ID_SCOUT = 448; static const int ID_EAGLE_SCOUT = 751; +static const int ID_MADARASH_MONK = 412; static const int ACTION_KIDNAP_UNIT = 135; static const int ACTION_LOOT = 122; static const int CLASS_CIVILIAN = 4; static const int CLASS_BUILDING = 3; +static const int ID_EMPTY_TC_ANNEX = 890; + +static const int EFFECT_ID_HUNS_100_WOOD = 214; +static const int EFFECT_ID_PERSIANS_TC_HITPOINTS = 340; +static const int EFFECT_ID_PERSIANS_DOCK_HITPOINTS = 347; +static const int EFFECT_ID_PERSIANS_KAMANDARAN = 547; +static const int EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_DARK = 283; +static const int EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_FEUDAL = 429; +static const int EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_CASTLE = 430; +static const int EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_IMPERIAL = 431; +static const int EFFECT_ID_MAYAN_TECH_TREE = 449; +static const int EFFECT_ID_SARACEN_MARKET_BONUS = 354; +static const int EFFECT_ID_SARACEN_MADARASH = 545; + + +static const int COMMAND_RESOURCE_MODIFIER = 1; +static const int COMMAND_UPGRADE_UNIT = 3; +static const int COMMAND_ATTRIBUTE_MODIFIER = 4; +static const int COMMAND_ATTRIBUTE_MULTIPLIER = 5; +static const int COMMAND_TEAM_ATTRIBUTE_MODIFIER = 10; +static const int COMMAND_TECH_COST_MODIFIER = 101; +static const int COMMAND_DISABLE_TECH = 102; +static const int COMMAND_TECH_TIME_MODIFIER = 103; + + #endif //CREATE_DATA_MOD_IDS_H diff --git a/patchGenieutils.sh b/patchGenieutils.sh deleted file mode 100755 index 18723dc..0000000 --- a/patchGenieutils.sh +++ /dev/null @@ -1,5 +0,0 @@ -#! /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 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..d301267 --- /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_civ_bonuses.cpp b/patches/duplicate_civ_bonuses.cpp new file mode 100644 index 0000000..01d7505 --- /dev/null +++ b/patches/duplicate_civ_bonuses.cpp @@ -0,0 +1,289 @@ +#include +#include +#include +#include +#include "genie/dat/DatFile.h" +#include "genie/dat/TechageEffect.h" +#include "ids.h" + + +void debugPrintEffect(genie::DatFile *df, uint16_t effectId) { + const genie::Effect &effect = df->Effects.at(effectId); + std::cout << effectId << " - " << effect.Name << std::endl; +} + +std::string getTechName(genie::DatFile *df, int techId) { + return techId > 0 ? df->Techs[techId].Name : "-1"; +} + +std::string getUnitName(genie::DatFile *df, int unitId) { + return unitId > 0 ? df->Civs[0].Units[unitId].Name : "-1"; +} + +std::string getCommandTypeName(genie::DatFile *df, genie::EffectCommand &command) { + switch (command.Type) { + case COMMAND_RESOURCE_MODIFIER: + return "Resource Modifier (Set/+/-)"; + case COMMAND_UPGRADE_UNIT: + return "Upgrade Unit " + getUnitName(df, command.A) + " -> " + getUnitName(df, command.B); + case COMMAND_ATTRIBUTE_MODIFIER: + return "Attribute Modifier (+/-)"; + case COMMAND_ATTRIBUTE_MULTIPLIER: + return "Attribute Modifier (Mult)"; + case COMMAND_TEAM_ATTRIBUTE_MODIFIER: + return "Team Attribute Modifier (Set)"; + case COMMAND_TECH_COST_MODIFIER: + return "Tech Cost Modifier (Set/+/-) " + getTechName(df, command.A); + case COMMAND_DISABLE_TECH: + return "Disable tech " + getTechName(df, command.D); + case COMMAND_TECH_TIME_MODIFIER: + return "Tech Time Modifier (Set/+/-) " + getTechName(df, command.A); + } + return "UNKNOWN"; +} + +int capEffectMultiplication(uint16_t effectId, int times) { + // Cap some effects multiplication so it doesnt break the gameplay too much + // especially for higher multiplication values + switch(effectId) { + case EFFECT_ID_HUNS_100_WOOD: + case EFFECT_ID_PERSIANS_KAMANDARAN: + return 1; + case EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_DARK: + case EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_FEUDAL: + case EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_CASTLE: + case EFFECT_ID_BYZANTINE_BUILDING_BONUS_HP_IMPERIAL: + case EFFECT_ID_MAYAN_TECH_TREE: + case EFFECT_ID_SARACEN_MARKET_BONUS: + return 3; + case EFFECT_ID_PERSIANS_TC_HITPOINTS: + return 4; + case EFFECT_ID_PERSIANS_DOCK_HITPOINTS: + return 5; + default: + return times; + } +} + +void addDummyAnnexBuilding(genie::DatFile *df, const std::vector annexUnitIds) { + genie::Unit dummyAnnexUnit(df->Civs[0].Units[annexUnitIds[0]]); + dummyAnnexUnit.Building.Annexes.clear(); + + const std::vector> misplacements { + {0, 0}, + {-1, 0}, + {-1, 1}, + {0, 1} + }; + + // generate the annex instances with the given unit ids + for (int i = 0; i < 4; ++i) { + auto newAnnex = genie::unit::BuildingAnnex(); + newAnnex.Misplacement = misplacements[i]; + newAnnex.UnitID = i < annexUnitIds.size() ? annexUnitIds.at(i) : -1; + dummyAnnexUnit.Building.Annexes.push_back(newAnnex); + } + for (auto& civ : df->Civs) { + civ.Units.push_back(dummyAnnexUnit); + civ.UnitPointers.push_back(1); + } +} + +void multiplyResourceModifierCommand(genie::DatFile *df, genie::EffectCommand& command, int civ_id, int times) { + if (command.B == 1) { // `add` or `sub` mode + command.D *= times; + } + else { // `set` mode + auto baseValue = df->Civs[civ_id].Resources.at(command.A); + // research cost modifier and research time modifier resources have a base value of 0 + // we need to replace that value with 1 so that the bonus calculation works correctly + if (command.A == TYPE_RESEARCH_COST_MODIFIER || command.A == TYPE_RESEARCH_TIME_MODIFIER) { + baseValue = 1.0; + } + + if (command.A == TYPE_GOLD_MINING_PRODUCTIVITY + || command.A == TYPE_STONE_MINING_PRODUCTIVITY + || command.A == TYPE_WOOD_CHOPPING_PRODUCTIVITY + || command.A == TYPE_FOOD_GATHERING_PRODUCTIVITY + || command.A == TYPE_FOOD_HERDING_PRODUCTIVITY + || command.D < baseValue + ) { + // productivity and "negative" bonuses stack multiplicatively + command.D = std::pow(command.D / baseValue, times) * baseValue; + } + else { + // the rest of the bonuses stack additively + command.D = (command.D - baseValue) * times + baseValue; + } + } +} + +void multiplyTcAnnexCommand(genie::DatFile *df, genie::EffectCommand &command, int times) { + int total_leafs = 0; + + // store unit ids for every created tc annex node + std::vector annexUnits; + annexUnits.push_back(command.B); + + int leafCount = 1; + + // find the subtree that will produce less than `times` leaves with the maximum degree (4) + while (leafCount * 4 < times) { + addDummyAnnexBuilding( + df, + std::vector(4, annexUnits.back()) + ); + annexUnits.push_back(df->Civs[0].Units.size() - 1); + leafCount *= 4; + } + + // find how many of each annex unit types are needed to reach `times` replicas + // add them in a tree using a stack + std::vector stack; + for (int i = annexUnits.size() - 1; i >= 0; --i) { + stack.insert(stack.end(), times / leafCount, annexUnits[i]); + times %= leafCount; + leafCount /= 4; // descend one level + while (stack.size() >= 4) { + addDummyAnnexBuilding(df, stack); + stack.erase(stack.begin(), stack.begin()+4); + stack.push_back(df->Civs[0].Units.size() - 1); + } + } + if (stack.size() != 1) { + addDummyAnnexBuilding(df, stack); + stack.clear(); + stack.push_back(df->Civs[0].Units.size() - 1); + } + command.B = stack.at(0); +} + +void multiplyAttributeModifierCommand(genie::DatFile *df, genie::EffectCommand &command, int times) { + if (command.C == 8 || command.C == 9) { // Armor/Atack + int armor_type = int(command.D) / 256; + int amount = int(command.D) % 256; + command.D = float(armor_type * 256 + std::min(amount * times, 255)); + } + else { + command.D *= times; + } +} + +void multiplyAttributeMultiplierCommand(genie::DatFile *df, genie::EffectCommand &command, int civ_id, int times) { + command.D = std::pow(command.D, times); + // make sure units wont have too many hitpoints + if (command.A != -1 && command.C == 0) { + const int unitHitPoints = df->Civs[civ_id].Units[command.A].HitPoints; + if (unitHitPoints * command.D >= (1 << 16)) { + std::cout << "[WARNING] unit with too many hitpoints: " << df->Civs[civ_id].Units[command.A].Name << " (" << df->Civs[civ_id].Name << ")" << std::endl; + } + } +} + +void multiplyTechCostModifierCommand(genie::DatFile *df, genie::EffectCommand &command, int times) { + if (command.C == 0) { // Set + + } else { // + or - + command.D *= times; + } +} + +void multiplyTechTimeModifierCommand(genie::DatFile *df, genie::EffectCommand &command, int times) { + if (command.A == -1) { + return; + } + const genie::Tech& tech = df->Techs[command.A]; + if (command.C == 0) { // `set` mode + + } + else { // `add` or `sub` mode + command.D *= times; + if (command.D <= -tech.ResearchTime) { + command.D = -tech.ResearchTime + 1; + } + } +} + +void multiplyEffectCommand(genie::DatFile *df, genie::EffectCommand& command, uint16_t effectId, uint16_t civ_id, int times) { + std::string commandTypeName = getCommandTypeName(df, command); + float oldValue = command.D; + switch (command.Type) { + case COMMAND_RESOURCE_MODIFIER: + multiplyResourceModifierCommand(df, command, civ_id, times); + break; + case COMMAND_UPGRADE_UNIT: + if (command.A == ID_EMPTY_TC_ANNEX) { + multiplyTcAnnexCommand(df, command, times); + } + break; + case COMMAND_ATTRIBUTE_MODIFIER: + multiplyAttributeModifierCommand(df, command, times); + break; + case COMMAND_ATTRIBUTE_MULTIPLIER: + multiplyAttributeMultiplierCommand(df, command, civ_id, times); + break; + case COMMAND_TEAM_ATTRIBUTE_MODIFIER: + if (command.A != -1) { + float delta = command.D - df->Civs[civ_id].Units[command.A].ResourceStorages[0].Amount; + command.D = delta * times; + } + break; + case COMMAND_TECH_COST_MODIFIER: + multiplyTechCostModifierCommand(df, command, times); + break; + case COMMAND_TECH_TIME_MODIFIER: + multiplyTechTimeModifierCommand(df, command, times); + break; + } + std::cout << " command type: " << int(command.Type) << " - " << commandTypeName << " - " << "(A=" << command.A << " B=" << command.B << " C=" << command.C << " D=" << oldValue << ") => " << command.D << std::endl; +} + +void multiplyEffect(genie::DatFile *df, uint16_t effectId, uint16_t civ_id, int times) { + times = capEffectMultiplication(effectId, times); + + auto& effect = df->Effects.at(effectId); + std::cout << "Effect " << effectId << " \"" << effect.Name << "\"" << std::endl; + for (auto& command: effect.EffectCommands) { + multiplyEffectCommand(df, command, effectId, civ_id, times); + } +} + +void multiplyCivilizationBonuses(genie::DatFile *df, int times) { + std::vector effectIds; + for (auto it = df->Civs.begin(); it != df->Civs.end(); ++it) { + auto civ_id = it - df->Civs.begin(); + if (civ_id == 0) // skip gaia + continue; + + effectIds.push_back(it->TechTreeID); + effectIds.push_back(it->TeamBonusID); + + std::cout << "Tech tree (" << it->Name << "):" << std::endl; + multiplyEffect(df, it->TechTreeID, civ_id, times); + std::cout << "Team bonus (" << it->Name << "):" << std::endl; + multiplyEffect(df, it->TeamBonusID, civ_id, times); + std::cout << std::endl; + } + + for (auto it = df->Techs.begin(); it != df->Techs.end(); ++it) { + if (it->Civ == 0 || it->Civ == -1 || it->EffectID == -1) + continue; + if (std::find(effectIds.begin(), effectIds.end(), it->EffectID) != effectIds.end()) + continue; + + effectIds.push_back(it->EffectID); + + std::cout << "Tech " << (it - df->Techs.begin()) << " \"" << it->Name << "\" " << "(" << df->Civs[it->Civ].Name << ")" << std::endl; + multiplyEffect(df, it->EffectID, it->Civ, times); + std::cout << std::endl; + } + + for (auto civ = df->Civs.begin(); civ != df->Civs.end(); ++civ) { + auto& madarashMonk = civ->Units[ID_MADARASH_MONK]; + for (auto storage = madarashMonk.ResourceStorages.begin(); storage != madarashMonk.ResourceStorages.end(); ++storage) { + if (storage->Type == TYPE_GOLD) { + storage->Amount *= capEffectMultiplication(EFFECT_ID_SARACEN_MADARASH, times); + } + } + } +} diff --git a/patches/duplicate_civ_bonuses.h b/patches/duplicate_civ_bonuses.h new file mode 100644 index 0000000..71bda0b --- /dev/null +++ b/patches/duplicate_civ_bonuses.h @@ -0,0 +1,8 @@ +#ifndef DUPLICATE_CIV_BONUSES_H +#define DUPLICATE_CIV_BONUSES_H + +#include "genie/dat/DatFile.h" + +void multiplyCivilizationBonuses(genie::DatFile *df, int times); + +#endif // DUPLICATE_CIV_BONUSES_H \ No newline at end of file diff --git a/patches/duplicate_techs.cpp b/patches/duplicate_techs.cpp new file mode 100644 index 0000000..114233d --- /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..54c64aa --- /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 \ No newline at end of file diff --git a/patches/exploding_villagers.cpp b/patches/exploding_villagers.cpp new file mode 100644 index 0000000..c7cf25f --- /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..d857b73 --- /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..85bfbdf --- /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..617c372 --- /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..d2f18eb --- /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 \ No newline at end of file diff --git a/patches/random_costs.cpp b/patches/random_costs.cpp new file mode 100644 index 0000000..0a49f5c --- /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..c1e9bfa --- /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 \ No newline at end of file