Ticket #52: Triggers.patch
File Triggers.patch, 33.5 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/maps/scripts/test.js
1 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 2 3 // Test rigger to log the kills and defeat a player if his/her hero dies 4 function trigger1_Action(data) 5 { 6 var cmpKilled = Engine.QueryInterface(data.killedEntity, IID_Identity); 7 var killedPlayerId = GetEntityOwner(data.killedEntity); 8 var killerPlayerId = GetEntityOwner(data.killerEntity); 9 var cmpKiller = Engine.QueryInterface(data.killerEntity, IID_Identity); 10 log("A player " + killerPlayerId + "'s " + GetEntityGenericName(data.killerEntity) + " killed a player " + killedPlayerId + "'s " + GetEntityGenericName(data.killedEntity) + "."); 11 12 if (EntityHasClass(data.killedEntity, "Hero")) 13 { 14 var playerEnt = GetPlayerEntityByID(killedPlayerId); 15 Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": killedPlayerId } ); 16 } 17 } 18 19 // Test trigger to check the "OnUnitRangeFromEntity" event. If entity 473 (Cyrus) gets near the entity 273 (The enemy embassy), 5 swordsman are spawned. This is done only once 20 function trigger2_Action(data) 21 { 22 if (data.entity == 473) 23 { 24 BuildingSpawnUnits(273, "units/cart_infantry_swordsman_2_b", 5); 25 26 log("Ok. Finish it."); 27 cmpTrigger.DisableTrigger("trigger2"); 28 } 29 } 30 31 // Test trigger to check the orders given by the player. Only works for the hero and the elite archer 32 function trigger3_Action(data) 33 { 34 if (data.entity == 473) 35 { 36 PushGUINotificationInTopCenter(1, "Your hero is ordered: " + data.order); 37 } 38 else if (data.entity == 474) 39 { 40 PushGUINotificationInTopCenter(1, "Your archer is ordered: " + data.order); 41 } 42 } 43 44 // The set of global trigger actions. The name must always be "g_TriggerActions" 45 var g_TriggerActions = { 46 "trigger1_Action": trigger1_Action, 47 "trigger2_Action": trigger2_Action, 48 "trigger3_Action": trigger3_Action 49 }; 50 51 // Make the trigger actions global so that we can use it in the trigger component. 52 Engine.RegisterGlobal("g_TriggerActions", g_TriggerActions); 53 54 // Register the triggers 55 cmpTrigger.RegisterTrigger("trigger1", "OnEntityKilled", "trigger1_Action"); 56 cmpTrigger.RegisterOnUnitRangeFromEntityTrigger("entered", "trigger2", 273, 40, "trigger2_Action", [0, 1, 2], IID_DamageReceiver); 57 cmpTrigger.RegisterTrigger("trigger3", "OnUnitIssuedOrder", "trigger3_Action"); 58 No newline at end of file -
binaries/data/mods/public/simulation/components/BuildingAI.js
146 146 */ 147 147 BuildingAI.prototype.OnRangeUpdate = function(msg) 148 148 { 149 150 149 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 151 150 if (!cmpAttack) 152 151 return; -
binaries/data/mods/public/simulation/components/Foundation.js
202 202 // (via CCmpTemplateManager). Now we need to remove that temporary 203 203 // blocker-disabling, so that we'll perform standard unit blocking instead. 204 204 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}); 205 209 } 206 210 207 211 // Switch foundation to scaffold variant -
binaries/data/mods/public/simulation/components/interfaces/Trigger.js
1 Engine.RegisterInterface("Trigger"); -
binaries/data/mods/public/simulation/components/ProductionQueue.js
288 288 "timeTotal": time*1000, 289 289 "timeRemaining": time*1000, 290 290 }); 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}); 291 295 } 292 296 else if (type == "technology") 293 297 { … … 324 328 "timeTotal": time*1000, 325 329 "timeRemaining": time*1000, 326 330 }); 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}); 327 335 } 328 336 else 329 337 { -
binaries/data/mods/public/simulation/components/ResourceTrickle.js
57 57 if (cmpPlayer) 58 58 for (var resource in rates) 59 59 cmpPlayer.AddResource(resource, rates[resource]); 60 61 60 }; 62 61 63 62 Engine.RegisterComponentType(IID_ResourceTrickle, "ResourceTrickle", ResourceTrickle); -
binaries/data/mods/public/simulation/components/TechnologyManager.js
283 283 return; 284 284 } 285 285 286 // Call the related trigger event 287 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 288 cmpTrigger.CallEvent("OnResearchFinished", {"researcher": this.entity, "tech": tech}); 289 286 290 var modifiedComponents = {}; 287 291 this.researchedTechs[tech] = template; 288 292 // store the modifications in an easy to access structure -
binaries/data/mods/public/simulation/components/Trigger.js
1 function Trigger() {} 2 3 Trigger.prototype.Schema = 4 "<a:component type='system'/><empty/>"; 5 6 Trigger.prototype.Init = function() 7 { 8 // Each event has its own set of actions determined by the map maker. 9 this.eventOnEntityTookDamageActions = {}; 10 this.eventOnEntityKilledActions = {}; 11 this.eventOnStructureBuiltActions = {}; 12 this.eventOnConstructionStartedActions = {}; 13 this.eventOnTrainingFinishedActions = {}; 14 this.eventOnTrainingQueuedActions = {}; 15 this.eventOnResearchFinishedActions = {}; 16 this.eventOnResearchQueuedActions = {}; 17 this.eventAlwaysActions = {}; 18 this.eventOnUnitRangeFromEntityData = {}; 19 this.eventOnUnitIssuedOrderActions = {}; 20 21 // We are going to have all of the triggers here to be able to enable/disbale them in runtime. 22 this.triggerEnabled = {}; 23 24 // Queries for OnUnitFromEntity events 25 this.activeRangeQueries = {}; 26 }; 27 28 Trigger.prototype.StartUpdateTimer = function(interval) 29 { 30 // Stop the last timer before starting a new one 31 if (this.timer !== undefined) 32 this.StopUpdateTimer(); 33 34 // Start the update timer 35 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 36 this.timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "TimerUpdate", 0, interval, undefined); 37 } 38 39 Trigger.prototype.StopUpdateTimer = function() 40 { 41 // Call the update timer 42 if (this.timer !== undefined) 43 { 44 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 45 cmpTimer.CancelTimer(this.timer); 46 this.timer = undefined; 47 } 48 } 49 50 // Binds the "action" function to one of the implemented events. "name" is a string for further access 51 // to the trigger for enabling/disabling. 52 Trigger.prototype.RegisterTrigger = function(name, event, action, enabled) 53 { 54 enabled = (enabled !== undefined ? enabled : true); 55 var validEvent = true; 56 switch (event) 57 { 58 case "OnEntityTookDamage": 59 this.eventOnEntityTookDamageActions[name] = action; 60 break; 61 case "OnEntityKilled": 62 this.eventOnEntityKilledActions[name] = action; 63 break; 64 case "OnUnitIssuedOrder": 65 this.eventOnUnitIssuedOrderActions[name] = action; 66 break; 67 case "OnStructureBuilt": 68 this.eventOnStructureBuiltActions[name] = action; 69 break; 70 case "OnConstructionStarted": 71 this.eventOnConstructionStartedActions[name] = action; 72 break; 73 case "OnTrainingFinished": 74 this.eventOnTrainingFinishedActions[name] = action; 75 break; 76 case "OnTrainingQueued": 77 this.eventOnTrainingQueuedActions[name] = action; 78 break; 79 case "OnResearchFinished": 80 this.eventOnResearchFinishedActions[name] = action; 81 break; 82 case "OnResearchQueued": 83 this.eventOnResearchQueuedActions[name] = action; 84 break; 85 case "Always": 86 this.eventAlwaysActions[name] = action; 87 break; 88 default: 89 validEvent = false; 90 break; 91 } 92 if (validEvent) 93 this.triggerEnabled[name] = enabled 94 else 95 error("Invalid trigger event \"" + event + "\"."); 96 }; 97 98 // This is an event with more than just the name argument, so we should have a special register function for it. 99 Trigger.prototype.RegisterOnUnitRangeFromEntityTrigger = function(event, name, entity, radius, action, players, component_id, enabled) 100 { 101 enabled = (enabled !== undefined ? enabled : true); 102 component_id = (component_id !== undefined ? component_id : 0); 103 104 // If the players parameter is not specified use all players. 105 if (!players) 106 { 107 var playerEntities = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayerEntities(); 108 players = []; 109 for each (var pentity in playerEntities) 110 players.push(Engine.QueryInterface(pentity, IID_Player).GetPlayerID()); 111 } 112 113 // To determine if a unit has "moved" or "was inside" the range, we should know if it was in the range before. We have "currentCollection" for this purpose. 114 // For the purpose of finding out the intersection of the previous and the current rangeQuery faster, we are sorting the current one. 115 this.eventOnUnitRangeFromEntityData[name] = {"event": event, "action": action, "entity": entity, "radius": radius, "currentCollection": [], "players": players}; 116 this.triggerEnabled[name] = enabled; 117 118 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 119 120 this.activeRangeQueries[name] = cmpRangeManager.CreateActiveQuery(entity, 0, radius, players, component_id, cmpRangeManager.GetEntityFlagMask("normal")); 121 cmpRangeManager.EnableActiveQuery(this.activeRangeQueries[name]); 122 } 123 124 // Disable trigger 125 Trigger.prototype.DisableTrigger = function(name) 126 { 127 if (this.triggerEnabled[name] !== undefined) 128 this.triggerEnabled[name] = false; 129 else 130 warn("Trigger doesn't exist:" + name); 131 } 132 133 // Enable trigger 134 Trigger.prototype.EnableTrigger = function(name) 135 { 136 if (this.triggerEnabled[name] !== undefined) 137 this.triggerEnabled[name] = true; 138 else 139 warn("Trigger doesn't exist:" + name); 140 } 141 142 // To handle the events that cannot be tracked by messages, this function should be called in the simulation code. 143 Trigger.prototype.CallEvent = function(event, data) 144 { 145 if (event == "OnEntityKilled") 146 { 147 for (var i in this.eventOnEntityKilledActions) 148 { 149 if (this.triggerEnabled[i]) // Check if it is enabled 150 g_TriggerActions[this.eventOnEntityKilledActions[i]](data); // The data for this one is {"killerEntity": killerEntity, "killedEntity": targetEntity} 151 152 // Remove the "OnUnitFromRangeEntity" triggers which have this entity as their argument 153 for (var j in this.eventOnUnitRangeFromEntityData) 154 { 155 if (this.eventOnUnitRangeFromEntityData[j].entity == data.killedEntity) 156 { 157 delete this.eventOnUnitRangeFromEntityData[j]; 158 delete this.triggerEnabled[j]; 159 } 160 } 161 } 162 163 return; 164 } 165 166 if (this["event" + event + "Actions"] === undefined) 167 { 168 warn("Invalid trigger event \"" + event + "\" called."); 169 return; 170 } 171 172 for (var i in this["event" + event + "Actions"]) 173 if (this.triggerEnabled[i]) 174 g_TriggerActions[this["event" + event + "Actions"][i]](data); 175 } 176 177 // Handles "OnStructureBuilt" event. 178 Trigger.prototype.OnGlobalConstructionFinished = function(msg) 179 { 180 for (var i in this.eventOnStructureBuiltActions) 181 if (this.triggerEnabled[i]) // Check if it is enabled 182 g_TriggerActions[this.eventOnStructureBuiltActions[i]]({"building": msg.newentity}); // The data for this one is {"building": constructedBuilding} 183 } 184 185 // Handles "OnTrainingFinished" event. 186 Trigger.prototype.OnGlobalTrainingFinished = function(msg) 187 { 188 for (var i in this.eventOnTrainingFinishedActions) 189 if (this.triggerEnabled[i]) // Check if it is enabled 190 g_TriggerActions[this.eventOnTrainingFinishedActions[i]](msg); // The data for this one is {"entities": createdEnts, 191 // "owner": cmpOwnership.GetOwner(), 192 // "metadata": metadata,} 193 // See function "SpawnUnits" in ProductionQueue for more details 194 } 195 196 // Handles an event that occurs by the interval the map designer specifies 197 Trigger.prototype.TimerUpdate = function(data, lateness) 198 { 199 // Handle "Always" event. 200 for (var i in this.eventAlwaysActions) 201 if (this.triggerEnabled[i]) // Check if it is enabled 202 eval(this.eventAlwaysActions[i] + "()"); // This function event has no data 203 } 204 205 // Handles "OnUnitRangeFromEntity" 206 Trigger.prototype.OnGlobalRangeUpdate = function(msg) 207 { 208 var updatedRange = undefined; 209 for (var name in this.activeRangeQueries) 210 { 211 if (msg.tag == this.activeRangeQueries[name]) 212 { 213 updatedRange = name; 214 break; 215 } 216 } 217 218 if (updatedRange === undefined) 219 return; 220 221 for each (var entity in msg.removed) 222 { 223 var index = this.eventOnUnitRangeFromEntityData[name].currentCollection.indexOf(entity); 224 if (index > -1) 225 this.eventOnUnitRangeFromEntityData[name].currentCollection.splice(index, 1); 226 this.eventOnUnitRangeFromEntityData[name].currentCollection.push(entity); 227 } 228 229 for each (var entity in msg.added) 230 this.eventOnUnitRangeFromEntityData[name].currentCollection.push(entity); 231 232 if (this.triggerEnabled[name]) // Check if it is enabled 233 { 234 if (this.eventOnUnitRangeFromEntityData[name].event == "moved") 235 { 236 for each (var entity in this.eventOnUnitRangeFromEntityData[name].currentCollection) 237 { 238 var cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); 239 if (cmpUnitMotion && cmpUnitMotion.IsMoving()) 240 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 241 } 242 } 243 else if (this.eventOnUnitRangeFromEntityData[name].event == "entered") 244 { 245 for each (var entity in msg.added) 246 { 247 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 248 } 249 } 250 else if (this.eventOnUnitRangeFromEntityData[name].event == "left") 251 { 252 for each (var entity in msg.removed) 253 { 254 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 255 } 256 } 257 else if (this.eventOnUnitRangeFromEntityData[name].event == "was inside") 258 { 259 for each (var entity in this.eventOnUnitRangeFromEntityData[name].currentCollection) 260 { 261 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 262 } 263 } 264 } 265 } 266 267 Engine.RegisterComponentType(IID_Trigger, "Trigger", Trigger); -
binaries/data/mods/public/simulation/components/UnitAI.js
199 199 cmpUnitMotion.MoveToFormationOffset(msg.data.target, msg.data.x, msg.data.z); 200 200 201 201 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}); 202 205 }, 203 206 204 207 // Special orders: … … 225 228 // We are already at the target, or can't move at all 226 229 this.FinishOrder(); 227 230 } 231 232 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 233 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.LeaveFoundation", "metadata": msg}); 228 234 }, 229 235 230 236 // Individual orders: … … 247 253 this.SetNextState("ANIMAL.IDLE"); 248 254 else 249 255 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}); 251 259 }, 252 260 253 261 "Order.Walk": function(msg) { … … 258 266 return; 259 267 } 260 268 269 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 270 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Walk", "metadata": msg}); 271 261 272 // For packable units: 262 273 // 1. If packed, we can move. 263 274 // 2. If unpacked, we first need to pack, then follow case 1. … … 284 295 return; 285 296 } 286 297 298 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 299 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.WalkAndFight", "metadata": msg}); 300 287 301 // For packable units: 288 302 // 1. If packed, we can move. 289 303 // 2. If unpacked, we first need to pack, then follow case 1. … … 310 324 this.FinishOrder(); 311 325 return; 312 326 } 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 314 331 // For packable units: 315 332 // 1. If packed, we can move. 316 333 // 2. If unpacked, we first need to pack, then follow case 1. … … 358 375 this.StopMoving(); 359 376 this.SetNextState("INDIVIDUAL.PICKUP.LOADING"); 360 377 } 378 379 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 380 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.PickupUnit", "metadata": msg, "target": this.order.data.target}); 361 381 }, 362 382 363 383 "Order.Guard": function(msg) { … … 371 391 this.SetNextState("INDIVIDUAL.GUARD.ESCORTING"); 372 392 else 373 393 this.SetNextState("INDIVIDUAL.GUARD.GUARDING"); 394 395 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 396 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Guard", "metadata": msg, "target": this.order.data.target}); 374 397 }, 375 398 376 399 "Order.Flee": function(msg) { … … 379 402 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 380 403 if (cmpUnitMotion.MoveToTargetRange(this.order.data.target, distance, -1)) 381 404 { 405 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 406 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Flee", "metadata": msg, "target": this.order.data.target}); 407 382 408 // We've started fleeing from the given target 383 409 if (this.IsAnimal()) 384 410 this.SetNextState("ANIMAL.FLEEING"); … … 391 417 this.StopMoving(); 392 418 this.FinishOrder(); 393 419 } 420 421 394 422 }, 395 423 396 424 "Order.Attack": function(msg) { … … 411 439 } 412 440 this.order.data.attackType = type; 413 441 442 // Call "OnUnitIssuedOrder" event of the triggers. 443 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 444 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Attack", "metadata": msg, "target": this.order.data.target}); 445 414 446 // If we are already at the target, try attacking it from here 415 447 if (this.CheckTargetAttackRange(this.order.data.target, this.order.data.attackType)) 416 448 { … … 495 527 // We can't reach the target, and can't move towards it, 496 528 // so abandon this attack order 497 529 this.FinishOrder(); 530 498 531 }, 499 532 500 533 "Order.Heal": function(msg) { … … 515 548 // Check if the target is in range 516 549 if (this.CheckTargetRange(this.order.data.target, IID_Heal)) 517 550 { 551 // Call "OnUnitIssuedOrder" event of the triggers. 552 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 553 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Heal", "metadata": msg, "target": this.order.data.target}); 554 518 555 this.StopMoving(); 519 556 this.SetNextState("INDIVIDUAL.HEAL.HEALING"); 520 557 return; … … 531 568 // Try to move within heal range 532 569 if (this.MoveToTargetRange(this.order.data.target, IID_Heal)) 533 570 { 571 // Call "OnUnitIssuedOrder" event of the triggers. 572 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 573 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Heal", "metadata": msg, "target": this.order.data.target}); 574 534 575 // We've started walking to the given point 535 576 this.SetNextState("INDIVIDUAL.HEAL.APPROACHING"); 536 577 return; … … 588 629 this.StopMoving(); 589 630 this.SetNextStateAlwaysEntering("INDIVIDUAL.GATHER.GATHERING"); 590 631 } 632 633 // Call "OnUnitIssuedOrder" event of the triggers. 634 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 635 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Gather", "metadata": msg, "target": this.order.data.target}); 591 636 }, 592 637 593 638 "Order.GatherNearPosition": function(msg) { 594 639 // Move the unit to the position to gather from. 595 640 this.MoveToPoint(this.order.data.x, this.order.data.z); 596 641 this.SetNextState("INDIVIDUAL.GATHER.WALKING"); 642 643 // Call "OnUnitIssuedOrder" event of the triggers. 644 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 645 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.GatherNearPosition", "metadata": msg, "target": this.order.data.target}); 597 646 }, 598 647 599 648 "Order.ReturnResource": function(msg) { … … 617 666 // Try to move to the dropsite 618 667 if (this.MoveToTargetRange(this.order.data.target, IID_ResourceGatherer)) 619 668 { 669 // Call "OnUnitIssuedOrder" event of the triggers. 670 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 671 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.ReturnResource", "metadata": msg, "target": this.order.data.target}); 672 620 673 // We've started walking to the target 621 674 this.SetNextState("INDIVIDUAL.RETURNRESOURCE.APPROACHING"); 622 675 return; … … 649 702 this.waypoints = undefined; 650 703 if (this.MoveToMarket(nextMarket)) 651 704 { 705 // Call "OnUnitIssuedOrder" event of the triggers. 706 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 707 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Trade", "metadata": msg, "target": this.order.data.target}); 708 652 709 // We've started walking to the next market 653 710 this.SetNextState(state); 654 711 } … … 671 728 this.StopMoving(); 672 729 this.SetNextState("INDIVIDUAL.REPAIR.REPAIRING"); 673 730 } 731 732 // Call "OnUnitIssuedOrder" event of the triggers. 733 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 734 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Repair", "metadata": msg, "target": this.order.data.target}); 674 735 }, 675 736 676 737 "Order.Garrison": function(msg) { 738 // Call "OnUnitIssuedOrder" event of the triggers. 739 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 740 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Garrison", "metadata": msg, "target": this.order.data.target}); 741 677 742 // For packable units: 678 743 // 1. If packed, we can move to the garrison target. 679 744 // 2. If unpacked, we first need to pack, then follow case 1. … … 698 763 699 764 "Order.Autogarrison": function(msg) { 700 765 this.SetNextState("INDIVIDUAL.AUTOGARRISON"); 766 767 // Call "OnUnitIssuedOrder" event of the triggers. 768 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 769 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Autogarrison", "metadata": msg}); 701 770 }, 702 771 703 772 "Order.Alert": function(msg) { … … 711 780 this.ReplaceOrder("Garrison", {"target": this.alertGarrisoningTarget}); 712 781 else 713 782 this.FinishOrder(); 783 784 // Call "OnUnitIssuedOrder" event of the triggers. 785 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 786 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Alert", "metadata": msg}); 714 787 }, 715 788 716 789 "Order.Cheering": function(msg) { 717 790 this.SetNextState("INDIVIDUAL.CHEERING"); 791 792 // Call "OnUnitIssuedOrder" event of the triggers. 793 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 794 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Cheering", "metadata": msg}); 718 795 }, 719 796 720 797 "Order.Pack": function(msg) { … … 722 799 { 723 800 this.StopMoving(); 724 801 this.SetNextState("INDIVIDUAL.PACKING"); 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.Pack", "metadata": msg}); 725 806 } 726 807 }, 727 808 … … 730 811 { 731 812 this.StopMoving(); 732 813 this.SetNextState("INDIVIDUAL.UNPACKING"); 814 815 // Call "OnUnitIssuedOrder" event of the triggers. 816 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 817 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.Unpack", "metadata": msg}); 733 818 } 734 819 }, 735 820 … … 738 823 if (cmpPack && cmpPack.IsPacking() && !cmpPack.IsPacked()) 739 824 cmpPack.CancelPack(); 740 825 this.FinishOrder(); 826 827 // Call "OnUnitIssuedOrder" event of the triggers. 828 var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); 829 cmpTrigger.CallEvent("OnUnitIssuedOrder", {"entity": this.entity, "order": "Order.CancelPack", "metadata": msg}); 741 830 }, 742 831 743 832 "Order.CancelUnpack": function(msg) { … … 745 834 if (cmpPack && cmpPack.IsPacking() && cmpPack.IsPacked()) 746 835 cmpPack.CancelPack(); 747 836 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.CancelUnpack", "metadata": msg}); 748 841 }, 749 842 750 843 // States for the special entity representing a group of units moving in formation: … … 809 902 var cmpTargetUnitAI = Engine.QueryInterface(target, IID_UnitAI); 810 903 if (cmpTargetUnitAI && cmpTargetUnitAI.IsFormationMember()) 811 904 target = cmpTargetUnitAI.GetFormationController(); 812 905 813 906 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 814 907 // Check if we are already in range, otherwise walk there 815 908 if (!this.CheckTargetAttackRange(target, target)) … … 838 931 this.FinishOrder(); 839 932 return; 840 933 } 934 841 935 // Check if we are already in range, otherwise walk there 842 936 if (!this.CheckGarrisonRange(msg.data.target)) 843 937 { … … 915 1009 } 916 1010 917 1011 this.CallMemberFunction("GatherNearPosition", [msg.data.x, msg.data.z, msg.data.type, msg.data.template, false]); 918 1012 919 1013 this.SetNextStateAlwaysEntering("MEMBER"); 920 1014 }, 921 1015 … … 934 1028 } 935 1029 936 1030 this.CallMemberFunction("Heal", [msg.data.target, false]); 937 1031 938 1032 this.SetNextStateAlwaysEntering("MEMBER"); 939 1033 }, 940 1034 … … 1188 1282 1189 1283 // Stop moving as soon as the formation disbands 1190 1284 this.StopMoving(); 1191 1285 1192 1286 // If the controller handled an order but some members rejected it, 1193 1287 // they will have no orders and be in the FORMATIONMEMBER.IDLE state. 1194 1288 if (this.orderQueue.length) -
binaries/data/mods/public/simulation/helpers/Damage.js
74 74 // Damage the target 75 75 var targetState = cmpDamageReceiver.TakeDamage(data.strengths.hack * data.multiplier, data.strengths.pierce * data.multiplier, data.strengths.crush * data.multiplier, data.attacker); 76 76 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 77 83 // If the target was killed run some cleanup 78 84 if (targetState.killed) 79 85 Damage.TargetKilled(data.attacker, data.target); … … 110 116 // Call RangeManager with dummy entity and return the result. 111 117 var rangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 112 118 var rangeQuery = rangeManager.ExecuteQueryAroundPos(origin, 0, radius, players, IID_DamageReceiver); 119 113 120 return rangeQuery; 114 121 }; 115 122 … … 133 140 var cmpLooter = Engine.QueryInterface(killerEntity, IID_Looter); 134 141 if (cmpLooter) 135 142 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}); 136 147 }; 137 148 138 149 Engine.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 /** 5 * A function to get the owner of an entity. 6 * Returns the ID of a player. Returns 0 if the owner is Gaia. 7 */ 8 function GetEntityOwner(entity) 9 { 10 return Engine.QueryInterface(entity, IID_Ownership).GetOwner() 11 } 12 13 /** 14 * A function to get the generic name of an entity 15 */ 16 function GetEntityGenericName(entity) 17 { 18 var cmpIdentity = Engine.QueryInterface(entity, IID_Identity); 19 return cmpIdentity.GetGenericName(); 20 } 21 22 /** 23 * A function to get a list of the classes of an entity 24 */ 25 function GetEntityClassesList(entity) 26 { 27 var cmpIdentity = Engine.QueryInterface(entity, IID_Identity); 28 return cmpIdentity.GetClassesList(); 29 } 30 31 /** 32 * A function to determine if an entity has a specific class 33 */ 34 function EntityHasClass(entity, classname) 35 { 36 var classes = GetEntityClassesList(entity); 37 return (classes && classes.indexOf(classname) != -1); 38 } 39 40 /** 41 * Returns the entity id of a player based on the id of the player 42 * Useful when one wants to change a player's properties. 43 */ 44 function GetPlayerEntityByID(id) 45 { 46 var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 47 return cmpPlayerMan.GetPlayerByID(id); 48 } 49 50 /** 51 * Can be used to "force" a building to spawn a group of entities. 52 * Only works for buildings that can already train units. 53 */ 54 function BuildingSpawnUnits(entity, template, count) 55 { 56 var cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue); 57 cmpProductionQueue.SpawnUnits(template, count, null); 58 } 59 60 /** 61 * Shows a message in the top center of the screen 62 */ 63 function PushGUINotificationInTopCenter(player, message) 64 { 65 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 66 cmpGUIInterface.PushNotification({"player": player, "message": message}); 67 } 68 69 Engine.RegisterGlobal("GetEntityOwner", GetEntityOwner); 70 Engine.RegisterGlobal("GetEntityGenericName", GetEntityGenericName); 71 Engine.RegisterGlobal("GetEntityClassesList", GetEntityClassesList); 72 Engine.RegisterGlobal("EntityHasClass", EntityHasClass); 73 Engine.RegisterGlobal("GetPlayerEntityByID", GetPlayerEntityByID); 74 Engine.RegisterGlobal("BuildingSpawnUnits", BuildingSpawnUnits); 75 Engine.RegisterGlobal("PushGUINotificationInTopCenter", PushGUINotificationInTopCenter); 76 No newline at end of file -
source/simulation2/Simulation2.cpp
133 133 LOAD_SCRIPTED_COMPONENT("PlayerManager"); 134 134 LOAD_SCRIPTED_COMPONENT("TechnologyTemplateManager"); 135 135 LOAD_SCRIPTED_COMPONENT("Timer"); 136 LOAD_SCRIPTED_COMPONENT("Trigger"); 136 137 LOAD_SCRIPTED_COMPONENT("ValueModificationManager"); 137 138 138 139 #undef LOAD_SCRIPTED_COMPONENT … … 748 749 749 750 if (!m->m_StartupScript.empty()) 750 751 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 } 751 762 } 752 763 753 764 int CSimulation2::ProgressiveLoad()