Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/config.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/config.js (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/config.js (revision 24597) @@ -1,291 +1,291 @@ PETRA.Config = function(difficulty, behavior) { // 0 is sandbox, 1 is very easy, 2 is easy, 3 is medium, 4 is hard and 5 is very hard. this.difficulty = difficulty !== undefined ? difficulty : 3; // for instance "balanced", "aggressive" or "defensive" this.behavior = behavior || "random"; // debug level: 0=none, 1=sanity checks, 2=debug, 3=detailed debug, -100=serializatio debug this.debug = 0; this.chat = true; // false to prevent AI's chats this.popScaling = 1; // scale factor depending on the max population this.Military = { "towerLapseTime": 90, // Time to wait between building 2 towers "fortressLapseTime": 390, // Time to wait between building 2 fortresses "popForBarracks1": 25, "popForBarracks2": 95, "popForForge": 65, "numSentryTowers": 1 }; // Define damage type importance factors here. this.DamageTypeImportance = { "Hack": 0.085, "Pierce": 0.075, "Crush": 0.065 }; this.Economy = { "popPhase2": 38, // How many units we want before aging to phase2. "workPhase3": 65, // How many workers we want before aging to phase3. "workPhase4": 80, // How many workers we want before aging to phase4 or higher. "popForDock": 25, "targetNumWorkers": 40, // dummy, will be changed later "targetNumTraders": 5, // Target number of traders "targetNumFishers": 1, // Target number of fishers per sea "supportRatio": 0.35, // fraction of support workers among the workforce "provisionFields": 2 }; // Note: attack settings are set directly in attack_plan.js // defense this.Defense = { "defenseRatio": { "ally": 1.4, "neutral": 1.8, "own": 2 }, // ratio of defenders/attackers. "armyCompactSize": 2000, // squared. Half-diameter of an army. "armyBreakawaySize": 3500, // squared. "armyMergeSize": 1400 // squared. }; // Additional buildings that the AI does not yet know when to build // and that it will try to build on phase 3 when enough resources. this.buildings = { "default": [], "athen": [ "structures/{civ}/gymnasium", "structures/{civ}/prytaneion", "structures/{civ}/theater" ], "brit": [], "cart": [ "structures/{civ}/embassy_celtic", "structures/{civ}/embassy_iberian", "structures/{civ}/embassy_italic" ], "gaul": [ - "structures/{civ}/tavern" + "structures/{civ}/assembly" ], "iber": [ "structures/{civ}/monument" ], "kush": [ "structures/{civ}/camp_blemmye", "structures/{civ}/camp_noba", "structures/{civ}/pyramid_large", "structures/{civ}/pyramid_small", "structures/{civ}/temple_amun" ], "mace": [ "structures/{civ}/library", "structures/{civ}/theater" ], "maur": [ "structures/{civ}/palace", "structures/{civ}/pillar_ashoka" ], "pers": [ "structures/{civ}/apadana" ], "ptol": [ "structures/{civ}/library" ], "rome": [ "structures/{civ}/army_camp", "structures/{civ}/temple_vesta" ], "sele": [ "structures/{civ}/library" ], "spart": [ "structures/{civ}/syssiton", "structures/{civ}/theater" ] }; this.priorities = { "villager": 30, // should be slightly lower than the citizen soldier one to not get all the food "citizenSoldier": 60, "trader": 50, "healer": 20, "ships": 70, "house": 350, "dropsites": 200, "field": 400, "dock": 90, "corral": 100, "economicBuilding": 90, "militaryBuilding": 130, "defenseBuilding": 70, "civilCentre": 950, "majorTech": 700, "minorTech": 40, "wonder": 1000, "emergency": 1000 // used only in emergency situations, should be the highest one }; // Default personality (will be updated in setConfig) this.personality = { "aggressive": 0.5, "cooperative": 0.5, "defensive": 0.5 }; // See PETRA.QueueManager.prototype.wantedGatherRates() this.queues = { "firstTurn": { "food": 10, "wood": 10, "default": 0 }, "short": { "food": 200, "wood": 200, "default": 100 }, "medium": { "default": 0 }, "long": { "default": 0 } }; this.garrisonHealthLevel = { "low": 0.4, "medium": 0.55, "high": 0.7 }; }; PETRA.Config.prototype.setConfig = function(gameState) { if (this.difficulty > 0) { // Setup personality traits according to the user choice: // The parameter used to define the personality is basically the aggressivity or (1-defensiveness) // as they are anticorrelated, although some small smearing to decorelate them will be added. // And for each user choice, this parameter can vary between min and max let personalityList = { "random": { "min": 0, "max": 1 }, "defensive": { "min": 0, "max": 0.27 }, "balanced": { "min": 0.37, "max": 0.63 }, "aggressive": { "min": 0.73, "max": 1 } }; let behavior = randFloat(-0.5, 0.5); // make agressive and defensive quite anticorrelated (aggressive ~ 1 - defensive) but not completelety let variation = 0.15 * randFloat(-1, 1) * Math.sqrt(Math.square(0.5) - Math.square(behavior)); let aggressive = Math.max(Math.min(behavior + variation, 0.5), -0.5) + 0.5; let defensive = Math.max(Math.min(-behavior + variation, 0.5), -0.5) + 0.5; let min = personalityList[this.behavior].min; let max = personalityList[this.behavior].max; this.personality = { "aggressive": min + aggressive * (max - min), "defensive": 1 - max + defensive * (max - min), "cooperative": randFloat(0, 1) }; } // Petra usually uses the continuous values of personality.aggressive and personality.defensive // to define its behavior according to personality. But when discontinuous behavior is needed, // it uses the following personalityCut which should be set such that: // behavior="aggressive" => personality.aggressive > personalityCut.strong && // personality.defensive < personalityCut.weak // and inversely for behavior="defensive" this.personalityCut = { "weak": 0.3, "medium": 0.5, "strong": 0.7 }; if (gameState.playerData.teamsLocked) this.personality.cooperative = Math.min(1, this.personality.cooperative + 0.30); else if (gameState.getAlliedVictory()) this.personality.cooperative = Math.min(1, this.personality.cooperative + 0.15); // changing settings based on difficulty or personality this.Military.towerLapseTime = Math.round(this.Military.towerLapseTime * (1.1 - 0.2 * this.personality.defensive)); this.Military.fortressLapseTime = Math.round(this.Military.fortressLapseTime * (1.1 - 0.2 * this.personality.defensive)); this.priorities.defenseBuilding = Math.round(this.priorities.defenseBuilding * (0.9 + 0.2 * this.personality.defensive)); if (this.difficulty < 2) { this.Economy.supportRatio = 0.5; this.Economy.provisionFields = 1; this.Military.numSentryTowers = this.personality.defensive > this.personalityCut.strong ? 1 : 0; } else if (this.difficulty < 3) { this.Economy.supportRatio = 0.4; this.Economy.provisionFields = 1; this.Military.numSentryTowers = this.personality.defensive > this.personalityCut.strong ? 1 : 0; } else { if (this.difficulty == 3) this.Military.numSentryTowers = 1; else this.Military.numSentryTowers = 2; if (this.personality.defensive > this.personalityCut.strong) ++this.Military.numSentryTowers; else if (this.personality.defensive < this.personalityCut.weak) --this.Military.numSentryTowers; if (this.personality.aggressive > this.personalityCut.strong) { this.Military.popForBarracks1 = 12; this.Economy.popPhase2 = 50; this.priorities.healer = 10; } } let maxPop = gameState.getPopulationMax(); if (this.difficulty < 2) this.Economy.targetNumWorkers = Math.max(1, Math.min(40, maxPop)); else if (this.difficulty < 3) this.Economy.targetNumWorkers = Math.max(1, Math.min(60, Math.floor(maxPop/2))); else this.Economy.targetNumWorkers = Math.max(1, Math.min(120, Math.floor(maxPop/3))); this.Economy.targetNumTraders = 2 + this.difficulty; if (gameState.getVictoryConditions().has("wonder")) { this.Economy.workPhase3 = Math.floor(0.9 * this.Economy.workPhase3); this.Economy.workPhase4 = Math.floor(0.9 * this.Economy.workPhase4); } if (maxPop < 300) { this.popScaling = Math.sqrt(maxPop / 300); this.Military.popForBarracks1 = Math.min(Math.max(Math.floor(this.Military.popForBarracks1 * this.popScaling), 12), Math.floor(maxPop/5)); this.Military.popForBarracks2 = Math.min(Math.max(Math.floor(this.Military.popForBarracks2 * this.popScaling), 45), Math.floor(maxPop*2/3)); this.Military.popForForge = Math.min(Math.max(Math.floor(this.Military.popForForge * this.popScaling), 30), Math.floor(maxPop/2)); this.Economy.popPhase2 = Math.min(Math.max(Math.floor(this.Economy.popPhase2 * this.popScaling), 20), Math.floor(maxPop/2)); this.Economy.workPhase3 = Math.min(Math.max(Math.floor(this.Economy.workPhase3 * this.popScaling), 40), Math.floor(maxPop*2/3)); this.Economy.workPhase4 = Math.min(Math.max(Math.floor(this.Economy.workPhase4 * this.popScaling), 45), Math.floor(maxPop*2/3)); this.Economy.targetNumTraders = Math.round(this.Economy.targetNumTraders * this.popScaling); } this.Economy.targetNumWorkers = Math.max(this.Economy.targetNumWorkers, this.Economy.popPhase2); this.Economy.workPhase3 = Math.min(this.Economy.workPhase3, this.Economy.targetNumWorkers); this.Economy.workPhase4 = Math.min(this.Economy.workPhase4, this.Economy.targetNumWorkers); if (this.difficulty < 2) this.Economy.workPhase3 = Infinity; // prevent the phasing to city phase if (this.debug < 2) return; API3.warn(" >>> Petra bot: personality = " + uneval(this.personality)); }; PETRA.Config.prototype.Serialize = function() { var data = {}; for (let key in this) if (this.hasOwnProperty(key) && key != "debug") data[key] = this[key]; return data; }; PETRA.Config.prototype.Deserialize = function(data) { for (let key in data) this[key] = data[key]; }; Index: ps/trunk/binaries/data/mods/public/simulation/components/Identity.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/Identity.js (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/components/Identity.js (revision 24597) @@ -1,204 +1,204 @@ function Identity() {} Identity.prototype.Schema = "Specifies various names and values associated with the entity, typically for GUI display to users." + "" + "athen" + "Athenian Hoplite" + "Hoplī́tēs Athēnaïkós" + "units/athen_infantry_spearman.png" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "tokens" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "Basic" + "Advanced" + "Elite" + "" + "" + "" + "" + "" + "" + "tokens" + "" + "" + "" + "" + "" + - "" + + "" + "" + "tokens" + "" + "" + "" + "" + "" + "" + "" + "tokens" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; Identity.prototype.Init = function() { this.classesList = GetIdentityClasses(this.template); this.visibleClassesList = GetVisibleIdentityClasses(this.template); if (this.template.Phenotype) this.phenotype = pickRandom(this.GetPossiblePhenotypes()); else this.phenotype = "default"; this.controllable = this.template.Controllable ? this.template.Controllable == "true" : true; }; Identity.prototype.HasSomeFormation = function() { return this.GetFormationsList().length > 0; }; Identity.prototype.GetCiv = function() { return this.template.Civ; }; Identity.prototype.GetLang = function() { return this.template.Lang || "greek"; // ugly default }; /** * Get a list of possible Phenotypes. * @return {string[]} A list of possible phenotypes. */ Identity.prototype.GetPossiblePhenotypes = function() { return this.template.Phenotype._string.split(/\s+/); }; /** * Get the current Phenotype. * @return {string} The current phenotype. */ Identity.prototype.GetPhenotype = function() { return this.phenotype; }; Identity.prototype.GetRank = function() { return this.template.Rank || ""; }; Identity.prototype.GetClassesList = function() { return this.classesList; }; Identity.prototype.GetVisibleClassesList = function() { return this.visibleClassesList; }; Identity.prototype.HasClass = function(name) { return this.GetClassesList().indexOf(name) != -1; }; Identity.prototype.GetFormationsList = function() { if (this.template.Formations && this.template.Formations._string) return this.template.Formations._string.split(/\s+/); return []; }; Identity.prototype.CanUseFormation = function(template) { return this.GetFormationsList().indexOf(template) != -1; }; Identity.prototype.GetSelectionGroupName = function() { return this.template.SelectionGroupName || ""; }; Identity.prototype.GetGenericName = function() { return this.template.GenericName; }; Identity.prototype.IsUndeletable = function() { return this.template.Undeletable == "true"; }; Identity.prototype.IsControllable = function() { return this.controllable; }; Identity.prototype.SetControllable = function(controllability) { this.controllable = controllability; }; Engine.RegisterComponentType(IID_Identity, "Identity", Identity); Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml (revision 24597) @@ -1,75 +1,86 @@ + + Council + - 500 + 200 - 500 - 500 + 400 10.0 - 5 + 20 0.1 Unit Support Infantry Cavalry 0 2 2000 decay|rubble/rubble_stone_6x6 gaul Assembly of Princes Remogantion - City Assembly + Train Heroes. + ConquestCritical CivSpecific + City Council structures/tholos.png phase_city - 100 - 100 + 80 + + 0.7 + + units/{civ}/hero_brennus + units/{civ}/hero_viridomarus + units/{civ}/hero_vercingetorix + + 20 30 3 - 3 + 1 10 - 3 + 1 interface/complete/building/complete_iber_monument.xml false - 100 + 40 40000 40 structures/gauls/theater.xml structures/fndn_6x6.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/fortress.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/fortress.xml (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/fortress.xml (revision 24597) @@ -1,32 +1,29 @@ gaul Dunon - Territory root. Train Champion Infantry and Heroes. Garrison Soldiers for additional arrows. + Territory root. Train Champion Infantry. Garrison Soldiers for additional arrows. 12 units/{civ}/champion_infantry - units/{civ}/hero_brennus - units/{civ}/hero_viridomarus - units/{civ}/hero_vercingetorix interface/complete/building/complete_fortress.xml structures/gauls/fortress.xml 16.8 5.8 Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_javelineer_b.xml (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_javelineer_b.xml (revision 24597) @@ -1,15 +1,20 @@ + + + structures/gaul/assembly + + gaul units/gaul/infantry_javelineer_b Adretos units/gaul_infantry_javelinist.png units/gaul/infantry_javelineer_a units/gauls/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_slinger_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_slinger_b.xml (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_slinger_b.xml (revision 24597) @@ -1,16 +1,21 @@ + + + structures/gaul/assembly + + gaul units/gaul/infantry_slinger_b Talmoris units/gaul_infantry_slinger.png phase_town units/gaul/infantry_slinger_a units/gauls/infantry_slinger_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_spearman_b.xml (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_spearman_b.xml (revision 24597) @@ -1,15 +1,20 @@ + + + structures/gaul/assembly + + gaul units/gaul/infantry_spearman_b Catucos units/gaul_infantry_spearman.png units/gaul/infantry_spearman_a units/gauls/infantry_spearman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/support_female_citizen.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/support_female_citizen.xml (revision 24596) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/support_female_citizen.xml (revision 24597) @@ -1,12 +1,17 @@ + + + structures/gaul/assembly + + gaul Celtic Woman Bena units/celt_support_female_citizen.png units/celts/female_citizen.xml