Ticket #3157: attackRequest.diff

File attackRequest.diff, 11.0 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

     
    261261    Engine.PostNetworkCommand({"type": "tribute", "player": data.player, "amounts":  data.amounts});
    262262}
    263263
     264function requestAttack(data)
     265{
     266    Engine.PostNetworkCommand({"type": "aievent", "from": data.from, "action": data.action, "target":  data.target});
     267}
     268
    264269function openDiplomacy()
    265270{
    266271    if (isTradeOpen)
     
    301306            // Hide the unused/unselectable options
    302307            for each (let a in ["TributeFood", "TributeWood", "TributeStone", "TributeMetal", "Ally", "Neutral", "Enemy"])
    303308                Engine.GetGUIObjectByName("diplomacyPlayer"+a+"["+(i-1)+"]").hidden = true;
     309            Engine.GetGUIObjectByName("diplomacyAttackRequest["+(i-1)+"]").hidden = true;
    304310            continue;
    305311        }
    306312
     
    341347            button.tooltip = formatTributeTooltip(g_Players[i], resource, 100);
    342348        }
    343349
     350        if (!g_IsNetworked)  // TODO in multiplayer, should be done if some AIs
     351        {
     352            // Attack Request (used to communicate with AI)
     353            let button = Engine.GetGUIObjectByName("diplomacyAttackRequest["+(i-1)+"]");
     354            button.hidden = !(g_Players[i].isEnemy[we]);
     355            button.tooltip = "request for your AI allies to attack this enemy";
     356            button.onpress = (function(i, we){ return function() { requestAttack({"type": "aievent", "from": we, "action": "attack", "target": i}); } })(i, we);
     357        }
     358
    344359        // Skip our own teams on teams locked
    345360        if (g_Players[we].teamsLocked && g_Players[we].team != -1 && g_Players[we].team == g_Players[i].team)
    346361            continue;
  • binaries/data/mods/public/simulation/ai/petra/attackManager.js

     
    4646    }
    4747};
    4848
     49m.AttackManager.prototype.checkEvents = function(gameState, events)
     50{
     51    let PlayerEvents = events["PlayerMessage"];
     52    let answer = false;
     53    let other = false;
     54    let targetPlayer = undefined;
     55    for (let evt of PlayerEvents)
     56    {
     57        if (evt.action !== "attack")
     58            continue;
     59        if (evt.from === PlayerID || !gameState.isPlayerAlly(evt.from) || !gameState.isPlayerEnemy(evt.target))
     60            continue;
     61        targetPlayer = evt.target;
     62        let available = 0;
     63        for (let attackType in this.upcomingAttacks)
     64        {
     65            for (let attack of this.upcomingAttacks[attackType])
     66            {
     67                if (attack.state === "completing")
     68                {
     69                    if (attack.targetPlayer && attack.targetPlayer === targetPlayer)
     70                        available += attack.unitCollection.length;
     71                    else if (attack.targetPlayer && attack.targetPlayer !== targetPlayer)
     72                        other = true;
     73                    continue;
     74                }
     75                if (!attack.targetPlayer || attack.targetPlayer !== targetPlayer)
     76                {
     77                    let oldTargetPlayer = attack.targetPlayer;
     78                    let oldTarget = attack.target;
     79                    attack.targetPlayer = targetPlayer;
     80                    attack.target = attack.getNearestTarget(gameState, attack.rallyPoint);
     81                    if (!attack.target)
     82                    {
     83                        attack.targetPlayer = oldTargetPlayer;
     84                        attack.target = oldTarget;
     85                        continue;
     86                    }
     87                }
     88                if (attack.targetPlayer && attack.targetPlayer === targetPlayer)
     89                    available += attack.unitCollection.length;
     90            }
     91        }
     92
     93        if (available > 12) // launch the attack immediately
     94        {
     95            for (let attackType in this.upcomingAttacks)
     96                for (let attack of this.upcomingAttacks[attackType])
     97                    if (attack.state !== "completing" && attack.targetPlayer && attack.targetPlayer === targetPlayer)
     98                        attack.forceStart();
     99            answer = true;
     100        }
     101        break;  // take only the first attack request into account
     102    }
     103    if (targetPlayer)
     104        m.chatAnswerRequestAttack(gameState, targetPlayer, answer, other);
     105};
     106
    49107// Some functions are run every turn
    50108// Others once in a while
    51109m.AttackManager.prototype.update = function(gameState, queues, events)
     
    64122        API3.warn(" ==================================");
    65123    }
    66124
    67     for (var attackType in this.upcomingAttacks)
     125    this.checkEvents(gameState, events);
     126
     127    let unexecutedAttacks = {"Rush": 0, "Raid": 0, "Attack": 0, "HugeAttack": 0};
     128    for (let attackType in this.upcomingAttacks)
    68129    {
    69         for (var i = 0; i < this.upcomingAttacks[attackType].length; ++i)
     130        for (let i = 0; i < this.upcomingAttacks[attackType].length; ++i)
    70131        {
    71             var attack = this.upcomingAttacks[attackType][i];
     132            let attack = this.upcomingAttacks[attackType][i];
    72133            attack.checkEvents(gameState, events);
    73134
    74135            if (attack.isStarted())
    75136                API3.warn("Petra problem in attackManager: attack in preparation has already started ???");
    76137
    77             var updateStep = attack.updatePreparation(gameState);
     138            let updateStep = attack.updatePreparation(gameState);
    78139            // now we're gonna check if the preparation time is over
    79140            if (updateStep === 1 || attack.isPaused() )
    80141            {
    81142                // just chillin'
     143                if (attack.state === "unexecuted")
     144                    ++unexecutedAttacks[attackType];
    82145            }
    83146            else if (updateStep === 0 || updateStep === 3)
    84147            {
     
    96159                    if (this.Config.chat)
    97160                        m.chatLaunchAttack(gameState, attack.targetPlayer);
    98161                    this.startedAttacks[attackType].push(attack);
    99 //                  Engine.PostCommand(PlayerID, {"type": "aievent", "from": PlayerID, "action": "attack", "target": attack.targetPlayer});
     162                    Engine.PostCommand(PlayerID, {"type": "aievent", "from": PlayerID, "action": "attack", "target": attack.targetPlayer});
    100163                }
    101164                else
    102165                    attack.Abort(gameState);
     
    129192
    130193    if (this.rushNumber < this.maxRushes && gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_barracks"), true) >= 1)
    131194    {
    132         if (this.upcomingAttacks["Rush"].length === 0)
     195        if (unexecutedAttacks["Rush"] === 0)
    133196        {
    134197            // we have a barracks and we want to rush, rush.
    135198            var data = { "targetSize": this.rushSize[this.rushNumber] };
     
    145208            this.rushNumber++;
    146209        }
    147210    }
    148     else if (this.upcomingAttacks["Attack"].length === 0 && this.upcomingAttacks["HugeAttack"].length === 0
     211    else if (unexecutedAttacks["Attack"] === 0 && unexecutedAttacks["HugeAttack"] === 0
    149212        && (this.startedAttacks["Attack"].length + this.startedAttacks["HugeAttack"].length < Math.round(gameState.getPopulationMax()/100)))
    150213    {
    151214        if ((gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_barracks"), true) >= 1
     
    172235        }
    173236    }
    174237
    175     if (this.upcomingAttacks["Raid"].length === 0 && gameState.ai.HQ.defenseManager.targetList.length)
     238    if (unexecutedAttacks["Raid"] === 0 && gameState.ai.HQ.defenseManager.targetList.length)
    176239    {
    177240        var target = undefined;
    178241        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{
  • binaries/data/mods/public/simulation/ai/petra/chatHelper.js

     
    1414    Engine.PostCommand(PlayerID, chat);
    1515};
    1616
     17m.chatAnswerRequestAttack = function(gameState, player, answer, other)
     18{
     19    var name = gameState.sharedScript.playersData[player].name;
     20    if (answer)
     21    {
     22        var proba = Math.random();
     23        if (proba < 0.5)
     24            var message = "/team " + markForTranslation("Let me regroup my army and I am with you against %(name)s.");
     25        else
     26            var message = "/team " + markForTranslation("I am doing the final preparation and I will attack %(name)s.");
     27    }
     28    else
     29    {
     30        if (other)
     31            var message = "/team " + markForTranslation("I cannot help you against %(name)s for the time being, I have another attack foreseen.");
     32        else
     33            var message = "/team " + markForTranslation("Sorry, I have not enough soldiers to attack %(name)s right now, but my next attack will target him.");
     34    }
     35
     36    var chat = { "type": "aichat", "message": message, "translateMessage": true, "translateParameters": ["name"], "parameters": { "name": name } };
     37    Engine.PostCommand(PlayerID, chat);
     38};
     39
    1740m.chatSentTribute = function(gameState, player)
    1841{
    1942    var name = gameState.sharedScript.playersData[player].name;
  • binaries/data/mods/public/simulation/components/AIInterface.js

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

     
    644644            }
    645645        }
    646646    },
     647
     648    "aievent": function(player, cmd, data)
     649    {
     650        // Used to allow interaction between players and AIs: i.e. warn it of foreseen attacks
     651        let cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
     652        if (!cmpAIInterface)
     653            return;
     654        cmpAIInterface.PushEvent("PlayerMessage", cmd);
     655    },
     656
    647657    "dialog-answer": function(player, cmd, data)
    648658    {
    649659        // Currently nothing. Triggers can read it anyway, and send this