Ticket #4142: 4142_petra_regicide_support_v1.5.patch

File 4142_petra_regicide_support_v1.5.patch, 8.7 KB (added by Sandarac, 7 years ago)

Update and apply mimo's remarks, except without Maps.

  • binaries/data/mods/public/simulation/ai/common-api/entity.js

     
    745745    garrisoned: function() { return this._entity.garrisoned; },
    746746    canGarrisonInside: function() { return this._entity.garrisoned.length < this.garrisonMax(); },
    747747
     748    "canGuard": function() { return this.get("UnitAI/CanGuard") === "true"; },
     749
    748750    move: function(x, z, queued = false) {
    749751        Engine.PostCommand(PlayerID,{"type": "walk", "entities": [this.id()], "x": x, "z": z, "queued": queued });
    750752        return this;
     
    929931            if (item.progress < percentToStopAt)
    930932                Engine.PostCommand(PlayerID,{ "type": "stop-production", "entity": this.id(), "id": item.id });
    931933        return this;
     934    },
     935
     936    "guard": function(target, queued = false) {
     937        Engine.PostCommand(PlayerID, { "type": "guard", "entities": [this.id()], "target": target.id(), "queued": queued });
     938        return this;
     939    },
     940
     941    "removeGuard": function() {
     942        Engine.PostCommand(PlayerID, { "type": "remove-guard", "entities": [this.id()] });
     943        return this;
    932944    }
    933945});
    934946
  • binaries/data/mods/public/simulation/ai/petra/gameTypeManager.js

     
    33
    44/**
    55 * Handle events that are important to specific gameTypes
     6 * In regicide, train and manage healer guards for the hero
    67 * TODO: Handle when there is more than one hero in regicide
    78 * TODO: Assign military units to guard the hero in regicide
    89 */
    910
    10 m.GameTypeManager = function()
     11m.GameTypeManager = function(Config)
    1112{
     13    this.Config = Config;
    1214    this.heroGarrisonEmergency = false;
     15    this.healersAssignedToHero = 0; // Accounts for healers being trained as well
     16    this.heroGuards = []; // Holds ents currently guarding the hero
    1317};
    1418
    1519/**
     
    8084        }
    8185    }
    8286
    83     if (!this.heroGarrisonEmergency)
    84         return;
     87    // check if new healers/guards need to be assigned to the hero
     88    for (let evt of events.Destroy)
     89    {
     90        if (!evt.entityObj || evt.entityObj.owner() !== PlayerID ||
     91            this.heroGuards.indexOf(evt.entityObj.id()) === -1)
     92            continue;
    8593
     94        this.heroGuards.splice(this.heroGuards.indexOf(evt.entityObj.id()), 1);
     95        if (evt.entityObj.hasClass("Healer"))
     96            --this.healersAssignedToHero;
     97    }
     98
     99    for (let evt of events.TrainingFinished)
     100        for (let entId of evt.entities)
     101        {
     102            let ent = gameState.getEntityById(entId);
     103            if (!ent || !ent.isOwn(PlayerID) || ent.getMetadata(PlayerID, "role") !== "regicideHealer")
     104                continue;
     105
     106            this.assignGuardToRegicideHero(gameState, ent);
     107        }
     108
    86109    for (let evt of events.Garrison)
    87         if (gameState.getEntityById(evt.entity).hasClass("Hero"))
     110    {
     111        let ent = gameState.getEntityById(evt.entity);
     112        if (!ent || !ent.isOwn(PlayerID) || !ent.hasClass("Hero"))
     113            continue;
     114
     115        if (this.heroGarrisonEmergency)
    88116            this.heroGarrisonEmergency = false;
     117
     118        if (!gameState.getEntityById(evt.holder).hasClass("Ship"))
     119            continue;
     120
     121        // If the hero is garrisoned on a ship, remove its guards
     122        for (let guardId of this.heroGuards)
     123            gameState.getEntityById(guardId).removeGuard();
     124
     125        this.heroGuards = [];
     126    }
     127
     128    for (let evt of events.UnGarrison)
     129    {
     130        let ent = gameState.getEntityById(evt.entity);
     131        if (!ent || !ent.isOwn(PlayerID))
     132            continue;
     133
     134        // If this ent travelled to a hero's accessValue, try again to assign as a guard
     135        if (ent.getMetadata(PlayerID, "role") === "regicideHealer" &&
     136            this.heroGuards.indexOf(evt.entity) === -1)
     137        {
     138            this.assignGuardToRegicideHero(gameState, ent);
     139            continue;
     140        }
     141
     142        if (!ent.hasClass("Hero"))
     143            continue;
     144
     145        // If this is the hero, try to assign ents that should be guarding it, but couldn't previously
     146        let regicideHealers = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "role", "regicideHealer"));
     147        for (let healer of regicideHealers.values())
     148        {
     149            if (this.heroGuards.indexOf(healer.id()) !== -1)
     150                continue;
     151
     152            this.assignGuardToRegicideHero(gameState, healer);
     153        }
     154    }
    89155};
    90156
    91157m.GameTypeManager.prototype.buildWonder = function(gameState, queues)
     
    116182        heroEnt.move(basePos.anchor.position()[0], basePos.anchor.position()[1]);
    117183};
    118184
     185m.GameTypeManager.prototype.trainRegicideHealer = function(gameState, queues)
     186{
     187    if (gameState.ai.HQ.saveResources || !gameState.getOwnEntitiesByClass("Temple", true).hasEntities())
     188        return;
     189
     190    let template = gameState.applyCiv("units/{civ}_support_healer_b");
     191
     192    queues.villager.addPlan(new m.TrainingPlan(gameState, template, { "role": "regicideHealer", "base": 0 }, 1, 1));
     193    ++this.healersAssignedToHero;
     194};
     195
     196/**
     197 * Only send the guard command if the guard's accessIndex is the same as the hero
     198 * and the hero has a position (i.e. not garrisoned)
     199 * request a transport if the accessIndex value is different
     200 */
     201m.GameTypeManager.prototype.assignGuardToRegicideHero = function(gameState, ent)
     202{
     203    let heroEnt = gameState.getOwnEntitiesByClass("Hero", true).toEntityArray()[0];
     204    if (!heroEnt || !heroEnt.position() || !ent.position() || !ent.canGuard())
     205        return;
     206
     207    let entAccess = gameState.ai.accessibility.getAccessValue(ent.position());
     208    let heroAccess = gameState.ai.accessibility.getAccessValue(heroEnt.position());
     209    if (entAccess && entAccess === heroAccess)
     210    {
     211        ent.guard(heroEnt);
     212        this.heroGuards.push(ent.id());
     213        return;
     214    }
     215    gameState.ai.HQ.navalManager.requireTransport(gameState, ent, entAccess, heroAccess, heroEnt.position());
     216};
     217
    119218m.GameTypeManager.prototype.update = function(gameState, events, queues)
    120219{
    121220    this.checkEvents(gameState, events);
     
    122221
    123222    if (gameState.getGameType() === "wonder")
    124223        this.buildWonder(gameState, queues);
    125     else if (gameState.getGameType() === "regicide" && gameState.ai.playedTurn % 50 === 0)
     224
     225    if (gameState.getGameType() !== "regicide")
     226        return;
     227
     228    if (gameState.ai.playedTurn % 50 === 0)
    126229    {
    127230        let heroEnt = gameState.getOwnEntitiesByClass("Hero", true).toEntityArray()[0];
    128231        if (heroEnt && heroEnt.healthLevel() > 0.7)
    129232            heroEnt.setStance("aggressive");
    130233    }
     234
     235    if (this.healersAssignedToHero < 2 + Math.round(this.Config.personality.defensive * 2))
     236        this.trainRegicideHealer(gameState, queues);
    131237};
    132238
    133239m.GameTypeManager.prototype.Serialize = function()
    134240{
    135     return { "heroGarrisonEmergency": this.heroGarrisonEmergency };
     241    return {
     242        "heroGarrisonEmergency": this.heroGarrisonEmergency,
     243        "healersAssignedToHero": this.healersAssignedToHero,
     244        "heroGuards": this.heroGuards
     245    };
    136246};
    137247
    138248m.GameTypeManager.prototype.Deserialize = function(data)
  • binaries/data/mods/public/simulation/ai/petra/garrisonManager.js

     
    215215{
    216216    ent.stopMoving();
    217217    this.leaveGarrison(ent);
    218     let holderId = ent.getMetadata(PlayerId, "garrisonHolder");
     218    let holderId = ent.getMetadata(PlayerID, "garrisonHolder");
    219219    if (!holderId || !this.holders.has(holderId))
    220220        return;
    221221    let list = this.holders.get(holderId);
  • binaries/data/mods/public/simulation/ai/petra/headquarters.js

     
    5151    this.researchManager = new m.ResearchManager(this.Config);
    5252    this.diplomacyManager = new m.DiplomacyManager(this.Config);
    5353    this.garrisonManager = new m.GarrisonManager();
    54     this.gameTypeManager = new m.GameTypeManager();
     54    this.gameTypeManager = new m.GameTypeManager(this.Config);
    5555};
    5656
    5757/** More initialisation for stuff that needs the gameState */
     
    12681268        gameState.getOwnEntitiesByClass("Temple", true).hasEntities() ||
    12691269        !gameState.getOwnEntitiesByClass("BarterMarket", true).hasEntities())
    12701270        return;
    1271     if (gameState.currentPhase() < 3)
     1271    // Try to build a temple earlier if in regicide to recruit healer guards
     1272    if (gameState.currentPhase() < 3 && gameState.getGameType() !== "regicide")
    12721273    {
    12731274        if (gameState.currentPhase() < 2 || this.econState !== "cityPhasing")
    12741275            return;
     
    22792280    this.garrisonManager = new m.GarrisonManager();
    22802281    this.garrisonManager.Deserialize(data.garrisonManager);
    22812282
    2282     this.gameTypeManager = new m.GameTypeManager();
     2283    this.gameTypeManager = new m.GameTypeManager(this.Config);
    22832284    this.gameTypeManager.Deserialize(data.gameTypeManager);
    22842285};
    22852286