Ticket #4431: petra_ally_requests_v0.1.patch

File petra_ally_requests_v0.1.patch, 9.3 KB (added by Sandarac, 7 years ago)

Petra will respond to ally requests.

  • binaries/data/mods/public/gui/session/messages.js

     
    175175        g_IsObserver,
    176176
    177177    "/msg": (senderID, addresseeGUID) =>
    178         addresseeGUID == Engine.GetPlayerGUID()
     178        addresseeGUID == (Engine.GetPlayerGUID() || "local")
    179179};
    180180
    181181/**
  • binaries/data/mods/public/simulation/ai/common-api/gamestate.js

     
    146146    return str.replace(/\{civ\}/g, this.playerData.civ);
    147147};
    148148
    149 m.GameState.prototype.civ = function()
     149m.GameState.prototype.civ = function(player)
    150150{
    151     return this.playerData.civ;
     151    if (player === undefined)
     152        return this.playerData.civ;
     153
     154    return this.sharedScript.playersData[player].civ;
    152155};
    153156
    154157m.GameState.prototype.currentPhase = function()
  • binaries/data/mods/public/simulation/ai/petra/chatHelper.js

     
    128128    });
    129129};
    130130
    131 m.chatNewDiplomacy = function(gameState, player, enemy)
     131m.chatNewDiplomacy = function(gameState, player, newStance)
    132132{
    133     let message = enemy ?
    134         markForTranslation("%(_player_)s and I are now enemies.") :
    135         markForTranslation("%(_player_)s and I are now allies.");
     133    let message;
     134    if (newStance === "enemy")
     135        message = markForTranslation("%(_player_)s and I are now enemies.");
     136    else if (newStance === "ally")
     137        message = markForTranslation("%(_player_)s and I are now allies.");
     138    else if (newStance === "neutral")
     139        message = markForTranslation("%(_player_)s and I are now neutral.");
    136140
    137141    Engine.PostCommand(PlayerID, {
    138142        "type": "aichat",
     
    143147    });
    144148};
    145149
     150m.chatAnswerRequestAlly = function(gameState, player, response, requiredTribute)
     151{
     152    let message;
     153    if (response === 0)
     154        message = markForTranslation("I cannot accept your offer to be allies %(_player_)s.");
     155    else if (response === 1)
     156        message = markForTranslation("%(_player_)s, our previous alliance did not work out, so I must decline your offer.");
     157    else if (response === 2)
     158        message = markForTranslation("I will accept your offer to become allies %(_player_)s. We will both benefit from this alliance");
     159    else if (response === 3)
     160    {
     161        let proba = Math.random();
     162        if (proba < 0.5)
     163            message = markForTranslation("I will ally with you %(_player_)s, but only if you send me a tribute of %(_amount_)s %(_resource_)s.");
     164        else
     165            message = markForTranslation("%(_player_)s, you must send me a tribute of %(_amount_)s %(_resource_)s for me to consider an alliance");
     166    }
     167    else if (response === 4)
     168        message = markForTranslation("%(_player_)s, my offer still stands. I will ally with you if you send me a tribute of %(_amount_)s %(_resource_)s.");
     169
     170    let chat = {
     171        "type": "aichat",
     172        "message": "/msg " + gameState.sharedScript.playersData[player].name + " " + message,
     173        "translateMessage": true,
     174        "translateParameters": ["_player_"],
     175        "parameters": {"_player_": player}
     176    };
     177    if (response >= 3)
     178    {
     179        chat.translateParameters.push("_amount_");
     180        chat.translateParameters.push("_resource_");
     181        chat.parameters._amount_ = requiredTribute.wanted;
     182        chat.parameters._resource_ = requiredTribute.type;
     183    }
     184    Engine.PostCommand(PlayerID, chat);
     185};
     186
    146187return m;
    147188}(PETRA);
  • binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js

     
    55 * Manage the diplomacy:
    66 *     update our cooperative trait
    77 *     sent tribute to allies
     8 *     decide which player to turn against in "Last Man Standing" mode
     9 *     respond to diplomacy requests
    810 */
    911
    1012m.DiplomacyManager = function(Config)
     
    1517    this.nextTributeRequest.set("all", 240);
    1618    this.betrayLapseTime = -1;
    1719    this.waitingToBetray = false;
     20    this.allyRequests = new Map();
     21    this.allyLapseTime = -1;
    1822};
    1923
    2024/**
     
    8690    // or if our allies attack enemies inside our territory
    8791    for (let evt of events.TributeExchanged)
    8892    {
     93        if (evt.to === PlayerID && !gameState.isPlayerAlly(evt.from) && this.allyRequests.has(evt.from))
     94        {
     95            let newAllyData = this.allyRequests.get(evt.from);
     96            if (newAllyData === -1 || newAllyData === -2)
     97                continue;
     98
     99            newAllyData.wanted -= evt.amounts[newAllyData.type];
     100
     101            if (newAllyData.wanted <= 0)
     102            {
     103                if (this.Config.debug > 1)
     104                    API3.warn("Player " + uneval(evt.from) + " has sent all requested tributes");
     105                if (gameState.sharedScript.playersData[evt.from].isAlly[PlayerID])
     106                {
     107                    this.changePlayerDiplomacy(gameState, evt.from, "ally");
     108                    // if this new ally turns on us later and requests to ally again, we will decline
     109                    this.allyRequests.set(evt.from, -2);
     110                }
     111                else
     112                    this.allyRequests.set(evt.from, -1);
     113                this.allyLapseTime = gameState.ai.elapsedTime + 120;
     114            }
     115        }
     116
    89117        if (evt.to !== PlayerID || !gameState.isPlayerAlly(evt.from))
    90118            continue;
    91119        let tributes = 0;
     
    114142
    115143    if (events.DiplomacyChanged.length || events.PlayerDefeated.length || events.CeasefireEnded.length)
    116144        this.lastManStandingCheck(gameState);
     145
     146    for (let evt of events.DiplomacyChanged)
     147        if (evt.otherPlayer === PlayerID && !gameState.isPlayerAlly(evt.player) &&
     148            gameState.sharedScript.playersData[evt.player].isAlly[PlayerID])
     149            this.handleAllyRequest(gameState, evt.player);
    117150};
    118151
    119152/**
     
    181214    }
    182215
    183216    if (playerToTurnAgainst)
    184     {
    185         Engine.PostCommand(PlayerID, { "type": "diplomacy", "player": playerToTurnAgainst, "to": "enemy" });
    186         if (this.Config.debug > 1)
    187             API3.warn("player " + playerToTurnAgainst + " is now an enemy");
    188         if (this.Config.chat)
    189             m.chatNewDiplomacy(gameState, playerToTurnAgainst, true);
    190     }
     217        this.changePlayerDiplomacy(gameState, playerToTurnAgainst, "enemy");
    191218    this.betrayLapseTime = -1;
    192219    this.waitingToBetray = false;
    193220};
    194221
     222/**
     223 * Do not become allies with a player if the game would be over, or if we recently became allies with another player
     224 * Overall, be reluctant to become allies with any one player, but accept if the player has more entites than us
     225 * Demand a tribute if the requesting player is not as strong as us.
     226 */
     227m.DiplomacyManager.prototype.handleAllyRequest = function(gameState, player)
     228{
     229    // 0 for decline, 1 for decline (already tried being allies), 2 for accept, 3 for demand tribute, 4 for waiting for required tributes
     230    let response = 0;
     231    let requiredTribute;
     232    let newAllyData = this.allyRequests.get(player);
     233
     234    // for any given ally request be likely to permanently decline
     235    if (gameState.ai.elapsedTime < this.allyLapseTime || newAllyData === undefined &&
     236        gameState.civ() !== gameState.civ(player) && Math.random() > 0.4)
     237    {
     238        this.allyRequests.set(player, -1);
     239        response = 0;
     240    }
     241    else if (newAllyData !== undefined)
     242    {
     243        if (newAllyData === -1)
     244            response = 0;
     245        else if (newAllyData === -2) // we had become allies with this player and the alliance was broken, so decline
     246            response = 1;
     247        else if (newAllyData !== -1 && newAllyData !== -2 &&
     248            newAllyData.wanted >= 0) // already sent ally request, and has not yet sent the required tributes
     249        {
     250            response = 4;
     251            requiredTribute = newAllyData;
     252        }
     253    }
     254    else if (gameState.getEnemies().length < 3 || gameState.ai.HQ.attackManager.currentEnemyPlayer === player)
     255        response = 0;
     256    else if (gameState.getEntities(player).length < gameState.getOwnEntities().length)
     257    {
     258        response = 3;
     259        requiredTribute = gameState.ai.HQ.pickMostNeededResources(gameState)[0];
     260        requiredTribute.wanted = Math.max(1000, gameState.getOwnUnits().length * 10);
     261        this.allyRequests.set(player, requiredTribute);
     262    }
     263    else // a stronger player wants to ally with us
     264    {
     265        response = 2;
     266        this.changePlayerDiplomacy(gameState, player, "ally");
     267        this.allyRequests.set(player, -2);
     268        this.allyLapseTime = gameState.ai.elapsedTime + 120;
     269    }
     270    m.chatAnswerRequestAlly(gameState, player, response, requiredTribute);
     271};
     272
     273/**
     274 * Change the diplomacy stance with a player, and send a chat message
     275 */
     276m.DiplomacyManager.prototype.changePlayerDiplomacy = function(gameState, player, newStance)
     277{
     278    Engine.PostCommand(PlayerID, { "type": "diplomacy", "player": player, "to": newStance });
     279    if (this.Config.debug > 1)
     280        API3.warn("diplomacy stance with player " + player + " is now " + newStance);
     281    if (this.Config.chat)
     282        m.chatNewDiplomacy(gameState, player, newStance);
     283};
     284
    195285m.DiplomacyManager.prototype.update = function(gameState, events)
    196286{
    197287    this.checkEvents(gameState, events);
     
    209299        "nextTributeUpdate": this.nextTributeUpdate,
    210300        "nextTributeRequest": this.nextTributeRequest,
    211301        "betrayLapseTime": this.betrayLapseTime,
    212         "waitingToBetray": this.waitingToBetray
     302        "waitingToBetray": this.waitingToBetray,
     303        "allyRequests": this.allyRequests,
     304        "allyLapseTime": this.allyLapseTime
    213305    };
    214306};
    215307