Ticket #4143: petra_lastmanstanding_v1.3_rebased.patch

File petra_lastmanstanding_v1.3_rebased.patch, 15.7 KB (added by elexis, 7 years ago)
  • binaries/data/mods/public/simulation/ai/common-api/gamestate.js

    m.GameState.prototype.init = function(Sh  
    1919    this.entities = SharedScript.entities;
    2020    this.player = player;
    2121    this.playerData = SharedScript.playersData[this.player];
    2222    this.barterPrices = SharedScript.barterPrices;
    2323    this.gameType = SharedScript.gameType;
     24    this.alliedVictory = SharedScript.alliedVictory;
     25    this.ceasefireActive = SharedScript.ceasefireActive;
    2426
    2527    // get the list of possible phases for this civ:
    2628    // we assume all of them are researchable from the civil centre
    2729    this.phases = [ { name: "phase_village" }, { name: "phase_town" }, { name: "phase_city" } ];
    2830    let cctemplate = this.getTemplate(this.applyCiv("structures/{civ}_civil_centre"));
    m.GameState.prototype.init = function(Sh  
    5355m.GameState.prototype.update = function(SharedScript)
    5456{
    5557    this.timeElapsed = SharedScript.timeElapsed;
    5658    this.playerData = SharedScript.playersData[this.player];
    5759    this.barterPrices = SharedScript.barterPrices;
     60    this.ceasefireActive = SharedScript.ceasefireActive;
    5861};
    5962
    6063m.GameState.prototype.updatingCollection = function(id, filter, collection)
    6164{
    6265    let gid = this.player + "-" + id;   // automatically add the player ID
    m.GameState.prototype.getBarterPrices =  
    115118m.GameState.prototype.getGameType = function()
    116119{
    117120    return this.gameType;
    118121};
    119122
     123m.GameState.prototype.getAlliedVictory = function()
     124{
     125    return this.alliedVictory;
     126};
     127
     128m.GameState.prototype.isCeasefireActive = function()
     129{
     130    return this.ceasefireActive;
     131};
     132
    120133m.GameState.prototype.getTemplate = function(type)
    121134{
    122135    if (this.techTemplates[type] !== undefined)
    123136        return new m.Technology(this.techTemplates, type);
    124137
    m.GameState.prototype.getPlayerID = func  
    289302};
    290303
    291304m.GameState.prototype.hasAllies = function()
    292305{
    293306    for (let i in this.playerData.isAlly)
    294         if (this.playerData.isAlly[i] && +i !== this.player)
     307        if (this.playerData.isAlly[i] && +i !== this.player &&
     308            this.sharedScript.playersData[i].state !== "defeated")
    295309            return true;
    296310    return false;
    297311};
    298312
     313m.GameState.prototype.hasEnemies = function()
     314{
     315    for (let i in this.playerData.isEnemy)
     316        if (this.playerData.isEnemy[i] && +i !== 0 &&
     317            this.sharedScript.playersData[i].state !== "defeated")
     318            return true;
     319    return false;
     320};
     321
     322m.GameState.prototype.hasNeutrals = function()
     323{
     324    for (let i in this.playerData.isNeutral)
     325        if (this.playerData.isNeutral[i] &&
     326            this.sharedScript.playersData[i].state !== "defeated")
     327            return true;
     328    return false;
     329};
     330
     331m.GameState.prototype.isPlayerNeutral = function(id)
     332{
     333    return this.playerData.isNeutral[id];
     334};
     335
    299336m.GameState.prototype.isPlayerAlly = function(id)
    300337{
    301338    return this.playerData.isAlly[id];
    302339};
    303340
    m.GameState.prototype.getEntityById = fu  
    381418        return this.entities._entities.get(+id);
    382419
    383420    return undefined;
    384421};
    385422
    386 m.GameState.prototype.getEntities = function()
     423m.GameState.prototype.getEntities = function(id)
    387424{
    388     return this.entities;
     425    if (id === undefined)
     426        return this.entities;
     427
     428    return this.updatingGlobalCollection("" + id + "-entities", m.Filters.byOwner(id));
    389429};
    390430
    391431m.GameState.prototype.getStructures = function()
    392432{
    393433    return this.updatingGlobalCollection("structures", m.Filters.byClass("Structure"), this.entities);
  • binaries/data/mods/public/simulation/ai/common-api/shared.js

    m.SharedScript.prototype.init = function  
    140140    this.timeElapsed = state.timeElapsed;
    141141    this.circularMap = state.circularMap;
    142142    this.mapSize = state.mapSize;
    143143    this.gameType = state.gameType;
    144144    this.barterPrices = state.barterPrices;
     145    this.alliedVictory = state.alliedVictory;
     146    this.ceasefireActive = state.ceasefireActive;
    145147
    146148    this.passabilityMap = state.passabilityMap;
    147149    if (this.mapSize % this.passabilityMap.width !== 0)
    148150         error("AI shared component inconsistent sizes: map=" + this.mapSize + " while passability=" + this.passabilityMap.width);
    149151    this.passabilityMap.cellSize = this.mapSize / this.passabilityMap.width;
    m.SharedScript.prototype.onUpdate = func  
    239241    this.events = state.events;
    240242    this.passabilityClasses = state.passabilityClasses;
    241243    this.playersData = state.players;
    242244    this.timeElapsed = state.timeElapsed;
    243245    this.barterPrices = state.barterPrices;
     246    this.ceasefireActive = state.ceasefireActive;
    244247
    245248    this.passabilityMap = state.passabilityMap;
    246249    this.passabilityMap.cellSize = this.mapSize / this.passabilityMap.width;
    247250    this.territoryMap = state.territoryMap;
    248251    this.territoryMap.cellSize = this.mapSize / this.territoryMap.width;
  • binaries/data/mods/public/simulation/ai/petra/chatHelper.js

    m.chatNewPhase = function(gameState, pha  
    128128        "translateParameters": ["phase"],
    129129        "parameters": { "phase": phase }
    130130    });
    131131};
    132132
     133m.chatNewDiplomacy = function(gameState, player, enemy)
     134{
     135    let message;
     136    if (enemy)
     137        message = markForTranslation("%(_player_)s and I are now enemies.");
     138    else
     139        message = markForTranslation("%(_player_)s and I are now allies.");
     140
     141    Engine.PostCommand(PlayerID, {
     142        "type": "aichat",
     143        "message": message,
     144        "translateMessage": true,
     145        "translateParameters": ["_player_"],
     146        "parameters": {"_player_": player}
     147    });
     148};
     149
    133150return m;
    134151}(PETRA);
  • binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js

    m.DiplomacyManager = function(Config)  
    1111{
    1212    this.Config = Config;
    1313    this.nextTributeUpdate = -1;
    1414    this.nextTributeRequest = new Map();
    1515    this.nextTributeRequest.set("all", 240);
     16    this.betrayLapseTime = -1;
     17    this.waitingToBetray = false;
    1618};
    1719
    1820/**
    1921 * Check if any allied needs help (tribute) and sent it if we have enough resource
    2022 * or ask for a tribute if we are in need and one ally can help
    m.DiplomacyManager.prototype.checkEvents  
    106108        let attacker = gameState.getEntityById(evt.attacker);
    107109        if (!attacker || attacker.owner() === PlayerID || !gameState.isPlayerAlly(attacker.owner()))
    108110            continue;
    109111        this.Config.personality.cooperative = Math.min(1, this.Config.personality.cooperative + 0.003);
    110112    }
     113
     114    if (events.DiplomacyChanged.length || events.PlayerDefeated.length || events.CeasefireEnded.length)
     115        this.lastManStandingCheck(gameState);
     116};
     117
     118/**
     119 * Check the diplomacy at the start of the game
     120 */
     121m.DiplomacyManager.prototype.diplomacyCheck = function(gameState)
     122{
     123    if (!gameState.getAlliedVictory() && !gameState.isCeasefireActive())
     124        this.lastManStandingCheck(gameState);
    111125};
    112126
     127/**
     128 * If the "Last Man Standing" option is enabled, check if the only remaining players are allies or neutral.
     129 * If so, turn against the strongest first, but be more likely to first turn against neutral players, if there are any.
     130 */
     131m.DiplomacyManager.prototype.lastManStandingCheck = function(gameState)
     132{
     133    if (gameState.getAlliedVictory() || gameState.isCeasefireActive())
     134        return;
     135
     136    if (gameState.hasEnemies())
     137    {
     138        this.waitingToBetray = false;
     139        return;
     140    }
     141
     142    if (!gameState.hasAllies() && !gameState.hasNeutrals())
     143        return;
     144
     145    // wait a bit before turning
     146    if (!this.waitingToBetray)
     147    {
     148        this.betrayLapseTime = gameState.ai.elapsedTime + Math.random() * 100 + 10;
     149        this.waitingToBetray = true;
     150        return;
     151    }
     152
     153    // do not turn against a player yet if we are not strong enough
     154    if (gameState.getOwnUnits().length < 50)
     155    {
     156        this.betrayLapseTime += 60;
     157        return;
     158    }
     159
     160    let playerToTurnAgainst;
     161    let turnFactor = 0;
     162    let max = 0;
     163
     164    // count the amount of entities remaining players have
     165    for (let i = 1; i < gameState.sharedScript.playersData.length; ++i)
     166    {
     167        if (i === PlayerID || gameState.ai.HQ.attackManager.defeated[i])
     168            continue;
     169
     170        turnFactor = gameState.getEntities(i).length;
     171
     172        if (gameState.isPlayerNeutral(i)) // be more inclined to turn against neutral players
     173            turnFactor += 150;
     174
     175        if (turnFactor < max)
     176            continue;
     177
     178        max = turnFactor;
     179        playerToTurnAgainst = i;
     180    }
     181
     182    if (playerToTurnAgainst)
     183    {
     184        Engine.PostCommand(PlayerID, { "type": "diplomacy", "player": playerToTurnAgainst, "to": "enemy" });
     185        if (this.Config.debug > 1)
     186            API3.warn("player " + playerToTurnAgainst + " is now an enemy");
     187        if (this.Config.chat)
     188            m.chatNewDiplomacy(gameState, playerToTurnAgainst, true);
     189    }
     190    this.betrayLapseTime = -1;
     191    this.waitingToBetray = false;
     192};
    113193
    114194m.DiplomacyManager.prototype.update = function(gameState, events)
    115195{
    116196    this.checkEvents(gameState, events);
    117197
    118198    if (!gameState.ai.HQ.saveResources && gameState.ai.elapsedTime > this.nextTributeUpdate)
    119199        this.tributes(gameState);
     200
     201    if (this.waitingToBetray && gameState.ai.elapsedTime > this.betrayLapseTime)
     202        this.lastManStandingCheck(gameState);
    120203};
    121204
    122205m.DiplomacyManager.prototype.Serialize = function()
    123206{
    124     return { "nextTributeUpdate": this.nextTributeUpdate, "nextTributeRequest": this.nextTributeRequest };
     207    return {
     208        "nextTributeUpdate": this.nextTributeUpdate,
     209        "nextTributeRequest": this.nextTributeRequest,
     210        "betrayLapseTime": this.betrayLapseTime,
     211        "waitingToBetray": this.waitingToBetray
     212    };
    125213};
    126214
    127215m.DiplomacyManager.prototype.Deserialize = function(data)
    128216{
    129     this.nextTributeUpdate = data.nextTributeUpdate;
    130     this.nextTributeRequest = data.nextTributeRequest;
     217    for (let key in data)
     218        this[key] = data[key];
    131219};
    132220
    133221return m;
    134222}(PETRA);
  • binaries/data/mods/public/simulation/ai/petra/startingStrategy.js

    m.HQ.prototype.gameAnalysis = function(g  
    5252    }
    5353
    5454    // configure our first base strategy
    5555    if (this.baseManagers.length > 1)
    5656        this.configFirstBase(gameState);
     57    this.diplomacyManager.diplomacyCheck(gameState);
    5758};
    5859
    5960/**
    6061 * Assign the starting entities to the different bases
    6162 */
  • binaries/data/mods/public/simulation/components/AIInterface.js

    AIInterface.prototype.EventNames = [  
    1818    "Garrison",
    1919    "UnGarrison",
    2020    "TerritoriesChanged",
    2121    "TerritoryDecayChanged",
    2222    "TributeExchanged",
    23     "AttackRequest"
     23    "AttackRequest",
     24    "CeasefireEnded"
    2425];
    2526
    2627AIInterface.prototype.Init = function()
    2728{
    2829    this.events = {};
    AIInterface.prototype.OnGlobalTributeExc  
    195196AIInterface.prototype.OnTerritoriesChanged = function(msg)
    196197{
    197198    this.events.TerritoriesChanged.push(msg);
    198199};
    199200
     201AIInterface.prototype.OnCeasefireEnded = function(msg)
     202{
     203    this.events.CeasefireEnded.push(msg);
     204};
     205
    200206/**
    201207 * When a new technology is researched, check which templates it affects,
    202208 * and send the updated values to the AI.
    203209 * this relies on the fact that any "value" in a technology can only ever change
    204210 * one template value, and that the naming is the same (with / in place of .)
  • binaries/data/mods/public/simulation/components/EndGameManager.js

    EndGameManager.prototype.MarkPlayerAsWon  
    7474EndGameManager.prototype.SetAlliedVictory = function(flag)
    7575{
    7676    this.alliedVictory = flag;
    7777};
    7878
     79EndGameManager.prototype.GetAlliedVictory = function()
     80{
     81    return this.alliedVictory;
     82};
     83
    7984EndGameManager.prototype.AlliedVictoryCheck = function()
    8085{
    8186    if (this.skipAlliedVictoryCheck)
    8287        return;
    8388
  • binaries/data/mods/public/simulation/components/GuiInterface.js

    GuiInterface.prototype.GetSimulationStat  
    142142    {
    143143        ret.ceasefireActive = cmpCeasefireManager.IsCeasefireActive();
    144144        ret.ceasefireTimeRemaining = ret.ceasefireActive ? cmpCeasefireManager.GetCeasefireStartedTime() + cmpCeasefireManager.GetCeasefireTime() - ret.timeElapsed : 0;
    145145    }
    146146
    147     // Add the game type
     147    // Add the game type and allied victory
    148148    let cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
    149149    ret.gameType = cmpEndGameManager.GetGameType();
     150    ret.alliedVictory = cmpEndGameManager.GetAlliedVictory();
    150151
    151152    // Add bartering prices
    152153    let cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter);
    153154    ret.barterPrices = cmpBarter.GetPrices();
    154155
  • binaries/data/mods/public/simulation/components/tests/test_EndGameManager.js

    AddMock(playerEnt1, IID_Player, {  
    2020    "GetState": () => "active",
    2121});
    2222
    2323TS_ASSERT_EQUALS(cmpEndGameManager.skipAlliedVictoryCheck, true);
    2424cmpEndGameManager.SetAlliedVictory(true);
    25 TS_ASSERT_EQUALS(cmpEndGameManager.alliedVictory, true);
     25TS_ASSERT_EQUALS(cmpEndGameManager.GetAlliedVictory(), true);
    2626cmpEndGameManager.SetGameType("wonder", { "wonderDuration": wonderDuration });
    2727TS_ASSERT_EQUALS(cmpEndGameManager.CheckGameType("regicide"), false);
    2828TS_ASSERT_EQUALS(cmpEndGameManager.skipAlliedVictoryCheck, false);
    2929TS_ASSERT(cmpEndGameManager.GetGameType() == "wonder");
    3030TS_ASSERT_EQUALS(cmpEndGameManager.GetGameTypeSettings().wonderDuration, wonderDuration);
  • binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js

    AddMock(SYSTEM_ENTITY, IID_Barter, {  
    4545        };
    4646    }
    4747});
    4848
    4949AddMock(SYSTEM_ENTITY, IID_EndGameManager, {
    50     GetGameType: function() { return "conquest"; }
     50    GetGameType: function() { return "conquest"; },
     51    GetAlliedVictory: function() { return false; }
    5152});
    5253
    5354AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
    5455    GetNumPlayers: function() { return 2; },
    5556    GetPlayerByID: function(id) { TS_ASSERT(id === 0 || id === 1); return 100+id; },
    TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulatio  
    329330        }
    330331    ],
    331332    circularMap: false,
    332333    timeElapsed: 0,
    333334    gameType: "conquest",
     335    alliedVictory: false,
    334336    barterPrices: {buy: {food: 150}, sell: {food: 25}}
    335337});
    336338
    337339TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
    338340    players: [
    TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedS  
    448450        }
    449451    ],
    450452    circularMap: false,
    451453    timeElapsed: 0,
    452454    gameType: "conquest",
     455    alliedVictory: false,
    453456    barterPrices: {buy: {food: 150}, sell: {food: 25}}
    454457});
    455458
    456459
    457460AddMock(10, IID_Builder, {