Index: ps/trunk/binaries/data/mods/public/maps/scenarios/Triggers_demo.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/scenarios/Triggers_demo.js (revision 15425) +++ ps/trunk/binaries/data/mods/public/maps/scenarios/Triggers_demo.js (revision 15426) @@ -1,90 +1,97 @@ warn("loading the triggers file"); /////////////////////// // Trigger listeners // /////////////////////// // every function just logs when it gets fired, and shows the data Trigger.prototype.StructureBuiltAction = function(data) { warn("The OnStructureBuilt event happened with the following data:"); warn(uneval(data)); }; Trigger.prototype.ConstructionStartedAction = function(data) { warn("The OnConstructionStarted event happened with the following data:"); warn(uneval(data)); }; Trigger.prototype.TrainingFinishedAction = function(data) { warn("The OnTrainingFinished event happened with the following data:"); warn(uneval(data)); }; Trigger.prototype.TrainingQueuedAction = function(data) { warn("The OnTrainingQueued event happened with the following data:"); warn(uneval(data)); }; Trigger.prototype.ResearchFinishedAction = function(data) { warn("The OnResearchFinished event happened with the following data:"); warn(uneval(data)); }; Trigger.prototype.ResearchQueuedAction = function(data) { warn("The OnResearchQueued event happened with the following data:"); warn(uneval(data)); }; +Trigger.prototype.OwnershipChangedAction = function(data) +{ + warn("The OnOwnershipChanged event happened with the following data:"); + warn(uneval(data)); +}; + Trigger.prototype.PlayerCommandAction = function(data) { warn("The OnPlayerCommand event happened with the following data:"); warn(uneval(data)); }; Trigger.prototype.IntervalAction = function(data) { warn("The OnInterval event happened with the following data:"); warn(uneval(data)); this.numberOfTimerTrigger++; if (this.numberOfTimerTrigger >= this.maxNumberOfTimerTrigger) this.DisableTrigger("OnInterval", "IntervalAction"); }; Trigger.prototype.RangeAction = function(data) { warn("The OnRange event happened with the following data:"); warn(uneval(data)); }; // Activate all possible triggers var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); var data = {"enabled": true}; cmpTrigger.RegisterTrigger("OnStructureBuilt", "StructureBuiltAction", data); cmpTrigger.RegisterTrigger("OnConstructionStarted", "ConstructionStartedAction", data); cmpTrigger.RegisterTrigger("OnTrainingFinished", "TrainingFinishedAction", data); cmpTrigger.RegisterTrigger("OnTrainingQueued", "TrainingQueuedAction", data); cmpTrigger.RegisterTrigger("OnResearchFinished", "ResearchFinishedAction", data); cmpTrigger.RegisterTrigger("OnResearchQueued", "ResearchQueuedAction", data); +cmpTrigger.RegisterTrigger("OnOwnershipChanged", "OwnershipChangedAction", data); cmpTrigger.RegisterTrigger("OnPlayerCommand", "PlayerCommandAction", data); data.delay = 10000; // after 10 seconds data.interval = 1000; // every second cmpTrigger.numberOfTimerTrigger = 0; cmpTrigger.maxNumberOfTimerTrigger = 10; // execute it 10 times maximum cmpTrigger.RegisterTrigger("OnInterval", "IntervalAction", data); var entities = cmpTrigger.GetTriggerPoints("A"); data = { "entities": entities, // central points to calculate the range circles "players": [1], // only count entities of player 1 "maxRange": 40, "requiredComponent": IID_UnitAI, // only count units in range "enabled": true, }; cmpTrigger.RegisterTrigger("OnRange", "RangeAction", data); Index: ps/trunk/binaries/data/mods/public/simulation/components/Trigger.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/Trigger.js (revision 15425) +++ ps/trunk/binaries/data/mods/public/simulation/components/Trigger.js (revision 15426) @@ -1,258 +1,265 @@ function Trigger() {} Trigger.prototype.Schema = ""; /** * Events we're able to receive and call handlers for */ Trigger.prototype.eventNames = [ "StructureBuilt", "ConstructionStarted", "TrainingFinished", "TrainingQueued", "ResearchFinished", "ResearchQueued", + "OwnershipChanged", "PlayerCommand", "Interval", "Range", ]; Trigger.prototype.Init = function() { this.triggerPoints = {}; // Each event has its own set of actions determined by the map maker. for each (var eventName in this.eventNames) this["On" + eventName + "Actions"] = {}; }; Trigger.prototype.RegisterTriggerPoint = function(ref, ent) { if (!this.triggerPoints[ref]) this.triggerPoints[ref] = []; this.triggerPoints[ref].push(ent); }; Trigger.prototype.RemoveRegisteredTriggerPoint = function(ref, ent) { if (!this.triggerPoints[ref]) { warn("no trigger points found with ref "+ref); return; } var i = this.triggerPoints[ref].indexOf(ent); if (i == -1) { warn("entity " + ent + " wasn't found under the trigger points with ref "+ref); return; } this.triggerPoints[ref].splice(i, 1); }; Trigger.prototype.GetTriggerPoints = function(ref) { return this.triggerPoints[ref] || []; }; /** Binds the "action" function to one of the implemented events. * * @param event Name of the event (see the list in init) * @param action Functionname of a function available under this object * @param Extra Data for the trigger (enabled or not, delay for timers, range for range triggers ...) * * Interval triggers example: * data = {enabled: true, interval: 1000, delay: 500} * * Range trigger: * data.entities = [id1, id2] * Ids of the source * data.players = [1,2,3,...] * list of player ids * data.minRange = 0 * Minimum range for the query * data.maxRange = -1 * Maximum range for the query (-1 = no maximum) * data.requiredComponent = 0 * Required component id the entities will have * data.enabled = false * If the query is enabled by default */ Trigger.prototype.RegisterTrigger = function(event, action, data) { var eventString = event + "Actions"; if (!this[eventString]) { warn("Trigger.js: Invalid trigger event \"" + event + "\".") return; } if (this[eventString][action]) { warn("Trigger.js: Trigger has been registered before. Aborting..."); return; } // clone the data to be sure it's only modified locally // We could run into triggers overwriting each other's data otherwise. // F.e. getting the wrong timer tag data = clone(data) || {"enabled": false}; this[eventString][action] = data; // setup range query if (event == "OnRange") { if (!data.entities) { warn("Trigger.js: Range triggers should carry extra data"); return; } data.queries = []; for (var ent of data.entities) { var cmpTriggerPoint = Engine.QueryInterface(ent, IID_TriggerPoint); if (!cmpTriggerPoint) { warn("Trigger.js: Range triggers must be defined on trigger points"); continue; } data.queries.push(cmpTriggerPoint.RegisterRangeTrigger(action, data)); } } if (data.enabled) this.EnableTrigger(event, action); }; // Disable trigger Trigger.prototype.DisableTrigger = function(event, action) { var eventString = event + "Actions"; if (!this[eventString][action]) { warn("Trigger.js: Disabling unknown trigger"); return; } var data = this[eventString][action]; // special casing interval and range triggers for performance if (event == "OnInterval") { if (!data.timer) // don't disable it a second time return; var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); cmpTimer.CancelTimer(data.timer); data.timer = null; } else if (event == "OnRange") { if (!data.queries) { warn("Trigger.js: Range query wasn't set up before trying to disable it."); return; } var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); for (var query of data.queries) cmpRangeManager.DisableActiveQuery(query); } data.enabled = false; }; // Enable trigger Trigger.prototype.EnableTrigger = function(event, action) { var eventString = event + "Actions"; if (!this[eventString][action]) { warn("Trigger.js: Enabling unknown trigger"); return; } var data = this[eventString][action]; // special casing interval and range triggers for performance if (event == "OnInterval") { if (data.timer) // don't enable it a second time return; if (!data.interval) { warn("Trigger.js: An interval trigger should have an intervel in its data") return; } var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); var timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "DoAction", data.delay || 0, data.interval, {"action" : action}); data.timer = timer; } else if (event == "OnRange") { if (!data.queries) { warn("Trigger.js: Range query wasn't set up before"); return; } var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); for (var query of data.queries) cmpRangeManager.EnableActiveQuery(query); } data.enabled = true; }; /** * This function executes the actions bound to the events * It's either called directlty from other simulation scripts, * or from message listeners in this file * * @param event Name of the event (see the list in init) * @param data Data object that will be passed to the actions */ Trigger.prototype.CallEvent = function(event, data) { var eventString = "On" + event + "Actions"; if (!this[eventString]) { warn("Trigger.js: Unknown trigger event called:\"" + event + "\"."); return; } for (var action in this[eventString]) { if (this[eventString][action].enabled) this.DoAction({"action": action, "data":data}); } }; // Handles "OnStructureBuilt" event. Trigger.prototype.OnGlobalConstructionFinished = function(msg) { this.CallEvent("StructureBuilt", {"building": msg.newentity}); // The data for this one is {"building": constructedBuilding} }; // Handles "OnTrainingFinished" event. Trigger.prototype.OnGlobalTrainingFinished = function(msg) { this.CallEvent("TrainingFinished", msg); // The data for this one is {"entities": createdEnts, // "owner": cmpOwnership.GetOwner(), // "metadata": metadata} // See function "SpawnUnits" in ProductionQueue for more details }; +Trigger.prototype.OnGlobalOwnershipChanged = function(msg) +{ + this.CallEvent("OwnershipChanged", msg); + // data is {"entities": ents, "from": playerId, "to": playerId} +}; + /** * Execute a function after a certain delay * @param time The delay expressed in milleseconds * @param action Name of the action function * @param data Data object that will be passed to the action function */ Trigger.prototype.DoAfterDelay = function(miliseconds, action, data) { var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); return cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Trigger, "DoAction", miliseconds, {"action": action, "data": data}); }; /** * Called by the trigger listeners to exucute the actual action. Including sanity checks. */ Trigger.prototype.DoAction = function(msg) { if (this[msg.action]) this[msg.action](msg.data || null); else warn("Trigger.js: called a trigger action '" + msg.action + "' that wasn't found"); }; Engine.RegisterSystemComponentType(IID_Trigger, "Trigger", Trigger);