Ticket #4082: globalauras.diff
File globalauras.diff, 15.6 KB (added by , 7 years ago) |
---|
-
binaries/data/mods/public/simulation/components/AuraManager.js
AuraManager.prototype.Init = function() 7 7 { 8 8 this.modificationsCache = new Map(); 9 9 this.modifications = new Map(); 10 10 this.templateModificationsCache = new Map(); 11 11 this.templateModifications = new Map(); 12 13 this.globalAuraGivers = []; 14 }; 15 16 17 AuraManager.prototype.RegisterGlobalAuraGiver = function(ent) 18 { 19 if (this.globalAuraGivers.indexOf(ent) == -1) 20 this.globalAuraGivers.push(ent); 21 }; 22 23 AuraManager.prototype.UnregisterGlobalAuraGiver = function(ent) 24 { 25 let idx = this.globalAuraGivers.indexOf(ent); 26 if (idx != -1) 27 this.globalAuraGivers.splice(idx, 1); 12 28 }; 13 29 14 30 AuraManager.prototype.ensureExists = function(name, value, id, key, defaultData) 15 31 { 16 32 var cacheName = name + "Cache"; … … AuraManager.prototype.ApplyTemplateModif 228 244 } 229 245 } 230 246 return value * multiply + add; 231 247 }; 232 248 249 AuraManager.prototype.OnGlobalOwnershipChanged = function(msg) 250 { 251 for (let ent of this.globalAuraGivers) 252 { 253 let cmpAuras = Engine.QueryInterface(ent, IID_Auras); 254 if (cmpAuras) 255 cmpAuras.RegisterGlobalOwnershipChanged(msg); 256 } 257 }; 258 233 259 Engine.RegisterSystemComponentType(IID_AuraManager, "AuraManager", AuraManager); -
binaries/data/mods/public/simulation/components/Auras.js
Auras.prototype.GetAffectedEntities = fu 58 58 return this[name].targetUnits; 59 59 }; 60 60 61 61 Auras.prototype.GetRange = function(name) 62 62 { 63 if (!this.IsRangeAura(name)) 64 return undefined; 65 if (this.IsGlobalAura(name)) 66 return -1; // -1 is infinite range 67 return +this.auras[name].radius; 63 if (this.IsRangeAura(name)) 64 return +this.auras[name].radius; 65 return undefined; 68 66 }; 69 67 70 68 Auras.prototype.GetClasses = function(name) 71 69 { 72 70 return this.auras[name].affects; … … Auras.prototype.IsGarrisonedUnitsAura = 152 150 return this.GetType(name) == "garrisonedUnits"; 153 151 }; 154 152 155 153 Auras.prototype.IsRangeAura = function(name) 156 154 { 157 // A global aura is also treated as a range aura with infinite range. 158 return ["range", "global"].indexOf(this.GetType(name)) != -1; 155 return this.GetType(name) == "range"; 159 156 }; 160 157 161 158 Auras.prototype.IsGlobalAura = function(name) 162 159 { 163 160 return this.GetType(name) == "global"; … … Auras.prototype.Clean = function() 202 199 var affectedPlayers = this.GetAffectedPlayers(name); 203 200 204 201 if (!affectedPlayers.length) 205 202 continue; 206 203 207 if ( !this.IsRangeAura(name))204 if (this.IsGlobalAura(name)) 208 205 { 209 this.ApplyBonus(name, targetUnitsClone[name]); 206 for (let player of affectedPlayers) 207 { 208 this.ApplyTemplateBonus(name, affectedPlayers); 209 // When only Player class affected, we do not need a rangeQuery as applicable only to player entity 210 // and templates TODO maybe add a new type "player" 211 if (this.GetClasses(name).length == 1 && this.GetClasses(name)[0] == "Player") 212 { 213 let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 214 let playerEnts = affectedPlayers.map(player => cmpPlayerManager.GetPlayerByID(player)); 215 this.ApplyBonus(name, playerEnts); 216 } 217 else 218 this.ApplyBonus(name, cmpRangeManager.GetEntitiesByPlayer(player)); 219 } 210 220 continue; 211 221 } 212 222 213 // When only Player class affected, we do not need a rangeQuery as applicable only to player entity 214 // and templates TODO maybe add a new type "player" 215 if (this.IsGlobalAura(name) && this.GetClasses(name).length == 1 && this.GetClasses(name)[0] == "Player") 223 if (!this.IsRangeAura(name)) 216 224 { 217 this.ApplyTemplateBonus(name, affectedPlayers); 218 let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 219 let playerEnts = affectedPlayers.map(player => cmpPlayerManager.GetPlayerByID(player)); 220 this.ApplyBonus(name, playerEnts); 225 this.ApplyBonus(name, targetUnitsClone[name]); 221 226 continue; 222 227 } 223 228 224 229 this[name].rangeQuery = cmpRangeManager.CreateActiveQuery( 225 230 this.entity, … … Auras.prototype.Clean = function() 228 233 affectedPlayers, 229 234 IID_Identity, 230 235 cmpRangeManager.GetEntityFlagMask("normal") 231 236 ); 232 237 cmpRangeManager.EnableActiveQuery(this[name].rangeQuery); 233 234 if (this.IsGlobalAura(name))235 {236 this.ApplyTemplateBonus(name, affectedPlayers);237 238 // Add self to your own query for consistency with templates.239 this.OnRangeUpdate({240 "tag": this[name].rangeQuery,241 "added": [this.entity],242 "removed": []243 });244 }245 238 } 246 239 }; 247 240 248 241 Auras.prototype.GiveMembersWithValidClass = function(auraName, entityList) 249 242 { … … Auras.prototype.OnGarrisonedUnitsChanged 272 265 this.ApplyBonus(name, msg.added); 273 266 this.RemoveBonus(name, msg.removed); 274 267 } 275 268 }; 276 269 270 Auras.prototype.RegisterGlobalOwnershipChanged = function(msg) 271 { 272 let auraNames = this.GetAuraNames().filter(n => this.IsGlobalAura(n)); 273 for (let name of auraNames) 274 { 275 let affectedPlayers = this.GetAffectedPlayers(name); 276 let wasApplied = affectedPlayers.indexOf(msg.from) != -1; 277 let willBeApplied = affectedPlayers.indexOf(msg.to) != -1; 278 if (wasApplied && !willBeApplied) 279 this.RemoveBonus(name, [msg.entity]); 280 if (willBeApplied && !wasApplied) 281 this.ApplyBonus(name, [msg.entity]); 282 } 283 }; 284 277 285 Auras.prototype.ApplyFormationBonus = function(memberList) 278 286 { 279 287 var auraNames = this.GetAuraNames().filter(n => this.IsFormationAura(n)); 280 288 for (let name of auraNames) 281 289 this.ApplyBonus(name, memberList); … … Auras.prototype.ApplyTemplateBonus = fun 297 305 return; 298 306 var modifications = this.GetModifications(name); 299 307 var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager); 300 308 var classes = this.GetClasses(name); 301 309 310 cmpAuraManager.RegisterGlobalAuraGiver(this.entity); 311 302 312 for (let mod of modifications) 303 313 for (let player of players) 304 314 cmpAuraManager.ApplyTemplateBonus(mod.value, player, classes, mod, this.GetModifierIdentifier(name)); 305 315 }; 306 316 … … Auras.prototype.RemoveTemplateBonus = fu 323 333 if (!this[name].isApplied) 324 334 return; 325 335 if (!this.IsGlobalAura(name)) 326 336 return; 327 337 328 var modifications = this.GetModifications(name);329 338 var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager); 339 cmpAuraManager.UnregisterGlobalAuraGiver(this.entity); 340 341 var modifications = this.GetModifications(name); 330 342 var classes = this.GetClasses(name); 331 343 var players = this.GetAffectedPlayers(name); 332 344 333 345 for (let mod of modifications) 334 346 for (let player of players) -
binaries/data/mods/public/simulation/components/tests/test_Auras.js
Engine.LoadComponentScript("interfaces/A 4 4 Engine.LoadComponentScript("interfaces/AuraManager.js"); 5 5 Engine.LoadComponentScript("interfaces/TechnologyManager.js"); 6 6 Engine.LoadComponentScript("Auras.js"); 7 7 Engine.LoadComponentScript("AuraManager.js"); 8 8 9 let playerID = 1;10 let playerEnt = 10;11 let auraEnt = 20;9 let playerID = [0, 1, 2]; 10 let playerEnt = [10, 11, 12]; 11 let giverEnt = 20; 12 12 let targetEnt = 30; 13 13 let auraRange = 40; 14 14 let template = { "Identity" : { "Classes" : { "_string" : "CorrectClass OtherClass" } } }; 15 15 16 16 function testAuras(name, test_function) 17 17 { 18 18 ResetState(); 19 19 20 20 AddMock(SYSTEM_ENTITY, IID_PlayerManager, { 21 "GetPlayerByID": () => playerEnt,22 "GetNumPlayers": () => 2,21 "GetPlayerByID": idx => playerEnt[idx], 22 "GetNumPlayers": () => 3, 23 23 }); 24 24 25 25 AddMock(SYSTEM_ENTITY, IID_RangeManager, { 26 26 "CreateActiveQuery": (ent, minRange, maxRange, players, iid, flags) => 1, 27 27 "EnableActiveQuery": id => {}, 28 28 "ResetActiveQuery": id => {}, 29 29 "DisableActiveQuery": id => {}, 30 30 "DestroyActiveQuery": id => {}, 31 31 "GetEntityFlagMask": identifier => {}, 32 "GetEntitiesByPlayer": id => [30, 31, 32] 32 33 }); 33 34 34 35 AddMock(SYSTEM_ENTITY, IID_DataTemplateManager, { 35 36 "GetAuraTemplate": (name) => { 36 37 let template = { 37 38 "type": name, 39 "affectedPlayers": ["Ally"], 38 40 "affects": ["CorrectClass"], 39 41 "modifications": [{ "value": "Component/Value", "add": 10 }], 40 42 "auraName": "name", 41 43 "auraDescription": "description" 42 44 }; … … function testAuras(name, test_function) 44 46 template.radius = auraRange; 45 47 return template; 46 48 } 47 49 }); 48 50 49 AddMock(playerEnt , IID_Player, {51 AddMock(playerEnt[1], IID_Player, { 50 52 "IsAlly": id => id == 1, 51 53 "IsEnemy": id => id != 1, 52 "GetPlayerID": () => 1,54 "GetPlayerID": () => playerID[1], 53 55 }); 54 56 55 57 AddMock(targetEnt, IID_Identity, { 56 58 "GetClassesList": () => ["CorrectClass", "OtherClass"], 57 59 }); 58 60 59 AddMock( auraEnt, IID_Position, {60 "GetPosition2D": () => new Vector2D() ,61 AddMock(giverEnt, IID_Position, { 62 "GetPosition2D": () => new Vector2D() 61 63 }); 62 64 63 65 AddMock(targetEnt, IID_Position, { 64 "GetPosition2D": () => new Vector2D() ,66 "GetPosition2D": () => new Vector2D() 65 67 }); 66 68 67 AddMock(auraEnt, IID_Ownership, { 68 "GetOwner": () => 1, 69 if (playerEnt.indexOf(giverEnt) == -1) 70 { 71 AddMock(giverEnt, IID_Ownership, { 72 "GetOwner": () => playerID[1] 73 }); 74 } 75 76 AddMock(targetEnt, IID_Ownership, { 77 "GetOwner": () => playerID[1] 69 78 }); 70 79 71 80 ConstructComponent(SYSTEM_ENTITY, "AuraManager", {}); 72 let cmpAuras = ConstructComponent( auraEnt, "Auras", { "_string": name });81 let cmpAuras = ConstructComponent(giverEnt, "Auras", { "_string": name }); 73 82 test_function(name, cmpAuras); 74 83 } 75 84 76 85 testAuras("global", (name, cmpAuras) => { 77 cmpAuras.OnRangeUpdate({ "tag": 1, "added": [targetEnt], "removed": [] }); 78 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11); 79 TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 1, playerID, template), 11); 86 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15); 87 TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 5, playerID[1], template), 15); 88 }); 89 90 giverEnt = 11; 91 testAuras("global", (name, cmpAuras) => { 92 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15); 93 TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 5, playerID[1], template), 15); 80 94 }); 81 95 96 // Test the case when the aura giver is a player entity. 97 giverEnt = 20; 82 98 testAuras("range", (name, cmpAuras) => { 83 99 cmpAuras.OnRangeUpdate({ "tag": 1, "added": [targetEnt], "removed": [] }); 84 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);85 TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 1, playerID, template), 1);100 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15); 101 TS_ASSERT_EQUALS(ApplyValueModificationsToTemplate("Component/Value", 5, playerID[1], template), 5); 86 102 cmpAuras.OnRangeUpdate({ "tag": 1, "added": [], "removed": [targetEnt] }); 87 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1);103 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 5); 88 104 }); 89 105 90 106 testAuras("garrisonedUnits", (name, cmpAuras) => { 91 107 cmpAuras.OnGarrisonedUnitsChanged({ "added" : [targetEnt], "removed": [] }); 92 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);108 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15); 93 109 cmpAuras.OnGarrisonedUnitsChanged({ "added" : [], "removed": [targetEnt] }); 94 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1);110 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 5); 95 111 }); 96 112 97 113 testAuras("garrison", (name, cmpAuras) => { 98 114 TS_ASSERT_EQUALS(cmpAuras.HasGarrisonAura(), true); 99 115 cmpAuras.ApplyGarrisonBonus(targetEnt); 100 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);116 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15); 101 117 cmpAuras.RemoveGarrisonBonus(targetEnt); 102 118 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1); 103 119 }); 104 120 105 121 testAuras("formation", (name, cmpAuras) => { 106 122 TS_ASSERT_EQUALS(cmpAuras.HasFormationAura(), true); 107 123 cmpAuras.ApplyFormationBonus([targetEnt]); 108 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 11);124 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 15); 109 125 cmpAuras.RemoveFormationBonus([targetEnt]); 110 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 1, targetEnt), 1);126 TS_ASSERT_EQUALS(ApplyValueModificationsToEntity("Component/Value", 5, targetEnt), 5); 111 127 }); -
binaries/data/mods/public/simulation/data/auras/maur_hero_ashoka.json
5 5 { "value": "ProductionQueue/TechCostMultiplier/wood", "multiply": 0.5 }, 6 6 { "value": "ProductionQueue/TechCostMultiplier/food", "multiply": 0.5 }, 7 7 { "value": "ProductionQueue/TechCostMultiplier/metal", "multiply": 0.5 }, 8 8 { "value": "ProductionQueue/TechCostMultiplier/stone", "multiply": 0.5 }, 9 9 { "value": "ProductionQueue/TechCostMultiplier/time", "multiply": 0.5 } 10 { "value": "Cost/BuildTime", "multiply": 0.5 }, 11 { "value": "Cost/Resources/stone", "multiply": 0.5 }, 12 { "value": "Cost/Resources/wood", "multiply": 0.5 } 10 13 ], 11 "auraDescription": " All player temple technologies -50% cost and -50% researchtime.",14 "auraDescription": "Temples and temple technologies -50% cost, in resources and time.", 12 15 "auraName": "Buddhism Aura", 13 16 "overlayIcon": "art/textures/ui/session/auras/build_bonus.png" 14 17 } -
binaries/data/mods/public/simulation/data/auras/teambonuses/maur_player_teambonus.json
1 { 2 "type": "global", 3 "affects": ["Temple"], 4 "affectedPlayers": ["ExclusiveMutualAlly"], 5 "modifications": [ 6 { "value": "ProductionQueue/TechCostMultiplier/wood", "multiply": 0.5 }, 7 { "value": "ProductionQueue/TechCostMultiplier/food", "multiply": 0.5 }, 8 { "value": "ProductionQueue/TechCostMultiplier/metal", "multiply": 0.5 }, 9 { "value": "ProductionQueue/TechCostMultiplier/stone", "multiply": 0.5 }, 10 { "value": "ProductionQueue/TechCostMultiplier/time", "multiply": 0.5 }, 11 { "value": "Cost/BuildTime", "multiply": 0.5 }, 12 { "value": "Cost/Resources/stone", "multiply": 0.5 }, 13 { "value": "Cost/Resources/wood", "multiply": 0.5 } 14 ], 15 "auraName": "Ashoka's Religious Support", 16 "auraDescription": "Allied temples and temple technologies -50% cost, in resources and time." 17 } -
binaries/data/mods/public/simulation/templates/special/player_maur.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <Entity parent="special/player"> 3 <Auras datatype="tokens">teambonuses/maur_player_teambonus</Auras> 4 </Entity>