////////////////////////////////////////////////////////////////////////////// /// SLIC code for Medieval Pack II by Wouter Snijders /// //////////////////////////////////////////////////////////////////////////// // Author: Wouter Snijders (aka Locutus) // E-mail: locutus-of-borg@hetnet.nl // Last update: 2001-12-15 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 int_t MM2_PIRACY_BEGIN_TURN; // store in what turn piracy should become possible int_t MM2_PIRACY_CHANCE; // change of piracy attack; on average, 1 piracy attack every MM2_PIRACY_CHANCE turns // 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 //// MM2_PIRACY_BEGIN_TURN = 100; // after this many turns the piracy code gets activated MM2_PIRACY_CHANCE = 10; // one piracy attack every this many turns //// 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 } ////////////////////////////////////////////////////////////////////////////////////////// // // Unbuildable units framework for for Medpack II v1.0 by Chris Whitaker (Gedrin) // ///////////////////////////////////////////////////////////////////////////////////////// //int_t unitOwner[]; // index is UnitDB(UNIT_name); // outcommented by Wouter Snijders (2001-5-22), already declared in file MM2_SLC_Wouter.slc // value is PlayerCivilization(owner) iff >-1 // value is anyCiv iff =-1 // value is noCiv iff <-1 int_t ANYCIV; // -1 constant value representing a unit anyone can build. int_t NOCIV; // -2 constant value representing a unit no-one can build. // added by Wouter Snijders (2001-7-16) int_t TerrainCount[]; int_t TerrainTotal[]; // run once to set units that can/cannot be built at startup. HandleEvent(BeginTurn) 'BuildableUnitsSetup' Pre { int_t i; ANYCIV = -1; NOCIV = -2; // enable all units for anyCiv. Note there are 125 units in the med mod (75 added for extra units others might add, WS 2001-8-07). for(i = 0;i < 200;i = i + 1) { unitOwner[i] = ANYCIV; } // disable all unbuildable Units in this mod unitOwner[UnitDB(UNIT_ZULU_WARRIOR)] = NOCIV; unitOwner[UnitDB(UNIT_JAVELINEER)] = NOCIV; unitOwner[UnitDB(UNIT_ELEPHANT)] = NOCIV; unitOwner[UnitDB(UNIT_BANDIT_HORSEMAN)] = NOCIV; unitOwner[UnitDB(UNIT_CATAMARAN)] = NOCIV; unitOwner[UnitDB(UNIT_HOPLITE)] = NOCIV; unitOwner[UnitDB(UNIT_LEGION)] = NOCIV; unitOwner[UnitDB(UNIT_FIRE_TRIREME)] = NOCIV; unitOwner[UnitDB(UNIT_BERSERKER)] = NOCIV; unitOwner[UnitDB(UNIT_SAMURAI)] = NOCIV; unitOwner[UnitDB(UNIT_LONGBOWMAN)] = NOCIV; unitOwner[UnitDB(UNIT_NOMADIC_HORSEMAN)] = NOCIV; unitOwner[UnitDB(UNIT_LONGSHIP)] = NOCIV; unitOwner[UnitDB(UNIT_ARQUEBUSIER)] = NOCIV; unitOwner[UnitDB(UNIT_BOMBARD)] = NOCIV; unitOwner[UnitDB(UNIT_SPEARMAN_MILITIA)] = NOCIV; unitOwner[UnitDB(UNIT_PHALANX_MILITIA)] = NOCIV; unitOwner[UnitDB(UNIT_FYRDMAN_MILITIA)] = NOCIV; unitOwner[UnitDB(UNIT_MUSKETEER_MILITIA)] = NOCIV; unitOwner[UnitDB(UNIT_RIFLEMAN_MILITIA)] = NOCIV; unitOwner[UnitDB(UNIT_MACHINE_GUNNER_MILITIA)] = NOCIV; unitOwner[UnitDB(UNIT_PLASMATICA_MILITIA)] = NOCIV; DisableTrigger('BuildableUnitsSetup' ); } int_f mod_CanCityBuildUnit(city_t theCity, int_t theUnit) { city_t tmpCity; int_t tmpUnit; tmpUnit = theUnit; tmpCity = theCity; if (unitOwner[tmpUnit] == ANYCIV) { return 1; // ANYCIV can build it } elseif (PlayerCivilization(tmpCity.owner) == unitOwner[tmpUnit]) { return 1; // this civ can build it } else { return 0; // this civ can't build it (and perhaps NOCIV can). } } /////////////////////////////// //// 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 USEL: 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; } } elseif (tmpBuilding == BuildingDB(IMPROVE_GERM_THEORY)) { return 0; } elseif (tmpBuilding == BuildingDB(IMPROVE_IMMUNIZATION)) { return 0; } 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 //// //// --> Disband code //// ///////////////////////////// // old Description: Kill all units with slaving capabilities when era of slaves is over // new Description: Kill all units that are too old HandleEvent(BeginTurn) 'MM2_EndOfSlavery' post { unit_t tmpUnit; int_t i; int_t j; if (g.year == 300 || 400 || 475 || 550) { // if year is disband year 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 (g.year == 300) { // disband ancient units if ( tmpUnit.type == UnitDB(UNIT_WARRIOR) || tmpUnit.type == UnitDB(UNIT_SPEARMAN) || tmpUnit.type == UnitDB(UNIT_SWORDSMAN) || tmpUnit.type == UnitDB(UNIT_ARCHER) || tmpUnit.type == UnitDB(UNIT_CHARIOT) || tmpUnit.type == UnitDB(UNIT_LIGHT_CAVALRY) ) { KillUnit(tmpUnit); // kill it } } elseif (g.year == 400) { // disband classical units (& ancient elites) if ( tmpUnit.type == UnitDB(UNIT_PHALANX) || tmpUnit.type == UnitDB(UNIT_HEAVY_SWORDSMAN) || tmpUnit.type == UnitDB(UNIT_BOWMAN) || tmpUnit.type == UnitDB(UNIT_CATAPULT) || tmpUnit.type == UnitDB(UNIT_MOUNTED_ARCHER) || tmpUnit.type == UnitDB(UNIT_HEAVY_CAVALRY) || tmpUnit.type == UnitDB(UNIT_ZULU_WARRIOR) || tmpUnit.type == UnitDB(UNIT_JAVELINEER) || tmpUnit.type == UnitDB(UNIT_ELEPHANT) || tmpUnit.type == UnitDB(UNIT_BANDIT_HORSEMAN) || tmpUnit.type == UnitDB(UNIT_CORACLE) || tmpUnit.type == UnitDB(UNIT_TRIREME) ) { KillUnit(tmpUnit); // kill it } } elseif (g.year == 475) { // disband medieval units (& classical elites) if ( tmpUnit.type == UnitDB(UNIT_FYRDMAN) || tmpUnit.type == UnitDB(UNIT_PIKEMEN) || tmpUnit.type == UnitDB(UNIT_SIEGE_ENGINE) || tmpUnit.type == UnitDB(UNIT_HORSE_ARCHER) || tmpUnit.type == UnitDB(UNIT_KNIGHT) || tmpUnit.type == UnitDB(UNIT_HOPLITE) || tmpUnit.type == UnitDB(UNIT_LEGION) || tmpUnit.type == UnitDB(UNIT_FIRE_TRIREME) || tmpUnit.type == UnitDB(UNIT_CATAMARAN) ) { KillUnit(tmpUnit); // kill it } } elseif (g.year == 550) { // disband renaissance units (& medieval elites) if ( tmpUnit.type == UnitDB(UNIT_MUSKETEER) || tmpUnit.type == UnitDB(UNIT_INFANTRYMAN) || tmpUnit.type == UnitDB(UNIT_CULVERIN) || tmpUnit.type == UnitDB(UNIT_CANNON) || tmpUnit.type == UnitDB(UNIT_CAVALRY) || tmpUnit.type == UnitDB(UNIT_BERSERKER) || tmpUnit.type == UnitDB(UNIT_SAMURAI) || tmpUnit.type == UnitDB(UNIT_LONGBOWMAN) || tmpUnit.type == UnitDB(UNIT_NOMADIC_HORSEMAN) || tmpUnit.type == UnitDB(UNIT_LONGSHIP) || tmpUnit.type == UnitDB(UNIT_COG) ) { KillUnit(tmpUnit); // kill it } } // in all other years do nothing do nothing } } } } ////////////////////////////// //// 8. Piracy Code //// //////////////////////////// HandleEvent(BeginTurn) 'MM2_PiracyTest' post { location_t tmpLoc; int_t xcoord; int_t ycoord; int_t i; int_t type; if (g.player == 0 && Random(MM2_PIRACY_CHANCE) == 0 && g.year > MM2_PIRACY_BEGIN_TURN) { xcoord = Random(GetMapWidth()); ycoord = Random(GetMapHeight()); MakeLocation(tmpLoc, xcoord, ycoord); while (TerrainType(tmpLoc) < 10 || (TerrainType(tmpLoc) > 16 && TerrainType(tmpLoc) != 22 && TerrainType(tmpLoc) != 23)) { xcoord = Random(GetMapWidth()); ycoord = Random(GetMapHeight()); MakeLocation(tmpLoc, xcoord, ycoord); } for (i = 0; i < 32; i = i + 1) { if (IsPlayerAlive(i)) { if (HasAdvance(i, ID_ADVANCE_INTERNAL_COMBUSTION)) { type = UnitDB(UNIT_PT_BOAT); } elseif (HasAdvance(i, ID_ADVANCE_OCEAN_FARING)) { if (type != UnitDB(UNIT_PT_BOAT)) { type = UnitDB(UNIT_CARRACK); } } elseif (HasAdvance(i, ID_ADVANCE_COMPASS)) { if (type != UnitDB(UNIT_PT_BOAT) && type != UnitDB(UNIT_CARRACK)) { type = UnitDB(UNIT_COG); } } elseif (HasAdvance(i, ID_ADVANCE_JOINERY)) { if (type != UnitDB(UNIT_PT_BOAT) && type != UnitDB(UNIT_CARRACK) && type != UnitDB(UNIT_COG)) { type = UnitDB(UNIT_LONGSHIP); } } elseif (HasAdvance(i, ID_ADVANCE_SHIP_BUILDING)) { if (type != UnitDB(UNIT_PT_BOAT) && type != UnitDB(UNIT_CARRACK) && type != UnitDB(UNIT_COG) && type != UnitDB(UNIT_LONGSHIP)) { type = UnitDB(UNIT_TRIREME); } } else { type = -100; // don't create pirate unit } } } if (type != -100) { CreateUnit(0, type, tmpLoc, 0); } } } ///////////////////////////////////////////////////////////////////// // // SLIC2 EliteUnit trigger for CTP2v1.1 by Chris Whitaker (Gedrin) // ///////////////////////////////////////////////////////////////////// // idea: count city square itself twice? //// Terrain Calculations //// // added by Wouter Snijders (2001-7-16) void_f MM2_AddTerrain(city_t theCity) { location_t tmpLoc; city_t tmpCity; int_t i; tmpCity = theCity; TerrainCount[tmpCity.owner * 30 + TerrainType(tmpCity.location)] = TerrainCount[tmpCity.owner * 30 + TerrainType(tmpCity.location)] + 1; TerrainTotal[tmpCity.owner] = TerrainTotal[tmpCity.owner] + 1; for (i = 0; i < 8; i = i + 1) { if (GetNeighbor(tmpCity.location, i, tmpLoc)) { TerrainCount[tmpCity.owner * 30 + TerrainType(tmpLoc)] = TerrainCount[tmpCity.owner * 30 + TerrainType(tmpLoc)] + 1; TerrainTotal[tmpCity.owner] = TerrainTotal[tmpCity.owner] + 1; } } } // added by Wouter Snijders (2001-7-16) -> edited by Wouter Snijders (2001-12-15): NO LONGER USED void_f MM2_SubTerrain(city_t theCity) { location_t tmpLoc; city_t tmpCity; int_t i; tmpCity = theCity; TerrainCount[tmpCity.owner * 30 + TerrainType(tmpCity.location)] = TerrainCount[tmpCity.owner * 30 + TerrainType(tmpCity.location)] - 1; TerrainTotal[tmpCity.owner] = TerrainTotal[tmpCity.owner] - 1; for (i = 0; i < 8; i = i + 1) { if (GetNeighbor(tmpCity.location, i, tmpLoc)) { TerrainCount[tmpCity.owner * 30 + TerrainType(tmpLoc)] = TerrainCount[tmpCity.owner * 30 + TerrainType(tmpLoc)] - 1; TerrainTotal[tmpCity.owner] = TerrainTotal[tmpCity.owner] - 1; } } } // added by Wouter Snijders (2001-12-15) HandleEvent(BeginTurn) 'MM2_EliteTerrainCalc' post { city_t tmpCity; int_t i; int_t tmpPlayer; tmpPlayer = player[0]; TerrainTotal[tmpPlayer] = 0; // reset total for (i = 0; i < 30; i = i + 1) { TerrainCount[tmpPlayer * 30 + i] = 0; // reset all terrain types } for (i = 0; i < player[0].cities; i = i + 1) { GetCityByIndex(tmpPlayer, i, tmpCity); MM2_AddTerrain(tmpCity); // recalc values } } // edited by Wouter Snijders (2001-12-15): Due to a bug the following eventhandlers have become obsolete and are no longer used //// added by Wouter Snijders (2001-7-16) //HandleEvent(CreateCity) 'MM2_EliteCreateCity' post { // MM2_AddTerrain(city[0]); ////// test code //int_t i; // value[0] = player[0] * 30; // for (i = 1; i < 30; i = i + 1) { // value[i] = value[i - 1] + 1; // } // for (i = 0; i < 30; i = i + 1) { // value[i] = TerrainCount[value[i]]; // } // value[31] = TerrainTotal[player[0]]; //// Message(1, 'MM2_Terrain'); // out-comment to disable test message //} ////// added by Wouter Snijders (2001-7-16) //HandleEvent(CaptureCity) 'MM2_EliteCaptureCity' post { // MM2_AddTerrain(city[0]); //// test code //int_t i; // value[0] = player[0] * 30; // for (i = 1; i < 30; i = i + 1) { // value[i] = value[i - 1] + 1; // } // for (i = 0; i < 30; i = i + 1) { // value[i] = TerrainCount[value[i]]; // } // value[31] = TerrainTotal[player[0]]; ////// Message(1, 'MM2_Terrain'); // out-comment to disable test message //} //// added by Wouter Snijders (2001-7-16) //HandleEvent(KillCity) 'MM2_EliteKillCity' pre { // MM2_SubTerrain(city[0]); ////// test code //int_t i; // value[0] = player[0] * 30; // for (i = 1; i < 30; i = i + 1) { // value[i] = value[i - 1] + 1; // } // for (i = 0; i < 30; i = i + 1) { // value[i] = TerrainCount[value[i]]; // } // value[31] = TerrainTotal[player[0]]; //// Message(1, 'MM2_Terrain'); // out-comment to disable test message //} // ////// added by Wouter Snijders (2001-7-16) //HandleEvent(DisbandCity) 'MM2_EliteDisbandCity' pre { // MM2_SubTerrain(city[0]); //// test code //int_t i; // value[0] = player[0] * 30; // for (i = 1; i < 30; i = i + 1) { // value[i] = value[i - 1] + 1; // } // for (i = 0; i < 30; i = i + 1) { // value[i] = TerrainCount[value[i]]; // } // value[31] = TerrainTotal[player[0]]; ////// Message(1, 'MM2_Terrain'); // out-comment to disable test message //} //// added by Wouter Snijders (2001-7-16) //HandleEvent(CaptureCity) 'MM2_EliteCityCaptured' pre { // MM2_SubTerrain(city[0]); ////// test code //int_t i; // value[0] = city[0].owner * 30; // for (i = 1; i < 30; i = i + 1) { // value[i] = value[i - 1] + 1; // } // for (i = 0; i < 30; i = i + 1) { // value[i] = TerrainCount[value[i]]; // } // value[31] = TerrainTotal[city[0].owner]; // Message(1, 'MM2_GotHere'); // out-comment to disable test message //} // Test Message - added by Wouter Snijders (2001-8-07) // MessageBox 'MM2_Terrain' { // Text(ID_MM2_TERRAIN_TEST); //} //// Unit Calculations //// // added by Wouter Snijders (2001-8-07) int_f MM2_ZuluChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_BROWN_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_MOUNTAIN)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_BROWN_MOUNTAIN)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-8-07) int_f MM2_ElephantChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_JUNGLE)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-8-07) int_f MM2_BanditChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_DESERT)] + TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_BROWN_HILL)] + TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_BROWN_MOUNTAIN)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-8-07) int_f MM2_CatamaranChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_WATER_BEACH)] + TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_JUNGLE)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-11-15) int_f MM2_HopliteChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_GRASSLAND)] + TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_PLAINS)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-11-15) int_f MM2_LegionChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_WHITE_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_BROWN_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_MOUNTAIN)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_WHITE_MOUNTAIN)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_BROWN_MOUNTAIN)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-11-15) int_f MM2_TriremeChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_WATER_BEACH)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-11-15) int_f MM2_BerserkerChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_WATER_BEACH)] + TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_FOREST)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-11-15) int_f MM2_SamuraiChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_WHITE_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_BROWN_HILL)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_MOUNTAIN)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_WHITE_MOUNTAIN)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_BROWN_MOUNTAIN)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-11-15) int_f MM2_LongbowChance(int_t thePlayer) { int_t terrain; int_t chance; int_t tmpCiv; tmpCiv = thePlayer; terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_FOREST)] + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_JUNGLE)]; chance = 10 - ((15 * terrain) / (TerrainTotal[tmpCiv])); if (chance <= 0) { return 1; } else { if (Random(chance) == 0) { return 1; } else { return 0; } } } // added by Wouter Snijders (2001-11-15) //int_f MM2_NomadicChance(int_t thePlayer) { //int_t terrain; //int_t chance; //int_t tmpCiv; // tmpCiv = thePlayer; // // terrain = TerrainCount[tmpCiv * 30 + TerrainDB(TERRAIN_GRASSLAND)] // + TerrainCount[(tmpCiv * 30) + TerrainDB(TERRAIN_PLAINS)]; // chance = 10 - ((10 * terrain) / (TerrainTotal[tmpCiv])); // if (chance <= 0) { // return 1; // } else { // if (Random(chance) == 0) { // return 1; // } else { // return 0; // } // } //} //// Unit Assignments //// // updated by Wouter Snijders (2001-8-07) HandleEvent(GrantAdvance) 'GrantEliteUnit' Post { // trigger off certain advances and grant the elite unit group if they are not already granted int_t tmpCiv; int_t advanceType; advanceType = value[0]; advance[0] = advanceType; unitrecord[1] = UnitDB(UNIT_ARCHER); tmpCiv = player[0]; tmpCiv = PlayerCivilization(tmpCiv); if ((advanceType == AdvanceDB(ADVANCE_BRONZE_WORKING)) && (unitOwner[UnitDB(UNIT_ZULU_WARRIOR)] == NOCIV) && (unitOwner[UnitDB(UNIT_ELEPHANT)] != tmpCiv) && (unitOwner[UnitDB(UNIT_BANDIT_HORSEMAN)] != tmpCiv) && (unitOwner[UnitDB(UNIT_CATAMARAN)] != tmpCiv) && (MM2_ZuluChance(player[0]))) { unitOwner[UnitDB(UNIT_ZULU_WARRIOR)] = tmpCiv; unitOwner[UnitDB(UNIT_JAVELINEER)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_ZULU_WARRIOR); unitrecord[1] = UnitDB(UNIT_JAVELINEER); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_DOMESTICATION)) && (unitOwner[UnitDB(UNIT_ZULU_WARRIOR)] != tmpCiv) && (unitOwner[UnitDB(UNIT_ELEPHANT)] == NOCIV) && (unitOwner[UnitDB(UNIT_BANDIT_HORSEMAN)] != tmpCiv) && (unitOwner[UnitDB(UNIT_CATAMARAN)] != tmpCiv) && (MM2_ElephantChance(player[0]))) { unitOwner[UnitDB(UNIT_ELEPHANT)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_ELEPHANT); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_TRADE)) && (unitOwner[UnitDB(UNIT_ZULU_WARRIOR)] != tmpCiv) && (unitOwner[UnitDB(UNIT_ELEPHANT)] != tmpCiv) && (unitOwner[UnitDB(UNIT_BANDIT_HORSEMAN)] == NOCIV) && (unitOwner[UnitDB(UNIT_CATAMARAN)] != tmpCiv) && (MM2_BanditChance(player[0]))) { unitOwner[UnitDB(UNIT_BANDIT_HORSEMAN)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_BANDIT_HORSEMAN); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_SHIP_BUILDING)) && (unitOwner[UnitDB(UNIT_ZULU_WARRIOR)] != tmpCiv) && (unitOwner[UnitDB(UNIT_ELEPHANT)] != tmpCiv) && (unitOwner[UnitDB(UNIT_BANDIT_HORSEMAN)] != tmpCiv) && (unitOwner[UnitDB(UNIT_CATAMARAN)] == NOCIV) && (MM2_CatamaranChance(player[0]))) { unitOwner[UnitDB(UNIT_CATAMARAN)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_CATAMARAN); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_INFANTRY_TACTICS)) && (unitOwner[UnitDB(UNIT_HOPLITE)] == NOCIV) && (unitOwner[UnitDB(UNIT_LEGION)] != tmpCiv) && (unitOwner[UnitDB(UNIT_FIRE_TRIREME)] != tmpCiv) && (MM2_HopliteChance(player[0]))) { unitOwner[UnitDB(UNIT_HOPLITE)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_HOPLITE); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_CITIZENSHIP)) && (unitOwner[UnitDB(UNIT_HOPLITE)] != tmpCiv) && (unitOwner[UnitDB(UNIT_LEGION)] == NOCIV) && (unitOwner[UnitDB(UNIT_FIRE_TRIREME)] != tmpCiv) && (MM2_LegionChance(player[0]))) { unitOwner[UnitDB(UNIT_LEGION)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_LEGION); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_ALCHEMY)) && (unitOwner[UnitDB(UNIT_HOPLITE)] != tmpCiv) && (unitOwner[UnitDB(UNIT_LEGION)] != tmpCiv) && (unitOwner[UnitDB(UNIT_FIRE_TRIREME)] == NOCIV) && (MM2_TriremeChance(player[0]))) { unitOwner[UnitDB(UNIT_FIRE_TRIREME)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_FIRE_TRIREME); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_JOINERY)) && (unitOwner[UnitDB(UNIT_BERSERKER)] == NOCIV) && (unitOwner[UnitDB(UNIT_SAMURAI)] != tmpCiv) && (unitOwner[UnitDB(UNIT_LONGBOWMAN)] != tmpCiv) && // (unitOwner[UnitDB(UNIT_NOMADIC_HORSEMAN)] != tmpCiv) && (MM2_BerserkerChance(player[0]))) { unitOwner[UnitDB(UNIT_BERSERKER)] = tmpCiv; unitOwner[UnitDB(UNIT_LONGSHIP)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_BERSERKER); unitrecord[1] = UnitDB(UNIT_LONGSHIP); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_FEUDALISM)) && (unitOwner[UnitDB(UNIT_BERSERKER)] != tmpCiv) && (unitOwner[UnitDB(UNIT_SAMURAI)] == NOCIV) && (unitOwner[UnitDB(UNIT_LONGBOWMAN)] != tmpCiv) && // (unitOwner[UnitDB(UNIT_NOMADIC_HORSEMAN)] != tmpCiv) && (MM2_SamuraiChance(player[0]))) { unitOwner[UnitDB(UNIT_SAMURAI)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_SAMURAI); Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_MECHANICAL_POWER)) && (unitOwner[UnitDB(UNIT_BERSERKER)] != tmpCiv) && (unitOwner[UnitDB(UNIT_SAMURAI)] != tmpCiv) && (unitOwner[UnitDB(UNIT_LONGBOWMAN)] == NOCIV) && // (unitOwner[UnitDB(UNIT_NOMADIC_HORSEMAN)] != tmpCiv) && (MM2_LongbowChance(player[0]))) { unitOwner[UnitDB(UNIT_LONGBOWMAN)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_LONGBOWMAN); Message(1, 'MM2_EliteMessage'); // } elseif ((advanceType == AdvanceDB(ADVANCE_CAVALRY_TACTICS)) && // (unitOwner[UnitDB(UNIT_BERSERKER)] != tmpCiv) && // (unitOwner[UnitDB(UNIT_SAMURAI)] != tmpCiv) && // (unitOwner[UnitDB(UNIT_LONGBOWMAN)] != tmpCiv) && // (unitOwner[UnitDB(UNIT_NOMADIC_HORSEMAN)] == NOCIV) && // (MM2_NomadicChance(player[0]))) { // unitOwner[UnitDB(UNIT_NOMADIC_HORSEMAN)] = tmpCiv; // unitrecord[0] = UnitDB(UNIT_NOMADIC_HORSEMAN); // Message(1, 'MM2_EliteMessage'); } elseif ((advanceType == AdvanceDB(ADVANCE_GUNPOWDER)) && (unitOwner[UnitDB(UNIT_ARQUEBUSIER)] == NOCIV) && (Random(6) == 0)) { // no info available unitOwner[UnitDB(UNIT_ARQUEBUSIER)] = tmpCiv; unitOwner[UnitDB(UNIT_BOMBARD)] = tmpCiv; unitrecord[0] = UnitDB(UNIT_ARQUEBUSIER); unitrecord[1] = UnitDB(UNIT_BOMBARD); Message(1, 'MM2_EliteMessage'); MM2_EliteMilitiaSetup(player[0]); // defined in file MM2_SLC_Wouter.slc } } // added by Wouter Snijders (2001-5-13) Messagebox 'MM2_EliteMessage' { Show(); if (player[0] == 1) { if (unitrecord[1] == UnitDB(UNIT_ARCHER)) { Text(ID_MM2_ELITE_UNITS_US_1); } else { Text(ID_MM2_ELITE_UNITS_US_2); } } else { if (unitrecord[1] == UnitDB(UNIT_ARCHER)) { Text(ID_MM2_ELITE_UNITS_THEM_1); } else { Text(ID_MM2_ELITE_UNITS_THEM_2); } } } // to be removed: // >>>>>>>>>>>>>>>>>>>>>>>>> Explanation for Terrain Dependent Elite Units <<<<<<<<<<<<<<<<<<<<<<<<< // // *** First Example *** // Elephant: (Random(6 - ElephantChance) == 0) // *** Explanation *** // JungleQuotient = Number of Jungle tiles / Total number of tiles // = TerrainCount(playerOffset + JungleIndex) / TerrainTotal(player) // Chance to get unit = 1 : (basechance - 2/3 * JungleQuotient * basechance) // -> here: basechance = 6; 2/3 is a factor to ensure the weight of the terrain isn't too strong, randomness should always play a part (or not?) // // *** Second Code Example *** // Catamaran: (Random(6 - CatamaranChance) == 0) // *** Explanation *** // WaterQuotient = (Number of Beach tiles + Number of Shallow tiles) / Total number of tiles // = (TerrainCount(playerOffset + BeachIndex) + TerrainCount(playerOffset + ShallowIndex)) / TerrainTotal(player) // Chance to get unit = 1 : (basechance - 5/6 * WaterQuotient * basechance) // // *** Final Code Example *** // Bandit Horsemen: (Random(6 - BanditChance) == 0) // *** Explanation *** // FlatQuotient = (Grassland + Plains - Hills - Mountains) / Total // = TerrainCount(playerOffset + GrasslandIndex) + TerrainCount(playerOffset + PlainsIndex) - TerrainCount(playerOffset + HillsIndex) - TerrainCount(playerOffset + BrownHillsIndex) - TerrainCount(playerOffset + MountainIndex) - TerrainCount(playerOffset + BrownMountainIndex) / TerrainTotal(player) // Chance to get unit = 1 : (basechance - 3/4 * FlatQuotient * basechance) // // The code looks so confusing (initially) because of limitiations of SLIC, // I tried to write it down as logically (not as briefly) as I could // - written by Wouter Snijders (2001-7-16) //// template function: //// //int_f MM2_Chance(int_t thePlayer) { //int_t terrain; //int_t chance; //int_t tmpCiv; // tmpCiv = thePlayer; // // terrain = TerrainCount[(tmpCiv * 30 + TerrainDB()] <+|-> TerrainCount[(tmpCiv * 30 + TerrainDB()]> ; // // --> these are the terrain types that (positively or negatively) affect the chance of getting the unit ('+' = increase of change, '-' = decrease) // note: multiplication makes certain terrain weigh more than other terrain types (possibly add a division at the end to ensure terrainvalue never exceeds total number of tiles, since this could severely decrease randomness) // chance = - (( * * terrain) / ( * TerrainTotal[tmpCiv])); // // --> the actual chance of getting the unit; base_chance is the chance of getting the unit if terrain has no impact (1:6 for old version); // // factor_[denomenator|numerator] is a factor that determines how big the role of terrain is (there should/could always be some degree of randomness) // // (factor 1/4 means terrain will determine chance of getting a unit for 1/4, randomness will determine it for 3/4) // if (chance <= 0) { // return 1; // } else { // if (Random(chance) == 0) { // return 1; // } else { // return 0; // } // } //} // - written by Wouter Snijders (2001-8-07)