Ticket #3157: attackRequest-v2.diff

File attackRequest-v2.diff, 15.1 KB (added by mimo, 9 years ago)
  • binaries/data/mods/public/gui/session/diplomacy_window.xml

     
    6565                <object name="diplomacyPlayerTributeMetal[n]" size="100%-50 0 100%-30 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
    6666                    <object name="diplomacyPlayerTributeMetalImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/resources/metal.png" ghost="true"/>
    6767                </object>
     68
     69                <object name="diplomacyAttackRequest[n]" size="100%-20 0 100% 100%" type="button" style="iconButton" tooltip_style="sessionToolTipBold" hidden="true">
     70                    <object name="diplomacyAttackRequestImage[n]" type="image" size="0 0 100% 100%" sprite="stretched:session/icons/stances/aggressive.png" ghost="true"/>
     71                </object>
    6872            </object>
    6973        </repeat>
    7074    </object>
  • binaries/data/mods/public/gui/session/menu.js

     
    301301            // Hide the unused/unselectable options
    302302            for each (let a in ["TributeFood", "TributeWood", "TributeStone", "TributeMetal", "Ally", "Neutral", "Enemy"])
    303303                Engine.GetGUIObjectByName("diplomacyPlayer"+a+"["+(i-1)+"]").hidden = true;
     304            Engine.GetGUIObjectByName("diplomacyAttackRequest["+(i-1)+"]").hidden = true;
    304305            continue;
    305306        }
    306307
     
    341342            button.tooltip = formatTributeTooltip(g_Players[i], resource, 100);
    342343        }
    343344
     345        // Attack Request
     346        let button = Engine.GetGUIObjectByName("diplomacyAttackRequest["+(i-1)+"]");
     347        button.hidden = !(g_Players[i].isEnemy[we]);
     348        button.tooltip = "request for your allies to attack this enemy";
     349        button.onpress = (function(i, we){ return function() {
     350            Engine.PostNetworkCommand({"type": "attack-request", "source": we, "target": i});
     351        } })(i, we);
     352
    344353        // Skip our own teams on teams locked
    345354        if (g_Players[we].teamsLocked && g_Players[we].team != -1 && g_Players[we].team == g_Players[i].team)
    346355            continue;
  • binaries/data/mods/public/gui/session/messages.js

     
    5757        {
    5858            message["translateParameters"] = notification["translateParameters"];
    5959            message["parameters"] = notification["parameters"];
     60            // special case for formatting of player names which are transmitted as _player_num
     61            for (let param in message["parameters"])
     62            {
     63                if (!message["parameters"][param].startsWith("_player_"))
     64                    continue;
     65                let colorName = getUsernameAndColor(+message["parameters"][param].substr(8));
     66                message["parameters"][param] = "[color=\"" + colorName[1] + "\"]" + colorName[0] + "[/color]";
     67            }
    6068        }
    6169        var guid = findGuidForPlayerID(g_PlayerAssignments, player);
    6270        if (guid == undefined)
  • binaries/data/mods/public/simulation/ai/petra/attackManager.js

     
    4646    }
    4747};
    4848
     49m.AttackManager.prototype.checkEvents = function(gameState, events)
     50{
     51    let PlayerEvents = events["AttackRequest"];
     52    let answer = false;
     53    let other = undefined;
     54    let targetPlayer = undefined;
     55    for (let evt of PlayerEvents)
     56    {
     57        if (evt.source === PlayerID || !gameState.isPlayerAlly(evt.source) || !gameState.isPlayerEnemy(evt.target))
     58            continue;
     59        targetPlayer = evt.target;
     60        let available = 0;
     61        for (let attackType in this.upcomingAttacks)
     62        {
     63            for (let attack of this.upcomingAttacks[attackType])
     64            {
     65                if (attack.state === "completing")
     66                {
     67                    if (attack.targetPlayer && attack.targetPlayer === targetPlayer)
     68                        available += attack.unitCollection.length;
     69                    else if (attack.targetPlayer && attack.targetPlayer !== targetPlayer)
     70                        other = attack.targetPlayer;
     71                    continue;
     72                }
     73                if (!attack.targetPlayer || attack.targetPlayer !== targetPlayer)
     74                {
     75                    let oldTargetPlayer = attack.targetPlayer;
     76                    let oldTarget = attack.target;
     77                    attack.targetPlayer = targetPlayer;
     78                    attack.target = attack.getNearestTarget(gameState, attack.rallyPoint);
     79                    if (!attack.target)
     80                    {
     81                        attack.targetPlayer = oldTargetPlayer;
     82                        attack.target = oldTarget;
     83                        continue;
     84                    }
     85                }
     86                if (attack.targetPlayer && attack.targetPlayer === targetPlayer)
     87                    available += attack.unitCollection.length;
     88            }
     89        }
     90
     91        if (available > 12) // launch the attack immediately
     92        {
     93            for (let attackType in this.upcomingAttacks)
     94            {
     95                for (let attack of this.upcomingAttacks[attackType])
     96                {
     97                    if (attack.state !== "completing" && attack.targetPlayer && attack.targetPlayer === targetPlayer)
     98                    {
     99                        attack.forceStart();
     100                        attack.requested = true;
     101                    }
     102                }
     103            }
     104            answer = true;
     105        }
     106        break;  // take only the first attack request into account
     107    }
     108    if (targetPlayer)
     109        m.chatAnswerRequestAttack(gameState, targetPlayer, answer, other);
     110};
     111
    49112// Some functions are run every turn
    50113// Others once in a while
    51114m.AttackManager.prototype.update = function(gameState, queues, events)
     
    64127        API3.warn(" ==================================");
    65128    }
    66129
    67     for (var attackType in this.upcomingAttacks)
     130    this.checkEvents(gameState, events);
     131
     132    let unexecutedAttacks = {"Rush": 0, "Raid": 0, "Attack": 0, "HugeAttack": 0};
     133    for (let attackType in this.upcomingAttacks)
    68134    {
    69         for (var i = 0; i < this.upcomingAttacks[attackType].length; ++i)
     135        for (let i = 0; i < this.upcomingAttacks[attackType].length; ++i)
    70136        {
    71             var attack = this.upcomingAttacks[attackType][i];
     137            let attack = this.upcomingAttacks[attackType][i];
    72138            attack.checkEvents(gameState, events);
    73139
    74140            if (attack.isStarted())
    75141                API3.warn("Petra problem in attackManager: attack in preparation has already started ???");
    76142
    77             var updateStep = attack.updatePreparation(gameState);
     143            let updateStep = attack.updatePreparation(gameState);
    78144            // now we're gonna check if the preparation time is over
    79145            if (updateStep === 1 || attack.isPaused() )
    80146            {
    81147                // just chillin'
     148                if (attack.state === "unexecuted")
     149                    ++unexecutedAttacks[attackType];
    82150            }
    83151            else if (updateStep === 0 || updateStep === 3)
    84152            {
     
    96164                    if (this.Config.chat)
    97165                        m.chatLaunchAttack(gameState, attack.targetPlayer);
    98166                    this.startedAttacks[attackType].push(attack);
    99 //                  Engine.PostCommand(PlayerID, {"type": "aievent", "from": PlayerID, "action": "attack", "target": attack.targetPlayer});
    100167                }
    101168                else
    102169                    attack.Abort(gameState);
     
    130197    var barracksNb = gameState.getOwnEntitiesByClass("Barracks", true).filter(API3.Filters.isBuilt()).length;
    131198    if (this.rushNumber < this.maxRushes && barracksNb >= 1)
    132199    {
    133         if (this.upcomingAttacks["Rush"].length === 0)
     200        if (unexecutedAttacks["Rush"] === 0)
    134201        {
    135202            // we have a barracks and we want to rush, rush.
    136203            var data = { "targetSize": this.rushSize[this.rushNumber] };
     
    146213            this.rushNumber++;
    147214        }
    148215    }
    149     else if (this.upcomingAttacks["Attack"].length === 0 && this.upcomingAttacks["HugeAttack"].length === 0
     216    else if (unexecutedAttacks["Attack"] === 0 && unexecutedAttacks["HugeAttack"] === 0
    150217        && (this.startedAttacks["Attack"].length + this.startedAttacks["HugeAttack"].length < Math.round(gameState.getPopulationMax()/100)))
    151218    {
    152219        if ((barracksNb >= 1 && (gameState.currentPhase() > 1 || gameState.isResearching(gameState.townPhase())))
     
    172239        }
    173240    }
    174241
    175     if (this.upcomingAttacks["Raid"].length === 0 && gameState.ai.HQ.defenseManager.targetList.length)
     242    if (unexecutedAttacks["Raid"] === 0 && gameState.ai.HQ.defenseManager.targetList.length)
    176243    {
    177244        var target = undefined;
    178245        for (var targetId of gameState.ai.HQ.defenseManager.targetList)
  • binaries/data/mods/public/simulation/ai/petra/attackPlan.js

     
    266266    return false;
    267267};
    268268
     269m.AttackPlan.prototype.forceStart = function()
     270{
     271    for (let unitCat in this.unitStat)
     272    {
     273        let Unit = this.unitStat[unitCat];
     274        Unit["targetSize"] = 0;
     275        Unit["minSize"] = 0;
     276    }
     277};
     278
    269279// Adds a build order. If resetQueue is true, this will reset the queue.
    270280m.AttackPlan.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue)
    271281{
     
    465475    if (this.type === "Raid")
    466476        this.maxCompletingTurn = gameState.ai.playedTurn + 20;
    467477    else
     478    {
    468479        this.maxCompletingTurn = gameState.ai.playedTurn + 60;
     480        // warn our allies so that they can help if possible
     481        if (!this.requested)
     482            Engine.PostCommand(PlayerID, {"type": "attack-request", "source": PlayerID, "target": this.targetPlayer});
     483    }
    469484
    470485    var rallyPoint = this.rallyPoint;
    471486    var rallyIndex = gameState.ai.accessibility.getAccessValue(rallyPoint);
  • binaries/data/mods/public/simulation/ai/petra/chatHelper.js

     
    33
    44m.chatLaunchAttack = function(gameState, player)
    55{
    6     var name = gameState.sharedScript.playersData[player].name;
    76    var proba = Math.random();
    87    if (proba < 0.5)
    98        var message = "/team " + markForTranslation("I am launching an attack against %(name)s.");
     
    109    else
    1110        var message = "/team " + markForTranslation("I have just sent an army against %(name)s.");
    1211
    13     var chat = { "type": "aichat", "message": message, "translateMessage": true, "translateParameters": ["name"], "parameters": { "name": name } };
     12    var chat = {
     13        "type": "aichat",
     14        "message": message,
     15        "translateMessage": true,
     16        "translateParameters": ["name"],
     17        "parameters": {"name": "_player_" + player}
     18    };
    1419    Engine.PostCommand(PlayerID, chat);
    1520};
    1621
     22m.chatAnswerRequestAttack = function(gameState, player, answer, other)
     23{
     24    if (answer)
     25    {
     26        var proba = Math.random();
     27        if (proba < 0.5)
     28            var message = "/team " + markForTranslation("Let me regroup my army and I am with you against %(name)s.");
     29        else
     30            var message = "/team " + markForTranslation("I am doing the final preparation and I will attack %(name)s.");
     31    }
     32    else
     33    {
     34        if (other !== undefined)
     35            var message = "/team " + markForTranslation("I cannot help you against %(name)s for the time being, as I have another attack foreseen against %(other)s.");
     36        else
     37            var message = "/team " + markForTranslation("Sorry, I have not enough soldiers currently, but my next attack will target %(name)s.");
     38    }
     39
     40    var chat = {
     41        "type": "aichat",
     42        "message": message,
     43        "translateMessage": true,
     44        "translateParameters": ["name"],
     45        "parameters": {"name": "_player_" + player}
     46    };
     47    if (other !== undefined)
     48    {
     49        chat.translateParameters.push("other");
     50        chat.parameters.other = "_player_" + other;
     51    }
     52    Engine.PostCommand(PlayerID, chat);
     53};
     54
    1755m.chatSentTribute = function(gameState, player)
    1856{
    19     var name = gameState.sharedScript.playersData[player].name;
    2057    var proba = Math.random();
    2158    if (proba < 0.5)
    2259        var message = "/team " + markForTranslation("Here is a gift for %(name)s, make a good use of it.");
     
    2360    else
    2461        var message = "/team " + markForTranslation("I see you are in a bad situation %(name)s, I hope this will help.");
    2562
    26     var chat = { "type": "aichat", "message": message, "translateMessage": true, "translateParameters": ["name"], "parameters": { "name": name } };
     63    var chat = {
     64        "type": "aichat",
     65        "message": message,
     66        "translateMessage": true,
     67        "translateParameters": ["name"],
     68        "parameters": {"name": "_player_" + player}
     69    };
    2770    Engine.PostCommand(PlayerID, chat);
    2871};
    2972
     
    3578    else
    3679        var message = "/team " + markForTranslation("I would participate more efficiently in our common war effort if you could provide me some %(resource)s.");
    3780
    38     var chat = { "type": "aichat", "message": message, "translateMessage": true, "translateParameters": ["resource"], "parameters": { "resource": resource } };
     81    var chat = {
     82        "type": "aichat",
     83        "message": message,
     84        "translateMessage": true,
     85        "translateParameters": ["resource"],
     86        "parameters": {"resource": resource}
     87    };
    3988    Engine.PostCommand(PlayerID, chat);
    4089};
    4190
    4291m.chatNewTradeRoute = function(gameState, player)
    4392{
    44     var name = gameState.sharedScript.playersData[player].name;
    4593    var proba = Math.random();
    4694    if (proba < 0.5)
    4795        var message = "/team " + markForTranslation("I have set up a new route with %(name)s. Trading will be profitable for all of us.");
     
    4896    else
    4997        var message = "/team " + markForTranslation("A new trade route is set up with %(name)s. Take your share of the profits");
    5098
    51     var chat = { "type": "aichat", "message": message, "translateMessage": true, "translateParameters": ["name"], "parameters": { "name": name } };
     99    var chat = {
     100        "type": "aichat",
     101        "message": message,
     102        "translateMessage": true,
     103        "translateParameters": ["name"],
     104        "parameters": {"name": "_player_" + player}
     105    };
    52106    Engine.PostCommand(PlayerID, chat);
    53107};
    54108
  • binaries/data/mods/public/simulation/components/AIInterface.js

     
    1717    "OwnershipChanged",
    1818    "Garrison",
    1919    "UnGarrison",
    20     "TributeExchanged"
     20    "TributeExchanged",
     21    "AttackRequest"
    2122];
    2223
    2324AIInterface.prototype.Init = function()
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    644644            }
    645645        }
    646646    },
     647
     648    "attack-request": function(player, cmd, data)
     649    {
     650        // Send a chat message to human players
     651        var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     652        if (cmpGuiInterface)
     653        {
     654            var notification = {
     655                "type": "aichat",
     656                "players": [player],
     657                "message": "/team " + markForTranslation("Attack against %(target)s requested."),
     658                "translateParameters": ["target"],
     659                "parameters": {"target": "_player_" + cmd.target}
     660            };
     661            cmpGuiInterface.PushNotification(notification);
     662        }
     663        // And send an attackRequest event to the AIs
     664        let cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
     665        if (cmpAIInterface)
     666            cmpAIInterface.PushEvent("AttackRequest", cmd);
     667    },
     668
    647669    "dialog-answer": function(player, cmd, data)
    648670    {
    649671        // Currently nothing. Triggers can read it anyway, and send this