Ticket #52: Triggers.3.patch

File Triggers.3.patch, 30.5 KB (added by sanderd17, 10 years ago)
  • binaries/data/mods/public/simulation/components/BuildingAI.js

     
    146146 */
    147147BuildingAI.prototype.OnRangeUpdate = function(msg)
    148148{
    149 
    150149    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
    151150    if (!cmpAttack)
    152151        return;
  • binaries/data/mods/public/simulation/components/Foundation.js

     
    202202            // (via CCmpTemplateManager). Now we need to remove that temporary
    203203            // blocker-disabling, so that we'll perform standard unit blocking instead.
    204204            cmpObstruction.SetDisableBlockMovementPathfinding(false, false, -1);
     205           
     206            // Call the related trigger event
     207            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     208            cmpTrigger.CallEvent("OnConstructionStarted", {"foundation": this.entity, "template": this.finalTemplateName});
    205209        }
    206210
    207211        // Switch foundation to scaffold variant
  • binaries/data/mods/public/simulation/components/PlayerManager.js

     
    3131    return INVALID_ENTITY;
    3232};
    3333
     34/**
     35 * Get the number of players (including gaia)
     36 */
    3437PlayerManager.prototype.GetNumPlayers = function()
    3538{
    3639    return this.playerEntities.length;
  • binaries/data/mods/public/simulation/components/ProductionQueue.js

     
    288288                "timeTotal": time*1000,
    289289                "timeRemaining": time*1000,
    290290            });
     291           
     292            // Call the related trigger event
     293            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     294            cmpTrigger.CallEvent("OnTrainingQueued", {"playerid": cmpPlayer.GetPlayerID(), "unitTemplate": templateName, "count": count, "metadata": metadata, "trainerEntity": this.entity});
    291295        }
    292296        else if (type == "technology")
    293297        {
     
    324328                "timeTotal": time*1000,
    325329                "timeRemaining": time*1000,
    326330            });
     331           
     332            // Call the related trigger event
     333            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     334            cmpTrigger.CallEvent("OnResearchQueued", {"playerid": cmpPlayer.GetPlayerID(), "technologyTemplate": templateName, "researcherEntity": this.entity});
    327335        }
    328336        else
    329337        {
  • binaries/data/mods/public/simulation/components/ResourceTrickle.js

     
    5757    if (cmpPlayer)
    5858        for (var resource in rates)
    5959            cmpPlayer.AddResource(resource, rates[resource]);
    60    
    6160};
    6261
    6362Engine.RegisterComponentType(IID_ResourceTrickle, "ResourceTrickle", ResourceTrickle);
  • binaries/data/mods/public/simulation/components/TechnologyManager.js

     
    286286        return;
    287287    }
    288288   
     289    // Call the related trigger event
     290    var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     291    cmpTrigger.CallEvent("OnResearchFinished", {"researcher": this.entity, "tech": tech});
     292   
    289293    var modifiedComponents = {};
    290294    this.researchedTechs[tech] = template;
    291295    // store the modifications in an easy to access structure
  • binaries/data/mods/public/simulation/components/Trigger.js

     
     1function Trigger() {}
     2
     3Trigger.prototype.Schema =
     4    "<a:component type='system'/><empty/>";
     5
     6Trigger.prototype.Init = function()
     7{
     8    // Each event has its own set of actions determined by the map maker.
     9    var eventNames = [
     10        "OnEntityTookDamage",
     11        "OnEntityKilled",
     12        "OnStructureBuilt",
     13        "OnConstructionStarted",
     14        "OnTrainingFinished",
     15        "OnTrainingQueued",
     16        "OnResearchFinished",
     17        "OnResearchQueued",
     18        "OnTimer",
     19        "OnUnitIssuedOrder"];
     20    for each (var eventName in eventNames)
     21        this["event" + eventName + "Actions"] = [];
     22
     23    this.eventOnUnitRangeFromEntityData = {};
     24};
     25
     26/**
     27 * Start the update timer, will cause the "Always" events to be triggered every timer tick
     28 */
     29Trigger.prototype.StartUpdateTimer = function(delay, interval)
     30{
     31    // Stop the last timer before starting a new one
     32    if (this.timer)
     33        this.StopUpdateTimer();
     34
     35    // Start the update timer
     36    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     37    this.timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "TimerUpdate", delay, interval, null);
     38}
     39
     40/**
     41 * Stop the update timer, will cause the "Always" events to never be triggered again
     42 */
     43Trigger.prototype.StopUpdateTimer = function()
     44{
     45    // Call the update timer
     46    if (!this.timer)
     47        return;
     48    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     49    cmpTimer.CancelTimer(this.timer);
     50    this.timer = undefined;
     51}
     52
     53/**
     54 * Binds the "action" function to one of the implemented events.
     55 *
     56 * @param eventName Name of the event (see the list in init)
     57 * @param action Functionname of a function available under the g_Triggers global object
     58 */
     59Trigger.prototype.RegisterTrigger = function(eventName, action)
     60{
     61    var eventString = "event" + eventName + "Actions";
     62    if (this[eventString])
     63        this[eventString].push(action);
     64    else
     65        error("event " + eventName + " not found as an existing trigger event.");
     66};
     67
     68/*
     69 * This is an event with more than just the key argument,
     70 * so we should have a special register function for it.
     71 *
     72 * @param entity Entity id around which the range is checked
     73 * @param radius Radius of the range
     74 * @param action Functionname to execute on a range change (entities entered or left)
     75 * @param players Array of player ids (0 to 8). Or null if you want to check for all players
     76 * @param componentID Only entities with this component id will be noticed. 0 for all entities
     77 */
     78Trigger.prototype.RegisterOnUnitRangeFromEntityTrigger = function(entity, radius, action, players, componentID)
     79{
     80    // If the players parameter is not specified use all players.
     81    if (!players)
     82    {
     83        var numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers;
     84        players = [];
     85        for (var i = 0; i < numPlayers; i++)
     86            players.push(i);
     87    }
     88
     89    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     90
     91    var rangeQueryID = cmpRangeManager.CreateActiveQuery(entity, 0, radius, players, componentID || 0, cmpRangeManager.GetEntityFlagMask("normal"));
     92
     93    cmpRangeManager.EnableActiveQuery(rangeQueryID);
     94
     95    this.eventOnUnitRangeFromEntityData[action] = {
     96        "action": action,
     97        "entity": entity,
     98        "radius": radius,
     99        "currentCollection": [],
     100        "rangeQuery": rangeQueryID,
     101        "players": players};
     102}
     103
     104Trigger.prototype.DisableRangeTrigger = function(action)
     105{
     106    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     107    cmpRangeManager.DisableActiveQuery(this.eventOnUnitRangeFromEntityData[action].rangeQuery);
     108}
     109
     110Trigger.prototype.EnableRangeTrigger = function(action)
     111{
     112    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     113    cmpRangeManager.EnableActiveQuery(this.eventOnUnitRangeFromEntityData[action].rangeQuery);
     114}
     115
     116Trigger.prototype.RemoveTrigger = function(eventName, action)
     117{
     118    var eventString = "event" + eventName + "Actions";
     119    if (this[eventString])
     120    {
     121        var index = this[eventString].indexOf(action);
     122        if (index > -1)
     123            this[eventString].splice(index, 1);
     124    }
     125    else
     126        error("event " + eventName + " not found as an existing trigger event.");
     127}
     128
     129/**
     130 * This function executes the actions bound to the events
     131 * It's either called directlty from other simulation scripts,
     132 * or from message listeners in this file
     133 *
     134 * @param eventName Name of the event (see the list in init)
     135 * @param data Data object that will be passed to the actions
     136 */
     137Trigger.prototype.CallEvent = function(eventName, data)
     138{
     139    var eventString = "event" + eventName + "Actions";
     140    if (!this[eventString])
     141        error("Unknown trigger event "+eventName);
     142    else
     143        this[eventString].forEach(function(action){this.DoAction({"action": action, "data": data});}, this);
     144}
     145
     146Trigger.prototype.OnGlobalConstructionFinished = function(msg)
     147{
     148    this.CallEvent("OnStructureBuilt", {"building": msg.newentity});
     149}
     150
     151Trigger.prototype.OnGlobalTrainingFinished = function(msg)
     152{
     153    this.CallEvent("OnTrainingFinished", msg);
     154    // The data for this one is {"entities": createdEnts,
     155    //                           "owner": cmpOwnership.GetOwner(),
     156    //                           "metadata": metadata}
     157    // See function "SpawnUnits" in ProductionQueue for more details
     158}
     159
     160Trigger.prototype.TimerUpdate = function(data, lateness)
     161{
     162    this.CallEvent("OnTimer", lateness);
     163}
     164
     165Trigger.prototype.OnGlobalRangeUpdate = function(msg)
     166{
     167    // search the right query
     168    for (var action in this.eventOnUnitRangeFromEntityData)
     169    {
     170        if (msg.tag == this.eventOnUnitRangeFromEntityData[action].rangeQuery)
     171        {
     172            var updatedQuery = this.eventOnUnitRangeFromEntityData[action];
     173            break;
     174        }
     175    }
     176   
     177    if (!updatedQuery)
     178        return;
     179
     180    for each (var entity in msg.removed)
     181    {
     182        var index = updatedQuery.currentCollection.indexOf(entity);
     183        if (index > -1)
     184            updatedQuery.currentCollection.splice(index, 1);
     185    }
     186       
     187    updatedQuery.currentCollection.concat(msg.added);
     188
     189    var data = {
     190        "currentCollection": updatedQuery.currentCollection.slice(),
     191        "added": msg.added,
     192        "removed": msg.removed};
     193
     194    this.DoAction({"action": updatedQuery.action, "data": data});
     195}
     196
     197/**
     198 * Execute a function after a certain delay
     199 * @param time The delay expressed in milleseconds
     200 * @param action Name of the action function
     201 * @param data Data object that will be passed to the action function
     202 */
     203Trigger.prototype.DoAfterDelay = function(time, action, data)
     204{
     205    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     206    return cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Trigger, "DoAction", time, {"action": action, "data": data});
     207}
     208
     209/**
     210 * Called by the trigger listeners to exucute the actual action. Including sanity checks.
     211 */
     212Trigger.prototype.DoAction = function(msg)
     213{
     214    if (g_Triggers[msg.action])
     215        g_Triggers[msg.action](msg.data);
     216    else
     217        error("called a trigger action '" + msg.action + "' that wasn't added to the g_Triggers global");
     218}
     219
     220Engine.RegisterComponentType(IID_Trigger, "Trigger", Trigger);
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    199199        cmpUnitMotion.MoveToFormationOffset(msg.data.target, msg.data.x, msg.data.z);
    200200
    201201        this.SetNextStateAlwaysEntering("FORMATIONMEMBER.WALKING");
     202       
     203        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     204        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.FormationWalk", "metadata": msg});
    202205    },
    203206
    204207    // Special orders:
     
    225228            // We are already at the target, or can't move at all
    226229            this.FinishOrder();
    227230        }
     231       
     232        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     233        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.LeaveFoundation", "metadata": msg});
    228234    },
    229235
    230236    // Individual orders:
     
    247253            this.SetNextState("ANIMAL.IDLE");
    248254        else
    249255            this.SetNextState("INDIVIDUAL.IDLE");
    250 
     256       
     257        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     258        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Stop", "metadata": msg});
    251259    },
    252260
    253261    "Order.Walk": function(msg) {
     
    258266            return;
    259267        }
    260268
     269        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     270        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Walk", "metadata": msg});
     271       
    261272        // For packable units:
    262273        // 1. If packed, we can move.
    263274        // 2. If unpacked, we first need to pack, then follow case 1.
     
    284295            return;
    285296        }
    286297
     298        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     299        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.WalkAndFight", "metadata": msg});
     300       
    287301        // For packable units:
    288302        // 1. If packed, we can move.
    289303        // 2. If unpacked, we first need to pack, then follow case 1.
     
    310324            this.FinishOrder();
    311325            return;
    312326        }
    313 
     327       
     328        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     329        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.WalkToTarget", "metadata": msg, "target": this.order.data.target});
     330       
    314331        // For packable units:
    315332        // 1. If packed, we can move.
    316333        // 2. If unpacked, we first need to pack, then follow case 1.
     
    369386            this.StopMoving();
    370387            this.SetNextState("INDIVIDUAL.PICKUP.LOADING");
    371388        }
     389       
     390        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     391        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.PickupUnit", "metadata": msg, "target": this.order.data.target});
    372392    },
    373393
    374394    "Order.Guard": function(msg) {
     
    382402            this.SetNextState("INDIVIDUAL.GUARD.ESCORTING");
    383403        else
    384404            this.SetNextState("INDIVIDUAL.GUARD.GUARDING");
     405       
     406        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     407        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Guard", "metadata": msg, "target": this.order.data.target});
    385408    },
    386409
    387410    "Order.Flee": function(msg) {
     
    390413        var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
    391414        if (cmpUnitMotion.MoveToTargetRange(this.order.data.target, distance, -1))
    392415        {
     416            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     417            cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Flee", "metadata": msg, "target": this.order.data.target});
     418       
    393419            // We've started fleeing from the given target
    394420            if (this.IsAnimal())
    395421                this.SetNextState("ANIMAL.FLEEING");
     
    402428            this.StopMoving();
    403429            this.FinishOrder();
    404430        }
     431       
     432
    405433    },
    406434
    407435    "Order.Attack": function(msg) {
     
    422450        }
    423451        this.order.data.attackType = type;
    424452
     453        // Call "OnUnitIssuedOrder" event of the triggers.
     454        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     455        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Attack", "metadata": msg, "target": this.order.data.target});
     456       
    425457        // If we are already at the target, try attacking it from here
    426458        if (this.CheckTargetAttackRange(this.order.data.target, this.order.data.attackType))
    427459        {
     
    506538        // We can't reach the target, and can't move towards it,
    507539        // so abandon this attack order
    508540        this.FinishOrder();
     541       
    509542    },
    510543
    511544    "Order.Heal": function(msg) {
     
    526559        // Check if the target is in range
    527560        if (this.CheckTargetRange(this.order.data.target, IID_Heal))
    528561        {
     562            // Call "OnUnitIssuedOrder" event of the triggers.
     563            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     564            cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Heal", "metadata": msg, "target": this.order.data.target});
     565       
    529566            this.StopMoving();
    530567            this.SetNextState("INDIVIDUAL.HEAL.HEALING");
    531568            return;
     
    542579        // Try to move within heal range
    543580        if (this.MoveToTargetRange(this.order.data.target, IID_Heal))
    544581        {
     582            // Call "OnUnitIssuedOrder" event of the triggers.
     583            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     584            cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Heal", "metadata": msg, "target": this.order.data.target});
     585       
    545586            // We've started walking to the given point
    546587            this.SetNextState("INDIVIDUAL.HEAL.APPROACHING");
    547588            return;
     
    599640            this.StopMoving();
    600641            this.SetNextStateAlwaysEntering("INDIVIDUAL.GATHER.GATHERING");
    601642        }
     643       
     644        // Call "OnUnitIssuedOrder" event of the triggers.
     645        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     646        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Gather", "metadata": msg, "target": this.order.data.target});
    602647    },
    603648
    604649    "Order.GatherNearPosition": function(msg) {
     
    605650        // Move the unit to the position to gather from.
    606651        this.MoveToPoint(this.order.data.x, this.order.data.z);
    607652        this.SetNextState("INDIVIDUAL.GATHER.WALKING");
     653       
     654        // Call "OnUnitIssuedOrder" event of the triggers.
     655        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     656        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.GatherNearPosition", "metadata": msg, "target": this.order.data.target});
    608657    },
    609658
    610659    "Order.ReturnResource": function(msg) {
     
    628677        // Try to move to the dropsite
    629678        if (this.MoveToTargetRange(this.order.data.target, IID_ResourceGatherer))
    630679        {
     680            // Call "OnUnitIssuedOrder" event of the triggers.
     681            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     682            cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.ReturnResource", "metadata": msg, "target": this.order.data.target});
     683       
    631684            // We've started walking to the target
    632685            this.SetNextState("INDIVIDUAL.RETURNRESOURCE.APPROACHING");
    633686            return;
     
    660713        this.waypoints = undefined;
    661714        if (this.MoveToMarket(nextMarket))
    662715        {
     716            // Call "OnUnitIssuedOrder" event of the triggers.
     717            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     718            cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Trade", "metadata": msg, "target": this.order.data.target});
     719       
    663720            // We've started walking to the next market
    664721            this.SetNextState(state);
    665722        }
     
    682739            this.StopMoving();
    683740            this.SetNextState("INDIVIDUAL.REPAIR.REPAIRING");
    684741        }
     742       
     743        // Call "OnUnitIssuedOrder" event of the triggers.
     744        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     745        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Repair", "metadata": msg, "target": this.order.data.target});
    685746    },
    686747
    687748    "Order.Garrison": function(msg) {
     749        // Call "OnUnitIssuedOrder" event of the triggers.
     750        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     751        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Garrison", "metadata": msg, "target": this.order.data.target});
     752   
    688753        // For packable units:
    689754        // 1. If packed, we can move to the garrison target.
    690755        // 2. If unpacked, we first need to pack, then follow case 1.
     
    709774
    710775    "Order.Autogarrison": function(msg) {
    711776        this.SetNextState("INDIVIDUAL.AUTOGARRISON");
     777       
     778        // Call "OnUnitIssuedOrder" event of the triggers.
     779        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     780        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Autogarrison", "metadata": msg});
    712781    },
    713782
    714783    "Order.Alert": function(msg) {
     
    722791            this.ReplaceOrder("Garrison", {"target": this.alertGarrisoningTarget});
    723792        else
    724793            this.FinishOrder();
     794       
     795        // Call "OnUnitIssuedOrder" event of the triggers.
     796        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     797        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Alert", "metadata": msg});
    725798    }, 
    726799
    727800    "Order.Cheering": function(msg) {
    728801        this.SetNextState("INDIVIDUAL.CHEERING");
     802       
     803        // Call "OnUnitIssuedOrder" event of the triggers.
     804        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     805        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Cheering", "metadata": msg});
    729806    },
    730807
    731808    "Order.Pack": function(msg) {
     
    733810        {
    734811            this.StopMoving();
    735812            this.SetNextState("INDIVIDUAL.PACKING");
     813           
     814            // Call "OnUnitIssuedOrder" event of the triggers.
     815            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     816            cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Pack", "metadata": msg});
    736817        }
    737818    },
    738819
     
    741822        {
    742823            this.StopMoving();
    743824            this.SetNextState("INDIVIDUAL.UNPACKING");
     825           
     826            // Call "OnUnitIssuedOrder" event of the triggers.
     827            var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     828            cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Unpack", "metadata": msg});
    744829        }
    745830    },
    746831
     
    749834        if (cmpPack && cmpPack.IsPacking() && !cmpPack.IsPacked())
    750835            cmpPack.CancelPack();
    751836        this.FinishOrder();
     837       
     838        // Call "OnUnitIssuedOrder" event of the triggers.
     839        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     840        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.CancelPack", "metadata": msg});
    752841    },
    753842
    754843    "Order.CancelUnpack": function(msg) {
     
    756845        if (cmpPack && cmpPack.IsPacking() && cmpPack.IsPacked())
    757846            cmpPack.CancelPack();
    758847        this.FinishOrder();
     848       
     849        // Call "OnUnitIssuedOrder" event of the triggers.
     850        var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     851        cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.CancelUnpack", "metadata": msg});
    759852    },
    760853
    761854    // States for the special entity representing a group of units moving in formation:
     
    820913            var cmpTargetUnitAI = Engine.QueryInterface(target, IID_UnitAI);
    821914            if (cmpTargetUnitAI && cmpTargetUnitAI.IsFormationMember())
    822915                target = cmpTargetUnitAI.GetFormationController();
    823 
     916           
    824917            var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
    825918            // Check if we are already in range, otherwise walk there
    826919            if (!this.CheckTargetAttackRange(target, target))
     
    849942                this.FinishOrder();
    850943                return;
    851944            }
     945           
    852946            // Check if we are already in range, otherwise walk there
    853947            if (!this.CheckGarrisonRange(msg.data.target))
    854948            {
     
    9261020            }
    9271021
    9281022            this.CallMemberFunction("GatherNearPosition", [msg.data.x, msg.data.z, msg.data.type, msg.data.template, false]);
    929 
     1023           
    9301024            this.SetNextStateAlwaysEntering("MEMBER");
    9311025        },
    9321026
     
    9451039            }
    9461040
    9471041            this.CallMemberFunction("Heal", [msg.data.target, false]);
    948 
     1042           
    9491043            this.SetNextStateAlwaysEntering("MEMBER");
    9501044        },
    9511045
     
    11991293
    12001294            // Stop moving as soon as the formation disbands
    12011295            this.StopMoving();
    1202 
     1296           
    12031297            // If the controller handled an order but some members rejected it,
    12041298            // they will have no orders and be in the FORMATIONMEMBER.IDLE state.
    12051299            if (this.orderQueue.length)
  • binaries/data/mods/public/simulation/components/interfaces/Trigger.js

     
     1Engine.RegisterInterface("Trigger");
  • binaries/data/mods/public/simulation/helpers/Damage.js

     
    7474    // Damage the target
    7575    var targetState = cmpDamageReceiver.TakeDamage(data.strengths.hack * data.multiplier, data.strengths.pierce * data.multiplier, data.strengths.crush * data.multiplier, data.attacker);
    7676
     77    // Call the related trigger event
     78    // We have to call the event instead of listening to it by messages because the message is sent
     79    // after the target gets killed, which is not our intended case
     80    var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     81    cmpTrigger.CallEvent("OnEntityTookDamage", {"attackerEntity": data.attacker, "attackedEntity": data.target, "type":data.type, "ammount":-targetState.change});
     82   
    7783    // If the target was killed run some cleanup
    7884    if (targetState.killed)
    7985        Damage.TargetKilled(data.attacker, data.target);
     
    110116    // Call RangeManager with dummy entity and return the result.
    111117    var rangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    112118    var rangeQuery = rangeManager.ExecuteQueryAroundPos(origin, 0, radius, players, IID_DamageReceiver);
     119   
    113120    return rangeQuery;
    114121};
    115122
     
    133140    var cmpLooter = Engine.QueryInterface(killerEntity, IID_Looter);
    134141    if (cmpLooter)
    135142        cmpLooter.Collect(targetEntity);
     143       
     144    // Call the related trigger event
     145    var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     146    cmpTrigger.CallEvent("OnEntityKilled", {"killerEntity": killerEntity, "killedEntity": targetEntity});
    136147};
    137148
    138149Engine.RegisterGlobal("Damage", Damage);
  • binaries/data/mods/public/simulation/helpers/TriggerHelpers.js

     
     1// Contains standardized functions suitable for using in trigger scripts.
     2// Do not use them in any other simulation script.
     3
     4// the global triggers variable used to exchange messages with the map scripts
     5var g_Triggers = {}
     6Engine.RegisterGlobal("g_Triggers", g_Triggers);
     7
     8/**
     9 * A function to get the owner of an entity.
     10 * Returns the ID of a player. Returns 0 if the owner is Gaia.
     11 */
     12function GetEntityOwner(entity)
     13{
     14    var cmpOwnership = Engine.QueryInterface(entity, IID_Ownership)
     15    if (!cmpOwnership)
     16        return null;
     17    return cmpOwnership.GetOwner();
     18}
     19
     20/**
     21 * A function to get the generic name of an entity
     22 */
     23function GetEntityGenericName(entity)
     24{
     25    var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
     26    if (!cmpIdentity)
     27        return null;
     28    return cmpIdentity.GetGenericName();
     29}
     30
     31/**
     32 * A function to get a list of the classes of an entity
     33 */
     34function GetEntityClassesList(entity)
     35{
     36    var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
     37    if (!cmpIdentity)
     38        return null;
     39    return cmpIdentity.GetClassesList();
     40}
     41
     42/**
     43 * A function to determine if an entity has a specific class
     44 */
     45function EntityHasClass(entity, classname)
     46{
     47    var classes = GetEntityClassesList(entity);
     48    return (classes && classes.indexOf(classname) != -1);
     49}
     50
     51/**
     52 * Returns the entity id of a player based on the id of the player
     53 * Useful when one wants to change a player's properties.
     54 */
     55function GetPlayerEntityByID(id)
     56{
     57    var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     58    return cmpPlayerMan.GetPlayerByID(id);
     59}
     60
     61/**
     62 * Can be used to "force" a building to spawn a group of entities.
     63 * Only works for buildings that can already train units.
     64 */
     65function BuildingSpawnUnits(entity, template, count)
     66{
     67    var cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
     68    cmpProductionQueue.SpawnUnits(template, count, null);
     69}
     70
     71/**
     72 * Shows a message in the top center of the screen
     73 */
     74function PushNotification(players, message)
     75{
     76    var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     77    for each (var player in players)
     78        cmpGUIInterface.PushNotification({"player": player, "message": message});
     79}
     80
     81/**
     82 * Returns the resource type that can be gathered from an entity
     83 */
     84function GetEntityResourceType(entity)
     85{
     86    var cmpResourceSupply = Engine.QueryInterface(entity, IID_ResourceSupply);
     87    if (!cmpResourceSupply)
     88        return null;
     89    return cmpResourceSupply.GetType();
     90}
     91
     92/**
     93 * Returns a list of entities owned by the player
     94 */
     95function GetEntitiesByPlayer(playerID)
     96{
     97    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     98    return cmpRangeManager.GetEntitiesByPlayer(playerID);
     99}
     100
     101/**
     102 * Wins the game for a player
     103 */
     104function SetPlayerWon(playerID)
     105{
     106    var playerEnt = GetPlayerEntityByID(playerID);
     107    var cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player);
     108    cmpPlayer.SetState("won")
     109}
     110
     111/**
     112 * Defeats a player
     113 */
     114function DefeatPlayer(playerID)
     115{
     116    var playerEnt = GetPlayerEntityByID(playerID);
     117    Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": playerID } );
     118}
     119
     120Engine.RegisterGlobal("GetEntityOwner", GetEntityOwner);
     121Engine.RegisterGlobal("GetEntityGenericName", GetEntityGenericName);
     122Engine.RegisterGlobal("GetEntityClassesList", GetEntityClassesList);
     123Engine.RegisterGlobal("EntityHasClass", EntityHasClass);
     124Engine.RegisterGlobal("GetPlayerEntityByID", GetPlayerEntityByID);
     125Engine.RegisterGlobal("BuildingSpawnUnits", BuildingSpawnUnits);
     126Engine.RegisterGlobal("PushNotification", PushNotification);
     127Engine.RegisterGlobal("GetEntityResourceType", GetEntityResourceType);
     128Engine.RegisterGlobal("GetEntitiesByPlayer", GetEntitiesByPlayer);
     129Engine.RegisterGlobal("SetPlayerWon", SetPlayerWon);
     130Engine.RegisterGlobal("DefeatPlayer", DefeatPlayer);
     131
  • source/simulation2/Simulation2.cpp

     
    133133            LOAD_SCRIPTED_COMPONENT("PlayerManager");
    134134            LOAD_SCRIPTED_COMPONENT("TechnologyTemplateManager");
    135135            LOAD_SCRIPTED_COMPONENT("Timer");
     136            LOAD_SCRIPTED_COMPONENT("Trigger");
    136137            LOAD_SCRIPTED_COMPONENT("ValueModificationManager");
    137138
    138139#undef LOAD_SCRIPTED_COMPONENT
     
    748749
    749750    if (!m->m_StartupScript.empty())
    750751        GetScriptInterface().LoadScript(L"map startup script", m->m_StartupScript);
     752   
     753    // Load the trigger script after we have loaded the simulation and the map.
     754    if (GetScriptInterface().HasProperty(m->m_MapSettings.get(), "TriggerScript"))
     755    {
     756        std::string script_name;
     757        GetScriptInterface().GetProperty(m->m_MapSettings.get(), "TriggerScript", script_name);
     758
     759        script_name = "maps/scripts/" + script_name;
     760        m->m_ComponentManager.LoadScript(script_name.data());
     761    }
    751762}
    752763
    753764int CSimulation2::ProgressiveLoad()