////////////////////////////////////////////////////////////////////////////// /// SLIC code for Medieval Pack II by Wouter Snijders /// //////////////////////////////////////////////////////////////////////////// // Author: Wouter Snijders (aka Locutus) // E-mail: locutus-of-borg@hetnet.nl // Last update: 2001 may 29 by: Wouter Snijders // // For: Medieval Mod II (by Wes Whitaker et al) // // Legal stuff, technical problems, questions, etc: see MedMod readmes // // Current contents of this file: // 0) Miscellaneous code - Code to set up the constants and // other stuff that is needed in the // rest of the file // 1) Militia code - Takes care of Militia creation and // maintenance in cities // 2) Partisan code - Creates Partisans outside city when // city is captured and happiness // decreases // 3) Unit repair code - Makes unit repair in cities cost PW // and if insufficent PW is available // slows it down // 4) Clear orders code - Clears orders of all units of every // AI civ once every 3 turns, to get the // AI to rethink his actions more often // 5) Wonder code - Takes certain buildings out of the // build lists when a player owns a // certain Wonder // 6) Capital code - Rebuilds capitol of AI civs elsewhere // if they loose their capital // 7) Slavery code - Kills all units with slaving powers // once slave age is over // // Any changes modmakers would like to make (e.g. what militia units are // available, how much repair costs, etc) can be made in the function // MM2_SetUp(), currently starting at line 70. //////// Declarations //////// // contstants int_t MM2_MILITIA_TYPE[]; // store what Militia types are available (index is age) int_t MM2_MILITIA_CITY_SIZE; // all cities larger than this will no longer have militias int_t MM2_PARTISAN_ROUND[]; // store when extra Partisan become available (cities above this size get extra unit) int_t MM2_PARTISAN_NUMBER[]; // store how many Partisan should be in a city (index is round from MM2_PARTISAN_ROUND) int_t MM2_PARTISAN_TYPE[]; // store what Partisan types are available (index is age) int_t MM2_DISTANCE_FROM_CITY[]; // store how far from city Partisans should be created (index 1 means first Partisan) //int_t MM2_PART_PER_POP; // NO LONGER USED: store how many Partisans should exist per pop (e.g. 6 means 1 Partisan per 6 pop) int_t MM2_UNIT_REPAIR_NUM; // store the numerator of the fraction in the unit repair trigger that determines the multiplier of the pw cost of unit repair int_t MM2_UNIT_REPAIR_DENOM; // store the denominator of the fraction in the unit repair trigger that determines the multiplier of the pw cost of unit repair // variables int_t MM2_capturedCity; // flag to prevent that new Militia are being placed in a just conquered city int_t MM2_cityHappiness; // pass happiness before city capture on to handler that's called after capture int_t MM2_cityOwner; // pass owner before city capture on to handler that's called after capture int_t unitOwner[]; // index is UnitDB(UNIT_name), needed for elite units & elite militia units, see file MM2_SLC_Chris.sl for details ////////////////////////////////// //// 0. Miscellaneous Code //// //////////////////////////////// // set up all the contstants void_f MM2_SetUp() { //// constants //// // Partisan MM2_PARTISAN_ROUND[0] = 8; // order of values must always be from lowest to highest MM2_PARTISAN_ROUND[1] = 20; // so index = 0 has value 8 then index = 1 must have a value > 8, etc. MM2_PARTISAN_ROUND[2] = 36; MM2_PARTISAN_ROUND[3] = 44; MM2_PARTISAN_ROUND[4] = 56; MM2_PARTISAN_ROUND[5] = 99; // add more rounds if needed MM2_PARTISAN_NUMBER[0] = 1; // always keep number of rounds in MM2_PARTISAN_NUMBER larger MM2_PARTISAN_NUMBER[1] = 2; // or equal to number of rounds in MM2_PARTISAN_ROUND MM2_PARTISAN_NUMBER[2] = 3; MM2_PARTISAN_NUMBER[3] = 4; MM2_PARTISAN_NUMBER[4] = 4; MM2_PARTISAN_NUMBER[5] = 4; // add more rounds if needed MM2_MILITIA_TYPE[0] = UnitDB(UNIT_SPEARMAN_MILITIA); // always keep number of ages in 'MM2_GetAge' MM2_MILITIA_TYPE[1] = UnitDB(UNIT_PHALANX_MILITIA); // smaller or equal to number of units here MM2_MILITIA_TYPE[2] = UnitDB(UNIT_FYRDMAN_MILITIA); MM2_MILITIA_TYPE[3] = UnitDB(UNIT_MUSKETEER_MILITIA); MM2_MILITIA_TYPE[4] = UnitDB(UNIT_RIFLEMAN_MILITIA); MM2_MILITIA_TYPE[5] = UnitDB(UNIT_MACHINE_GUNNER_MILITIA); MM2_MILITIA_TYPE[6] = UnitDB(UNIT_PLASMATICA_MILITIA); // add more units if needed MM2_MILITIA_TYPE[7] = UnitDB(UNIT_BOMBARD); // elite militias MM2_MILITIA_TYPE[8] = UnitDB(UNIT_ARQUEBUSIER); MM2_MILITIA_CITY_SIZE = 99; MM2_PARTISAN_TYPE[0] = UnitDB(UNIT_PARTISAN); // always keep number of ages in 'MM2_GetAge' MM2_PARTISAN_TYPE[1] = UnitDB(UNIT_PARTISAN); // smaller or equal to number of units here MM2_PARTISAN_TYPE[2] = UnitDB(UNIT_PARTISAN); MM2_PARTISAN_TYPE[3] = UnitDB(UNIT_PARTISAN); MM2_PARTISAN_TYPE[4] = UnitDB(UNIT_PARTISAN); MM2_PARTISAN_TYPE[5] = UnitDB(UNIT_PARTISAN); MM2_PARTISAN_TYPE[6] = UnitDB(UNIT_PARTISAN); // add more units if needed MM2_DISTANCE_FROM_CITY[1] = 2; MM2_DISTANCE_FROM_CITY[2] = 2; MM2_DISTANCE_FROM_CITY[3] = 2; MM2_DISTANCE_FROM_CITY[4] = 2; MM2_DISTANCE_FROM_CITY[5] = 3; MM2_DISTANCE_FROM_CITY[6] = 3; MM2_DISTANCE_FROM_CITY[7] = 3; MM2_DISTANCE_FROM_CITY[8] = 3; MM2_DISTANCE_FROM_CITY[9] = 3; MM2_DISTANCE_FROM_CITY[10] = 3; MM2_DISTANCE_FROM_CITY[11] = 3; MM2_DISTANCE_FROM_CITY[12] = 3; // 15 x 6 = 90, add more if cities can get larger than 95 MM2_DISTANCE_FROM_CITY[13] = 3; // (95 / 6) = 15.833333, which is rounded down to 15) MM2_DISTANCE_FROM_CITY[14] = 3; // if less than 90 are needed, some of this code is redundant MM2_DISTANCE_FROM_CITY[15] = 3; // but that isn't harmful in any way MM2_DISTANCE_FROM_CITY[16] = 3; // MM2_PART_PER_POP = 9; // NO LONGER USED: 1 Partisan per 9 population points // Unit Repair MM2_UNIT_REPAIR_NUM = 4; // so fraction is 3/4 and cost of repair will be (3/4 * damage), where 'damage' is the amount of MM2_UNIT_REPAIR_DENOM = 5; // production (i.e. pw) needed to repair the unit //// variables //// //// flags //// MM2_capturedCity = 0; } //int_t MM2_pwtax[32]; // //HandleEvent(BeginTurn) 'MM2_Strat' post { // if (player[0].publicworkstax != MM2_pwtax[player[0]]) { // MM2_pwtax[player[0]] = player[0].publicworkstax; // Message(1, 'MM2_GotHere'); // send message if pw-tax changed // } //} Messagebox 'MM2_GotHere' { Text(ID_MM2_GOT_HERE); } // executes at the beginning of the game to set everything up (initialize constants & variables, set flags, etc) HandleEvent(BeginTurn) 'MM2_GameStart' pre { // 'pre' because it has to trigger before 'MM2_EveryTurn' and set things up for the rest of the code MM2_SetUp(); DisableTrigger('MM2_GameStart'); // execute this trigger only once int_t i; for (i = 0; i < 32; i = i + 1) { // MM2_pwtax[i] = 0; } } // return what generation (age) of defensive units is currently available for 'thePlayer' // this code is needed for the Partisan code int_f MM2_GetAge(int_t thePlayer) { int_t tmpPlayer; tmpPlayer = thePlayer; // to add ages, change age 6 to whatever the highest age should be and use age 5 as example for the other ages if (HasAdvance(tmpPlayer, ID_ADVANCE_CYBERNETICS) ) { // if player has Chaos Theory, return 6; // age is age 5 } elseif (HasAdvance(tmpPlayer, ID_ADVANCE_AUTOMATIC_RIFLES)) { // etc. return 5; } elseif (HasAdvance(tmpPlayer, ID_ADVANCE_REPEATING_RIFLES)) { return 4; } elseif (HasAdvance(tmpPlayer, ID_ADVANCE_FLINTLOCK)) { return 3; } elseif (HasAdvance(tmpPlayer, ID_ADVANCE_THEOLOGY)) { return 2; } elseif (HasAdvance(tmpPlayer, ID_ADVANCE_INFANTRY_TACTICS)) { return 1; } elseif (HasAdvance(tmpPlayer, ID_ADVANCE_TOOLMAKING)) { return 0; } else { // if none of above advances present, (should never happen) return 0; // age is age 0 } } // this code returns if 'theAdvance' grants a new type of Militia // this code is needed for the Militia code (put here to keep overview over settings) int_f MM2_GetAdvance(int_t theAdvance) { int_t tmpAdvance; tmpAdvance = theAdvance; if (tmpAdvance == AdvanceDB(ADVANCE_CYBERNETICS)) { return 1; } if (tmpAdvance == AdvanceDB(ADVANCE_AUTOMATIC_RIFLES)) { return 1; } if (tmpAdvance == AdvanceDB(ADVANCE_REPEATING_RIFLES)) { return 1; } if (tmpAdvance == AdvanceDB(ADVANCE_FLINTLOCK)) { return 1; } if (tmpAdvance == AdvanceDB(ADVANCE_THEOLOGY)) { return 1; } if (tmpAdvance == AdvanceDB(ADVANCE_INFANTRY_TACTICS)) { return 1; } if (tmpAdvance == AdvanceDB(ADVANCE_TOOLMAKING)) { return 1; } return 0; } //// City Changes //// // when a city is captured, set flag and store old owner and happiness level // this code is needed for Partisans code HandleEvent(CaptureCity) 'MM2_MilitiaCaptureCity' pre { // triggers right before a city is captured MM2_capturedCity = 1; MM2_cityHappiness = city[0].happiness; // store happiness level before capture MM2_cityOwner = city[0].owner; // store owner before capture } /////////////////////////////// //// 1. Militia Functions //// ///////////////////////////// // Description // This section of this file takes care of the Militia units in the MedMod. // Militia units are defensive units that you get for free to protect your // cities. They have the same sprite, name and statistics as some of the // regular defensive units in the game and they are created and updated // automaticly. // The main difference between regular and Militia defenders is that // Militias can't move: they represent some sort of civilian guard or police // force) that is formed by the citizens of your city and who's sole purpose is // to protect the other citizens of that city. Because Militias aren't // 'regular' military units but more a police force, they are also cheaper to // maintain: they only have half the upkeep cost of their regular counterparts. // They exert martial law but do not suppress slaves. They cannot move either, // but they can expel units. // The idea behind this is that neither you nor the AI will have to worry // too much about city defense and can concentrate your resources on more // important areas such as offense or research. It's a simple but effective // way to reduce micromanagement and increase the AI's performance (esp. early // on in the game against the aggressive barbarians). // Once a city is founded, it gets one Militia unit and as the city grows // more units will be added automaticly. Currently, the city sizes at which // you get an extra Militia unit are 9, 21, and 37, the same sizes at // which your city radius increases. Also, when the city decreases in size // Militia units will be deleted if warranted. Contrary to MedMod I, the // additions now occur as soon as a city changes to a critical size, not just // with the discovery of an important advance. // As soon as you discover certain key advances that give you new // defensive units, your Militia force will be automaticly upgraded as well. // Here is a list of Militia units and advances at which they become available: // // Advance | Unit // --------------------------+----------------------- // Toolmaking | Spearman Militia // Infantry Tactics | Phalanx Militia // Theology | Fyrdman Militia // Flintlock | Musketeer Militia // Repeating Rifles | Rifleman Militia // Automatic Rifles | Machine Gunner Militia // Cybernetics | Plasmatica Militia // return if unit of 'theType' is a MilitiaUnit int_f MM2_IsMilitia(int_t theType) { int_t i; int_t typeOfUnit; typeOfUnit = theType; for (i = 0; i < MM2_MILITIA_TYPE.#; i = i + 1) { // for all Militia units if (typeOfUnit == MM2_MILITIA_TYPE[i]) { // check if unit is of that type return 1; // if so, return true } } return 0; // if not of part of Militia array, return false } // kill up to 'number' Militia units at 'theLoc' (if less than 'number' Militias are present, all Militias are killed) // note that this functions takes first unit(s) it finds, regardless of veteran or health status or whatever void_f MM2_KillMilitia(int_t theNumber, location_t theLoc) { location_t tmpLoc; unit_t tmpUnit; int_t number; int_t i; int_t killed; killed = 0; tmpLoc = theLoc; number = theNumber; for (i = 0; i < GetUnitsAtLocation(tmpLoc); i = i + 1) { GetUnitFromCell(tmpLoc, i, tmpUnit); // cycle through all units at current location if (MM2_IsMilitia(tmpUnit.type)) { // if unit is Militia if (killed < number) { // and if more need to be killed KillUnit(tmpUnit); // kill this unit killed = killed + 1; // and count the number of units killed so far } } } } // create the special elite militia units when needed (called from file MM2_SLC_Chris.slc) void_f MM2_EliteMilitiaSetup(int_t thePlayer) { city_t tmpCity; unit_t tmpUnit; int_t i; int_t tmpPlayer; tmpPlayer = thePlayer; player[3] = tmpPlayer; for (i = 0; i < player[3].cities; i = i + 1) { GetCityByIndex(tmpPlayer, i, tmpCity); CreateUnit(tmpPlayer, UnitDB(UNIT_ARQUEBUSIER), tmpCity.location, 0, tmpUnit); Event:EntrenchUnit(tmpUnit); CreateUnit(tmpPlayer, UnitDB(UNIT_BOMBARD), tmpCity.location, 0, tmpUnit); Event:EntrenchUnit(tmpUnit); } } // create 'number' Militia units at 'theLoc' for 'thePlayer' and fortify them void_f MM2_CreateMilitia(int_t theNumber, int_t thePlayer, location_t theLoc) { location_t tmpLoc; unit_t tmpUnit; int_t i; int_t age; int_t number; int_t tmpPlayer; tmpPlayer = thePlayer; tmpLoc = theLoc; number = theNumber; age = MM2_GetAge(tmpPlayer); // based upon current age for (i = 0; i < number; i = i + 1) { // create number units location[0] = tmpLoc; CreateUnit(tmpPlayer, MM2_MILITIA_TYPE[age], tmpLoc, 0, tmpUnit); // of this age Event:EntrenchUnit(tmpUnit); // and fortify them } } // when a city is build, no matter how (settler, sea engineer, ruin), create one Militia unit HandleEvent(CreateCity) 'MM2_MilitiaCityCreated' post { // triggers if a city is founded location_t tmpLoc; unit_t tmpUnit; int_t tmpPlayer; tmpPlayer = player[0]; tmpLoc = location[0]; MM2_CreateMilitia(1, tmpPlayer, tmpLoc); // create 1 Militia } // prevent Militia units from moving through keypad commands // bug fixed: MoveUnits changed to MoveOrder, prevents ZOC problems HandleEvent(MoveToOrder) 'MM2_MilitiaMoveKeypad' pre { // triggers right before an army moves int_t i; unit_t tmpUnit; army_t tmpArmy; tmpArmy = army[0]; for (i = 0; i < tmpArmy.size; i = i + 1) { // cycle through all units in this army GetUnitFromArmy(tmpArmy, i, tmpUnit); if (MM2_IsMilitia(tmpUnit.type)) { // if any of the units in this army is a Militia return STOP; // don't allow army to move } } } // prevent Militia units from moving // bug fixed: MoveUnits changed to MoveOrder, prevents ZOC problems HandleEvent(MoveOrder) 'MM2_MilitiaMove' pre { // triggers right before an army moves int_t i; unit_t tmpUnit; army_t tmpArmy; tmpArmy = army[0]; for (i = 0; i < tmpArmy.size; i = i + 1) { // cycle through all units in this army GetUnitFromArmy(tmpArmy, i, tmpUnit); if (MM2_IsMilitia(tmpUnit.type)) { // if any of the units in this army is a Militia return STOP; // don't allow army to move } } } // prevent Militia units from boarding a transport HandleEvent(MoveIntoTransport) 'MM2_MilitiaBoard' pre { // triggers right before an army boards a transport int_t j; unit_t tmpUnit2; army_t tmpArmy2; tmpArmy2 = army[0]; for (j = 0; j < tmpArmy2.size; j = j + 1) { // cycle through all units in this army GetUnitFromArmy(tmpArmy2, j, tmpUnit2); if (MM2_IsMilitia(tmpUnit2.type)) { // if any of the units in this army is a Militia return STOP; // don't allow army to board } } } // prevent Militia units from attacking HandleEvent(Battle) 'MM2_MilitiaBattle' pre { // triggers right before a battle takes place int_t k; unit_t tmpUnit3; army_t tmpArmy3; tmpArmy3 = army[0]; // look at the attacking army for (k = 0; k < tmpArmy3.size; k = k + 1) { // cycle through all units in this army GetUnitFromArmy(tmpArmy3, k, tmpUnit3); if (MM2_IsMilitia(tmpUnit3.type)) { // if any of the units in this army is a Militia return STOP; // don't allow army to attack } } } // prevent Militia units from sleeping - just in case it boards a transport this way (note to self: check if really needed) HandleEvent(SleepUnit) 'MM2_MilitiaSleep' pre { // triggers right before a unit sleeps unit_t tmpUnit4; tmpUnit4 = unit[0]; if (MM2_IsMilitia(tmpUnit4.type)) { // if the unit is a Militia return STOP; // don't allow it to sleep } } // when a city grows in size, update # of Militias if needed HandleEvent(MakePop) 'MM2_MilitiaCityGrew' post { // triggers if city grew in size city_t tmpCity; tmpCity = city[0]; if (tmpCity.population > MM2_MILITIA_CITY_SIZE) { MM2_KillMilitia(12, tmpCity.location); } } // if city is disbanded, kill all Militia units HandleEvent(DisbandCity) 'MM2_MilitiaCityDisbanded' pre { // triggers if city is disbanded location_t tmpLoc; city_t tmpCity; tmpCity = city[0]; tmpLoc = tmpCity.location; MM2_KillMilitia(12, tmpLoc); // kill all Militias } // if city is destroyed (from hunger or war), kill all Militia units HandleEvent(KillCity) 'MM2_MilitiaCityDestroyed' pre { // triggers if city is destroyed unit_t tmpUnit; city_t tmpCity; int_t i; int_t tmpPlayer; tmpPlayer = player[0]; i = 0; while (i < player[0].units) { GetUnitByIndex(tmpPlayer, i, tmpUnit); // cycle through all units if (MM2_IsMilitia(tmpUnit.type)) { // if unit is a Militia unit GetCityByLocation(tmpUnit.location, tmpCity); if (!CityIsValid(tmpCity)) { // and it's not in a city KillUnit(tmpUnit); // kill it } } else { i = i + 1; // else look at next unit } } } ////////////////////////////// //// 2. Partisan Code //// //////////////////////////// // Description: // Partisans are units that are created outside a city when it conquered. They // belong to the civ that just lost the city and represent the 'resistance' // that is formed by citizens that are dissatisfied with the conquest of their // city, like what happened in occupied Europe during WWII. The distance to the // city depends on how many partisans are created (FE the first 4 partisans are // created at distance 2 from the city, all subsequent units at distance 3). // The number of Partisans created is based upon city size, like the militia // code. The code will only activate when the civ has discovered Nationalism. // Also, the code will only activate if the happiness in the city is lower than // before the city was conquered. This way, if you re-take a city you just // lost, you will not have to fight your own citizens. // create Partisan units near 'theCity' that are owned by 'prevOwner' (previous owner of that city) void_f MM2_CreatePartisans(city_t theCity, int_t prevOwner) { location_t tmpLoc; city_t tmpCity; unit_t tmpUnit; int_t i; int_t j; int_t number; int_t age; int_t dist; int_t previousOwner; previousOwner = prevOwner; tmpCity = theCity; tmpLoc = tmpCity.location; number = -100; for (i = 0; i < MM2_PARTISAN_ROUND.#; i = i + 1) { if (number == -100) { if (tmpCity.population <= MM2_PARTISAN_ROUND[i]) { // number of Partisans is same as number of Militias would be number = MM2_PARTISAN_NUMBER[i]; } } } // number = 1 + (tmpCity.population / MM2_PART_PER_POP); // NO LONGER USED: 1 Partisan per x citizens, x is determined in SetUp() for (i = 1; i <= number; i = i + 1) { // cycle through all units that are to be created dist = MM2_DISTANCE_FROM_CITY[i]; // determine how far from the city this Partisan should be age = MM2_GetAge(previousOwner); // based upon current age CreateUnit(previousOwner, MM2_PARTISAN_TYPE[age], tmpLoc, dist, tmpUnit); // give Partisan of this age Event:EntrenchUnit(tmpUnit); // and fortify it } } HandleEvent(CaptureCity) 'MM2_CaptureCity' post { // triggers if a city is captured if (MM2_cityHappiness > city[0].happiness) { // if old happiness higher than new happiness if (HasAdvance(MM2_cityOwner, ID_ADVANCE_NATIONALISM)) { MM2_CreatePartisans(city[0], MM2_cityOwner); // if the previous owner has Nationalism, create Partisans } } } ////////////////////////////// //// 3. Unit Repair Code //// //////////////////////////// // Description: // This code takes over the part of the ... // movement? timing? HandleEvent(BeginTurn) 'MM2_UnitRepair' post { city_t tmpCity; unit_t tmpUnit; int_t i; int_t j; int_t pw; int_t hpOld; int_t hpDif; int_t hpAffordable; int_t pwCost; int_t pwPerHp; int_t notEnough; int_t tmpPlayer; tmpPlayer = player[0]; notEnough = 0; player[5] = tmpPlayer; for (i = 0; i < player[5].cities; i = i + 1) { // cycle through all cities GetCityByIndex(tmpPlayer, i, tmpCity); for (j = 0; j < GetUnitsAtLocation(tmpCity.location); j = j + 1) { // cycle through all units in this city GetUnitFromCell(tmpCity.location, j, tmpUnit); // in other words: cycle through all units that are in a city hpOld = tmpUnit.hp; // store hp of unit Heal(tmpUnit); // repair unit completely hpDif = tmpUnit.hp - hpOld; // determine difference in hp before and after repair if (hpDif != 0) { // if unit actually needed repair pwPerHp = UnitDB(tmpUnit.type).ShieldCost / UnitDB(tmpUnit.type).MaxHP; pwPerHp = (pwPerHp * MM2_UNIT_REPAIR_NUM) / MM2_UNIT_REPAIR_DENOM; // calculate how many pw is needed to repair 1 hp of unit pwCost = hpDif * pwPerHp; // calculate amount of pw needed to fully repair unit pw = player[5].publicworkslevel; // determine how much pw player has if (pwCost <= pw) { // if player has enough pw SetPW(tmpPlayer, (pw - pwCost)); // subtract amount of pw needed to fully repair unit } elseif (pw > 0) { // if player doesn't have enough pw but at least some notEnough = 1; hpAffordable = pw / pwPerHp; // only enough pw to restore this many hp pwCost = hpAffordable * pwPerHp; // calculate cost of this repair (rounding down guarantees correct numbers) DamageUnit(tmpUnit, (hpDif - hpAffordable)); // damage unit for the part of the repair the player can't afford SetPW(tmpPlayer, (pw - pwCost)); // subtract amount of pw needed to repair this unit with this amount } else { // if (pw == 0) { // if no PW at all notEnough = 1; DamageUnit(tmpUnit, hpDif); // no healing happens at all, reparation is undone } } } } if (IsHumanPlayer(tmpPlayer) && notEnough == 1) { // if not enough pw and player is human player[5] = tmpPlayer; Message(1, 'MM2_NotEnoughPW_M'); // give message that more pw is needed } } Messagebox 'MM2_NotEnoughPW_M' { Text(ID_MM2_NOT_ENOUGH_PW); } /////////////////////////////// //// 4. Clear Orders Code //// ///////////////////////////// // Description: // This clears the orders of all units of 1/3 of all players every turn. The // next turn another (different) 1/3 of all players get all their unit's orders // cleared. The next turn the a last 1/3 of players gets all their unit's // orders cleared. The following turn this process starts all over again. The // practical effect of this is that every player has all it's unit's orders // cleared once every three turns. This gives the AI more oppurtunities to // rethink it's orders and redeploy it's units if the situation has changed // since the orders were given in the first place. // Clear all orders of all units of thePlayer void_f MM2_ClearOrders(int_t thePlayer) { unit_t tmpUnit; int_t i; int_t tmpPlayer; tmpPlayer = thePlayer; player[3] = tmpPlayer; for (i = 0; i < player[3].units; i = i + 1) { GetUnitByIndex(tmpPlayer, i, tmpUnit); // cycle through all units of this player ClearOrders(tmpUnit); // clear order of unit } } // every turn, clear all orders of 1/3 of the AIs (one particular AI will have his orders cleared every third turn) // (this spreads any slowdown caused by this trigger to be spread over // all turns instead of being concentrated in 1/3 of the turns) HandleEvent(BeginTurn) 'MM2_SetupClearOrders' post { int_t tmpPlayer; tmpPlayer = player[0]; if (!IsHumanPlayer(tmpPlayer)) { // this only applies to AI players if (g.year/3 == (g.year + 2)/3) { // if the year is part of the first partition if (tmpPlayer/3 == (tmpPlayer + 2)/3) { // and if the player is part of first partition MM2_ClearOrders(tmpPlayer); // clear orders of all this player's units } } elseif (g.year/3 == (g.year + 1)/3) { // if the year is part of the second partition if (tmpPlayer/3 != (tmpPlayer + 2)/3 && tmpPlayer/3 == (tmpPlayer + 1)/3) { // and the player is as well MM2_ClearOrders(tmpPlayer); // clear orders of all this player's units } } else { // if the year is part of the third and final partition if (tmpPlayer/3 != (tmpPlayer + 2)/3 && tmpPlayer/3 != (tmpPlayer + 1)/3) { // and the player is as well MM2_ClearOrders(tmpPlayer); // clear orders of all this player's units } } } } ////////////////////////////// //// 5. Wonder Code //// //////////////////////////// // Description: // This code makes takes those buildings out of the build lists of both AI and // human players that are no longer necessary because a Wonder was built by // this player that gives a free building of this type in every city. This // prevents the AI from building expensive buildings that it doesn't need // anyway and makes the build list more readable and less confusing for the // human. // make buildings unbuildable for civs with a wonder that grants those buildings int_f mod_CanCityBuildBuilding(city_t theCity, int_t theBuilding) { city_t tmpCity; int_t tmpBuilding; tmpBuilding = theBuilding; tmpCity = theCity; // if (!IsHumanPlayer(tmpCity.owner)) { // NO LONGER USED: humans can still build everything if (tmpBuilding == BuildingDB(IMPROVE_SHRINE)) { // if building is Shrine if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_TEMPLE_OF_KARNAK))) { // and player has Karnak return 0; // this cannot be built } else { return 1; // if player doesn't have Karnak, it can be built } } elseif (tmpBuilding == BuildingDB(IMPROVE_FORCEFIELD)) { if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_NATIONAL_SHIELD))) { return 0; } else { return 1; } } elseif (tmpBuilding == BuildingDB(IMPROVE_MATTER_DECOMPILER)) { if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_CENTRAL_MATTER_DECOMPILER))) { return 0; } else { return 1; } } elseif (tmpBuilding == BuildingDB(IMPROVE_BROKERAGE)) { if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_LONDON_EXCHANGE))) { return 0; } else { return 1; } } elseif (tmpBuilding == BuildingDB(IMPROVE_FOOD_SILO)) { if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_PENICILLIN))) { return 0; } else { return 1; } } elseif (tmpBuilding == BuildingDB(IMPROVE_THEATER)) { if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_RAMAYANA))) { return 0; } else { return 1; } } elseif (tmpBuilding == BuildingDB(IMPROVE_COMPUTER_CENTER)) { if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_INTERNET))) { return 0; } else { return 1; } } elseif (tmpBuilding == BuildingDB(IMPROVE_GRANARY)) { // if building is Granary if (PlayerHasWonder(tmpCity.owner, WonderDB(WONDER_STONEHENGE))) { return 0; } else { return 1; } } else { return 1; // all other buildings can always be built } // } else { // return 1; // NO LONGER USED: humans can still build everything // } } /////////////////////////////// //// 6. Capital Code //// ///////////////////////////// // Description: // This code asks AI players build a new capitol when the old one is lost (due // to combat/starvation/flooding/whatever). // function that actually finds a replacement city for the capital and makes it build a new one int_f MM2_CreateCapital(int_t thePlayer) { city_t tmpCity; city_t largestCity; int_t i; int_t size; int_t tmpPlayer; tmpPlayer = thePlayer; player[3] = tmpPlayer; if (player[3].cities > 1) { // if player has more cities size = -1; for (i = 0; i < player[3].cities; i = i + 1) { // cycle through all cities GetCityByIndex(tmpPlayer, 0, tmpCity); if (tmpCity.population > size && !CityHasBuilding(tmpCity, "IMPROVE_CAPITOL")) { // check for capitol needed since this is executed pre capture, so old capital is evaluated as well if (IsWonderAtHead(tmpCity) == -1) { // check for wonder at head of build queue is needed since ClearBuildQueue doesn't clear queues with wonders at head largestCity = tmpCity; // store city size = largestCity.population; } } } if (size > -1) { // if a city was found ClearBuildQueue(largestCity); // clear existing buildqueue AddBuildingToBuildList(largestCity, BuildingDB(IMPROVE_CAPITOL)); // start building a Capitol Event:BuyFront(largestCity); // (try to) rush buy it } } } // detect the capture of a Capital and call CreateCapital function HandleEvent(CaptureCity) 'MM2_CapitalCaptured' pre { int_t tmpPlayer; city_t tmpCity; tmpCity = city[0]; tmpPlayer = tmpCity.owner; player[3] = tmpPlayer; if (CityHasBuilding(tmpCity, "IMPROVE_CAPITOL")) { // if city is capital/has capitol if (!IsHumanPlayer(tmpPlayer)) { // if player isn't human MM2_CreateCapital(tmpPlayer); // find new capital } } } // detect the destruction of a Capital and call CreateCapital function HandleEvent(KillCity) 'MM2_CapitalCaptured' pre { int_t tmpPlayer1; city_t tmpCity1; tmpCity1 = city[0]; tmpPlayer1 = tmpCity1.owner; player[3] = tmpPlayer1; if (CityHasBuilding(tmpCity1, "IMPROVE_CAPITOL")) { if (!IsHumanPlayer(tmpPlayer1)) { MM2_CreateCapital(tmpPlayer1); } } } // detect the gift of a Capital and call CreateCapital function HandleEvent(GiveCity) 'MM2_CapitalCaptured' pre { int_t tmpPlayer2; city_t tmpCity2; tmpCity2 = city[0]; tmpPlayer2 = tmpCity2.owner; player[3] = tmpPlayer2; if (CityHasBuilding(tmpCity2, "IMPROVE_CAPITOL")) { // if (player[3].capital == tmpCity2) { if (!IsHumanPlayer(tmpPlayer2)) { MM2_CreateCapital(tmpPlayer2); } } } // detect the disbandment of a Capital and call CreateCapital function HandleEvent(DisbandCity) 'MM2_CapitalCaptured' pre { int_t tmpPlayer3; city_t tmpCity3; tmpCity3 = city[0]; tmpPlayer3 = tmpCity3.owner; player[3] = tmpPlayer3; if (CityHasBuilding(tmpCity3, "IMPROVE_CAPITOL")) { // if (player[3].capital == tmpCity3) { if (!IsHumanPlayer(tmpPlayer3)) { MM2_CreateCapital(tmpPlayer3); } } } // detect the park creation of a Capital and call CreateCapital function HandleEvent(CreatePark) 'MM2_CapitalCaptured' pre { int_t tmpPlayer4; city_t tmpCity4; tmpCity4 = city[0]; tmpPlayer4 = tmpCity4.owner; player[3] = tmpPlayer4; if (CityHasBuilding(tmpCity4, "IMPROVE_CAPITOL")) { // if (player[3].capital == tmpCity4) { if (!IsHumanPlayer(tmpPlayer4)) { MM2_CreateCapital(tmpPlayer4); } } } /////////////////////////////// //// 7. Slavery Code //// ///////////////////////////// // Description: Kill all units with slaving capabilities when era of slaves is over HandleEvent(BeginTurn) 'MM2_EndOfSlavery' post { unit_t tmpUnit; int_t i; int_t j; if (g.year == 400) { // if year is 400 for (i = 0; i < 32; i = i + 1) { // cycle through civs player[0] = i; for (j = 0; j < player[0].units; j = j + 1) { // cycle though units GetUnitByIndex(i, j, tmpUnit); if ( tmpUnit.type == UnitDB(UNIT_SWORDSMAN) || tmpUnit.type == UnitDB(UNIT_LIGHT_CAVALRY) || tmpUnit.type == UnitDB(UNIT_CHARIOT) || tmpUnit.type == UnitDB(UNIT_HEAVY_SWORDSMAN) || tmpUnit.type == UnitDB(UNIT_HEAVY_CAVALRY) || tmpUnit.type == UnitDB(UNIT_HORSE_ARCHER) || tmpUnit.type == UnitDB(UNIT_ZULU_WARRIOR) || tmpUnit.type == UnitDB(UNIT_BANDIT_HORSEMAN) || tmpUnit.type == UnitDB(UNIT_HOPLITE) || tmpUnit.type == UnitDB(UNIT_LEGION) || tmpUnit.type == UnitDB(UNIT_SAMURAI) || tmpUnit.type == UnitDB(UNIT_NOMADIC_HORSEMAN) || tmpUnit.type == UnitDB(UNIT_BERSERKER) ) { // if unit of any of the above types, KillUnit(tmpUnit); // kill it } } } } }