Ticket #4431: petra_ally_requests_v0.3.patch

File petra_ally_requests_v0.3.patch, 8.9 KB (added by Sandarac, 7 years ago)

Update, and only consider ally requests from neutrals for now.

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

     
    185185        g_IsObserver,
    186186
    187187    "/msg": (senderID, addresseeGUID) =>
    188         addresseeGUID == Engine.GetPlayerGUID()
     188        addresseeGUID == (Engine.GetPlayerGUID() || "local")
    189189};
    190190
    191191/**
  • binaries/data/mods/public/simulation/ai/petra/chatHelper.js

     
    1313    ]
    1414};
    1515
     16m.chatAnswerAllyRequestMessages = {
     17    "decline": [
     18        markForTranslation("I cannot accept your offer to be allies %(_player_)s.")
     19    ],
     20    "declineSuggestNeutral": [
     21        markForTranslation("I will not ally with you %(_player_)s, but I will consider a neutrality pact.")
     22    ],
     23    "declineRepeatedOffer": [
     24        markForTranslation("%(_player_)s, our previous alliance did not work out, so I must decline your offer.")
     25    ],
     26    "accept": [
     27        markForTranslation("I will accept your offer to become allies %(_player_)s. We will both benefit from this alliance.")
     28    ],
     29    "acceptWithTribute": [
     30        markForTranslation("I will ally with you %(_player_)s, but only if you send me a tribute of %(_amount_)s %(_resource_)s."),
     31        markForTranslation("%(_player_)s, you must send me a tribute of %(_amount_)s %(_resource_)s for me to accept an alliance.")
     32    ],
     33    "waitingForTribute": [
     34        markForTranslation("%(_player_)s, my offer still stands. I will ally with you if you send me a tribute of %(_amount_)s %(_resource_)s.")
     35    ]
     36};
     37
    1638m.chatLaunchAttack = function(gameState, player, type)
    1739{
    1840    let message;
     
    151173    });
    152174};
    153175
     176m.chatAnswerRequestAlly = function(gameState, player, response, requiredTribute)
     177{
     178    Engine.PostCommand(PlayerID, {
     179        "type": "aichat",
     180        "message": "/msg " + gameState.sharedScript.playersData[player].name + " " +
     181            API3.PickRandom(this.chatAnswerAllyRequestMessages[response]),
     182        "translateMessage": true,
     183        "translateParameters": requiredTribute ? ["_amount_", "_resource_", "_player_"] : ["_player_"],
     184        "parameters": requiredTribute ?
     185            { "_amount_": requiredTribute.wanted, "_resource_": requiredTribute.type, "_player_": player } :
     186            { "_player_": player }
     187    });
     188};
     189
    154190return m;
    155191}(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
     12/**
     13 * If a player sends us an ally request, an Object in this.allyRequests will be created
     14 * that includes the request status, and the amount and type of the resource tribute (if any)
     15 * that they must send in order for us to accept their request.
     16 * In addition, a message will be sent if the player has not sent us a tribute within a minute.
     17 * If two minutes pass without a tribute, we will decline their request.
     18 */
    1019m.DiplomacyManager = function(Config)
    1120{
    1221    this.Config = Config;
     
    1524    this.nextTributeRequest.set("all", 240);
    1625    this.betrayLapseTime = -1;
    1726    this.waitingToBetray = false;
     27    this.allyRequests = new Map();
    1828};
    1929
    2030/**
     
    8696    // or if our allies attack enemies inside our territory
    8797    for (let evt of events.TributeExchanged)
    8898    {
     99        if (evt.to === PlayerID && !gameState.isPlayerAlly(evt.from) && this.allyRequests.has(evt.from))
     100        {
     101            let request = this.allyRequests.get(evt.from);
     102            if (request.status !== "waitingForTribute")
     103                continue;
     104
     105            request.wanted -= evt.amounts[request.type];
     106
     107            if (request.wanted <= 0)
     108            {
     109                if (this.Config.debug > 1)
     110                    API3.warn("Player " + uneval(evt.from) + " has sent the required tribute amount");
     111
     112                this.changePlayerDiplomacy(gameState, evt.from, "ally");
     113                request.status = "accepted";
     114            }
     115            else
     116            {
     117                // Reset the warning sent to the player that reminds them to speed up the tributes
     118                request.warnTime = gameState.ai.elapsedTime + 60;
     119                request.sentWarning = false;
     120            }
     121        }
     122
    89123        if (evt.to !== PlayerID || !gameState.isPlayerAlly(evt.from))
    90124            continue;
    91125        let tributes = 0;
     
    114148
    115149    if (events.DiplomacyChanged.length || events.PlayerDefeated.length || events.CeasefireEnded.length)
    116150        this.lastManStandingCheck(gameState);
     151
     152    for (let evt of events.DiplomacyChanged)
     153    {
     154        if (evt.otherPlayer !== PlayerID)
     155            continue;
     156
     157        if (this.allyRequests.has(evt.player) && !gameState.sharedScript.playersData[evt.player].isAlly[PlayerID])
     158        {
     159            // a player that had requested to be allies changed their stance with us
     160            let request = this.allyRequests.get(evt.player);
     161            if (request.status === "accepted")
     162                request.status = "allianceBroken";
     163            else if (request.status !== "allianceBroken")
     164                request.status = "declinedRequest";
     165        }
     166        else if (gameState.sharedScript.playersData[evt.player].isAlly[PlayerID] && gameState.isPlayerEnemy(evt.player))
     167            m.chatAnswerRequestAlly(gameState, evt.player, "declineSuggestNeutral");
     168        else if (gameState.sharedScript.playersData[evt.player].isAlly[PlayerID] && gameState.isPlayerNeutral(evt.player))
     169            this.handleAllyRequest(gameState, evt.player);
     170    }
    117171};
    118172
    119173/**
     
    186240    this.waitingToBetray = false;
    187241};
    188242
     243/**
     244 * Do not become allies with a player if the game would be over.
     245 * Overall, be reluctant to become allies with any one player.
     246 */
     247m.DiplomacyManager.prototype.handleAllyRequest = function(gameState, player)
     248{
     249    let response;
     250    let requiredTribute;
     251    let request = this.allyRequests.get(player);
     252
     253    // For any given ally request be likely to permanently decline
     254    if (!request && gameState.getPlayerCiv() !== gameState.getPlayerCiv(player) && Math.random() > 0.4)
     255    {
     256        this.allyRequests.set(player, { "status": "declinedRequest" });
     257        response = "decline";
     258    }
     259    else if (request)
     260    {
     261        if (request.status === "declinedRequest")
     262            response = "decline";
     263        else if (request.status === "allianceBroken") // Previous alliance was broken, so decline
     264            response = "declineRepeatedOffer";
     265        else if (request.status === "waitingForTribute")
     266        {
     267            response = "waitingForTribute";
     268            requiredTribute = request;
     269        }
     270    }
     271    else if (gameState.getEnemies().length < 2 + gameState.getExclusiveMutualAllies().length ||
     272        gameState.ai.HQ.attackManager.currentEnemyPlayer === player)
     273    {
     274        response = "decline";
     275        this.allyRequests.set(player, { "status": "declinedRequest" });
     276    }
     277    else if (gameState.getEntities(player).length < gameState.getOwnEntities().length && Math.random() > 0.6)
     278    {
     279        response = "accept";
     280        this.changePlayerDiplomacy(gameState, player, "ally");
     281        this.allyRequests.set(player, { "status": "accepted" });
     282    }
     283    else
     284    {
     285        response = "acceptWithTribute";
     286        requiredTribute = gameState.ai.HQ.pickMostNeededResources(gameState)[0];
     287        requiredTribute.wanted = Math.max(1000, gameState.getOwnUnits().length * 10);
     288        this.allyRequests.set(player, {
     289            "status": "waitingForTribute",
     290            "wanted": requiredTribute.wanted,
     291            "type": requiredTribute.type,
     292            "warnTime": gameState.ai.elapsedTime + 60,
     293            "sentWarning": false
     294        });
     295    }
     296    m.chatAnswerRequestAlly(gameState, player, response, requiredTribute);
     297};
     298
    189299m.DiplomacyManager.prototype.changePlayerDiplomacy = function(gameState, player, newDiplomaticStance)
    190300{
    191301    Engine.PostCommand(PlayerID, { "type": "diplomacy", "player": player, "to": newDiplomaticStance });
     
    204314
    205315    if (this.waitingToBetray && gameState.ai.elapsedTime > this.betrayLapseTime)
    206316        this.lastManStandingCheck(gameState);
     317
     318    for (let [player, data] of this.allyRequests.entries())
     319    {
     320        if (data.status !== "declinedRequest" && data.status !== "allianceBroken" &&
     321            data.warnTime && gameState.ai.elapsedTime > data.warnTime)
     322        {
     323            if (data.sentWarning)
     324            {
     325                data.status = "declinedRequest";
     326                m.chatAnswerRequestAlly(gameState, player, "decline");
     327            }
     328            else
     329            {
     330                data.sentWarning = true;
     331                data.warnTime = gameState.ai.elapsedTime + 60;
     332                m.chatAnswerRequestAlly(gameState, player, "waitingForTribute", {
     333                    "wanted": data.wanted,
     334                    "type": data.type
     335                });
     336            }
     337        }
     338    }
    207339};
    208340
    209341m.DiplomacyManager.prototype.Serialize = function()
     
    212344        "nextTributeUpdate": this.nextTributeUpdate,
    213345        "nextTributeRequest": this.nextTributeRequest,
    214346        "betrayLapseTime": this.betrayLapseTime,
    215         "waitingToBetray": this.waitingToBetray
     347        "waitingToBetray": this.waitingToBetray,
     348        "allyRequests": this.allyRequests
    216349    };
    217350};
    218351