Ticket #52: Triggers.2.patch
File Triggers.2.patch, 35.2 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, delay) 29 { 30 delay = (delay === undefined ? 0 : delay); 31 32 // Stop the last timer before starting a new one 33 if (this.timer !== undefined) 34 this.StopUpdateTimer(); 35 36 // Start the update timer 37 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 38 this.timer = cmpTimer.SetInterval(this.entity, IID_Trigger, "TimerUpdate", delay, interval, undefined); 39 } 40 41 Trigger.prototype.StopUpdateTimer = function() 42 { 43 // Call the update timer 44 if (this.timer !== undefined) 45 { 46 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 47 cmpTimer.CancelTimer(this.timer); 48 this.timer = undefined; 49 } 50 } 51 52 // Binds the "action" function to one of the implemented events. "name" is a string for further access 53 // to the trigger for enabling/disabling. 54 Trigger.prototype.RegisterTrigger = function(name, event, action, enabled) 55 { 56 enabled = (enabled !== undefined ? enabled : true); 57 var validEvent = true; 58 switch (event) 59 { 60 case "OnEntityTookDamage": 61 this.eventOnEntityTookDamageActions[name] = action; 62 break; 63 case "OnEntityKilled": 64 this.eventOnEntityKilledActions[name] = action; 65 break; 66 case "OnUnitIssuedOrder": 67 this.eventOnUnitIssuedOrderActions[name] = action; 68 break; 69 case "OnStructureBuilt": 70 this.eventOnStructureBuiltActions[name] = action; 71 break; 72 case "OnConstructionStarted": 73 this.eventOnConstructionStartedActions[name] = action; 74 break; 75 case "OnTrainingFinished": 76 this.eventOnTrainingFinishedActions[name] = action; 77 break; 78 case "OnTrainingQueued": 79 this.eventOnTrainingQueuedActions[name] = action; 80 break; 81 case "OnResearchFinished": 82 this.eventOnResearchFinishedActions[name] = action; 83 break; 84 case "OnResearchQueued": 85 this.eventOnResearchQueuedActions[name] = action; 86 break; 87 case "Always": 88 this.eventAlwaysActions[name] = action; 89 break; 90 default: 91 validEvent = false; 92 break; 93 } 94 if (validEvent) 95 this.triggerEnabled[name] = enabled 96 else 97 error("Invalid trigger event \"" + event + "\"."); 98 }; 99 100 // This is an event with more than just the name argument, so we should have a special register function for it. 101 Trigger.prototype.RegisterOnUnitRangeFromEntityTrigger = function(event, name, entity, radius, action, players, component_id, enabled) 102 { 103 enabled = (enabled !== undefined ? enabled : true); 104 component_id = (component_id !== undefined ? component_id : 0); 105 106 // If the players parameter is not specified use all players. 107 if (!players) 108 { 109 var playerEntities = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayerEntities(); 110 players = []; 111 for each (var pentity in playerEntities) 112 players.push(Engine.QueryInterface(pentity, IID_Player).GetPlayerID()); 113 } 114 115 // 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. 116 // For the purpose of finding out the intersection of the previous and the current rangeQuery faster, we are sorting the current one. 117 this.eventOnUnitRangeFromEntityData[name] = {"event": event, "action": action, "entity": entity, "radius": radius, "currentCollection": [], "players": players}; 118 this.triggerEnabled[name] = enabled; 119 120 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 121 122 this.activeRangeQueries[name] = cmpRangeManager.CreateActiveQuery(entity, 0, radius, players, component_id, cmpRangeManager.GetEntityFlagMask("normal")); 123 cmpRangeManager.EnableActiveQuery(this.activeRangeQueries[name]); 124 } 125 126 // Disable trigger 127 Trigger.prototype.DisableTrigger = function(name) 128 { 129 if (this.triggerEnabled[name] !== undefined) 130 this.triggerEnabled[name] = false; 131 else 132 warn("Trigger doesn't exist:" + name); 133 } 134 135 // Enable trigger 136 Trigger.prototype.EnableTrigger = function(name) 137 { 138 if (this.triggerEnabled[name] !== undefined) 139 this.triggerEnabled[name] = true; 140 else 141 warn("Trigger doesn't exist:" + name); 142 } 143 144 // To handle the events that cannot be tracked by messages, this function should be called in the simulation code. 145 Trigger.prototype.CallEvent = function(event, data) 146 { 147 if (event == "OnEntityKilled") 148 { 149 for (var i in this.eventOnEntityKilledActions) 150 { 151 if (this.triggerEnabled[i]) // Check if it is enabled 152 g_TriggerActions[this.eventOnEntityKilledActions[i]](data); // The data for this one is {"killerEntity": killerEntity, "killedEntity": targetEntity} 153 154 // Remove the "OnUnitFromRangeEntity" triggers which have this entity as their argument 155 for (var j in this.eventOnUnitRangeFromEntityData) 156 { 157 if (this.eventOnUnitRangeFromEntityData[j].entity == data.killedEntity) 158 { 159 delete this.eventOnUnitRangeFromEntityData[j]; 160 delete this.triggerEnabled[j]; 161 } 162 } 163 } 164 165 return; 166 } 167 168 if (this["event" + event + "Actions"] === undefined) 169 { 170 warn("Invalid trigger event \"" + event + "\" called."); 171 return; 172 } 173 174 for (var i in this["event" + event + "Actions"]) 175 if (this.triggerEnabled[i]) 176 g_TriggerActions[this["event" + event + "Actions"][i]](data); 177 } 178 179 // Handles "OnStructureBuilt" event. 180 Trigger.prototype.OnGlobalConstructionFinished = function(msg) 181 { 182 for (var i in this.eventOnStructureBuiltActions) 183 if (this.triggerEnabled[i]) // Check if it is enabled 184 g_TriggerActions[this.eventOnStructureBuiltActions[i]]({"building": msg.newentity}); // The data for this one is {"building": constructedBuilding} 185 } 186 187 // Handles "OnTrainingFinished" event. 188 Trigger.prototype.OnGlobalTrainingFinished = function(msg) 189 { 190 for (var i in this.eventOnTrainingFinishedActions) 191 if (this.triggerEnabled[i]) // Check if it is enabled 192 g_TriggerActions[this.eventOnTrainingFinishedActions[i]](msg); // The data for this one is {"entities": createdEnts, 193 // "owner": cmpOwnership.GetOwner(), 194 // "metadata": metadata,} 195 // See function "SpawnUnits" in ProductionQueue for more details 196 } 197 198 // Handles an event that occurs by the interval the map designer specifies 199 Trigger.prototype.TimerUpdate = function(data, lateness) 200 { 201 // Handle "Always" event. 202 for (var i in this.eventAlwaysActions) 203 if (this.triggerEnabled[i]) // Check if it is enabled 204 g_TriggerActions[this.eventAlwaysActions[i]](); // This function event has no data 205 } 206 207 // Handles "OnUnitRangeFromEntity" 208 Trigger.prototype.OnGlobalRangeUpdate = function(msg) 209 { 210 var updatedRange = undefined; 211 for (var name in this.activeRangeQueries) 212 { 213 if (msg.tag == this.activeRangeQueries[name]) 214 { 215 updatedRange = name; 216 break; 217 } 218 } 219 220 if (updatedRange === undefined) 221 return; 222 223 for each (var entity in msg.removed) 224 { 225 var index = this.eventOnUnitRangeFromEntityData[name].currentCollection.indexOf(entity); 226 if (index > -1) 227 this.eventOnUnitRangeFromEntityData[name].currentCollection.splice(index, 1); 228 this.eventOnUnitRangeFromEntityData[name].currentCollection.push(entity); 229 } 230 231 for each (var entity in msg.added) 232 this.eventOnUnitRangeFromEntityData[name].currentCollection.push(entity); 233 234 if (this.triggerEnabled[name]) // Check if it is enabled 235 { 236 if (this.eventOnUnitRangeFromEntityData[name].event == "moved") 237 { 238 for each (var entity in this.eventOnUnitRangeFromEntityData[name].currentCollection) 239 { 240 var cmpUnitMotion = Engine.QueryInterface(entity, IID_UnitMotion); 241 if (cmpUnitMotion && cmpUnitMotion.IsMoving()) 242 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 243 } 244 } 245 else if (this.eventOnUnitRangeFromEntityData[name].event == "entered") 246 { 247 for each (var entity in msg.added) 248 { 249 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 250 } 251 } 252 else if (this.eventOnUnitRangeFromEntityData[name].event == "left") 253 { 254 for each (var entity in msg.removed) 255 { 256 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 257 } 258 } 259 else if (this.eventOnUnitRangeFromEntityData[name].event == "was inside") 260 { 261 for each (var entity in this.eventOnUnitRangeFromEntityData[name].currentCollection) 262 { 263 g_TriggerActions[this.eventOnUnitRangeFromEntityData[name].action]({"entity": entity}); 264 } 265 } 266 } 267 } 268 269 // These two functions are for handling one time timers in the triggers. 270 Trigger.prototype.DoAfterDelay = function(miliseconds, action, data) 271 { 272 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 273 return cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_Trigger, "DoAction", miliseconds, {"action": action, "data": data}); 274 } 275 276 Trigger.prototype.DoAction = function(data) 277 { 278 g_TriggerActions[data.action](data); 279 } 280 281 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 /** 70 * Returns the resource type that can be gathered from an entity 71 */ 72 function GetEntityResourceType(entity) 73 { 74 var cmpResourceSupply = Engine.QueryInterface(entity, IID_ResourceSupply); 75 if (!cmpResourceSupply) 76 return undefined; 77 return cmpResourceSupply.GetType(); 78 } 79 80 /** 81 * Returns a list of entities owned by the player 82 */ 83 function GetEntitiesByPlayer(playerID) 84 { 85 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 86 return cmpRangeManager.GetEntitiesByPlayer(playerID); 87 } 88 89 /** 90 * Wins the game for a player 91 */ 92 function SetPlayerWon(playerID) 93 { 94 var playerEnt = GetPlayerEntityByID(playerID); 95 var cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player); 96 cmpPlayer.SetState("won") 97 } 98 99 /** 100 * Defeats a player 101 */ 102 function DefeatPlayer(playerID) 103 { 104 var playerEnt = GetPlayerEntityByID(playerID); 105 Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": playerID } ); 106 } 107 108 Engine.RegisterGlobal("GetEntityOwner", GetEntityOwner); 109 Engine.RegisterGlobal("GetEntityGenericName", GetEntityGenericName); 110 Engine.RegisterGlobal("GetEntityClassesList", GetEntityClassesList); 111 Engine.RegisterGlobal("EntityHasClass", EntityHasClass); 112 Engine.RegisterGlobal("GetPlayerEntityByID", GetPlayerEntityByID); 113 Engine.RegisterGlobal("BuildingSpawnUnits", BuildingSpawnUnits); 114 Engine.RegisterGlobal("PushGUINotificationInTopCenter", PushGUINotificationInTopCenter); 115 Engine.RegisterGlobal("GetEntityResourceType", GetEntityResourceType); 116 Engine.RegisterGlobal("GetEntitiesByPlayer", GetEntitiesByPlayer); 117 Engine.RegisterGlobal("SetPlayerWon", SetPlayerWon); 118 Engine.RegisterGlobal("DefeatPlayer", DefeatPlayer); 119 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()