Ticket #2010: buildingAI.diff
File buildingAI.diff, 18.6 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/simulation/components/BuildingAI.js
1 1 //Number of rounds of firing per 2 seconds 2 2 const roundCount = 10; 3 3 const timerInterval = 2000 / roundCount; 4 const attackType = "Ranged"; 4 5 5 6 function BuildingAI() {} 6 7 … … 10 11 "</element>" + 11 12 "<element name='GarrisonArrowMultiplier'>" + 12 13 "<ref name='nonNegativeDecimal'/>" + 14 "</element>" + 15 "<element name='GarrisonArrowClasses'>" + 16 "<attribute name='datatype'>" + 17 "<value>tokens</value>" + 18 "</attribute>" + 19 "<text/>" + 13 20 "</element>"; 14 21 15 22 /** … … 19 26 { 20 27 if (this.GetDefaultArrowCount() > 0 || this.GetGarrisonArrowMultiplier() > 0) 21 28 { 22 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);23 29 this.currentRound = 0; 24 30 //Arrows left to fire 25 31 this.arrowsLeft = 0; 26 this.timer = cmpTimer.SetTimeout(this.entity, IID_BuildingAI, "FireArrows", timerInterval, {});27 32 this.targetUnits = []; 28 33 } 29 34 }; … … 96 101 players.push(i); 97 102 } 98 103 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 99 if ( cmpAttack)100 {101 var range = cmpAttack.GetRange("Ranged");102 this.enemyUnitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));103 cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);104 }104 if (!cmpAttack) 105 return; 106 107 var range = cmpAttack.GetRange(attackType); 108 this.enemyUnitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal")); 109 cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery); 105 110 }; 106 111 107 112 // Set up a range query for Gaia units within LOS range which can be attacked. … … 111 116 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 112 117 var owner = cmpOwnership.GetOwner(); 113 118 114 var rangeMan= Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);119 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 115 120 var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 116 121 117 122 if (this.gaiaUnitsQuery) 118 123 { 119 rangeMan.DestroyActiveQuery(this.gaiaUnitsQuery);124 cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery); 120 125 this.gaiaUnitsQuery = undefined; 121 126 } 122 127 … … 128 133 return; 129 134 130 135 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 131 if (cmpAttack) 132 { 133 var range = cmpAttack.GetRange("Ranged"); 136 if (!cmpAttack) 137 return; 138 139 var range = cmpAttack.GetRange(attackType); 134 140 135 // This query is only interested in Gaia entities that can attack. 136 this.gaiaUnitsQuery = rangeMan.CreateActiveQuery(this.entity, range.min, range.max, [0], IID_Attack, rangeMan.GetEntityFlagMask("normal")); 137 rangeMan.EnableActiveQuery(this.gaiaUnitsQuery); 138 } 141 // This query is only interested in Gaia entities that can attack. 142 this.gaiaUnitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal")); 143 cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery); 139 144 }; 140 145 141 146 /** … … 143 148 */ 144 149 BuildingAI.prototype.OnRangeUpdate = function(msg) 145 150 { 151 152 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 153 if (!cmpAttack) 154 return; 155 146 156 if (msg.tag == this.gaiaUnitsQuery) 147 157 { 148 158 const filter = function(e) { … … 161 171 else if (msg.tag != this.enemyUnitsQuery) 162 172 return; 163 173 174 const restrictedClasses = cmpAttack.GetRestrictedClasses(attackType); 175 164 176 if (msg.added.length > 0) 165 177 { 166 178 for each (var entity in msg.added) 167 179 { 168 this.targetUnits.push(entity); 180 var cmpIdentity = Engine.QueryInterface(entity, IID_Identity); 181 var targetClasses = cmpIdentity.GetClassesList(); 182 183 if (!targetClasses.some(function(c){return restrictedClasses.indexOf(c) > -1;})) 184 this.targetUnits.push(entity); 169 185 } 170 186 } 171 187 if (msg.removed.length > 0) 172 188 { 173 189 for each (var entity in msg.removed) 174 { 175 this.targetUnits.splice(this.targetUnits.indexOf(entity), 1); 190 { 191 var index = this.targetUnits.indexOf(entity); 192 if (index > -1) 193 this.targetUnits.splice(index, 1); 176 194 } 177 195 } 196 197 if (!this.targetUnits.length || this.timer) 198 return; 199 // units entered the range, prepare to shoot 200 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 201 var attackTimers = cmpAttack.GetTimers(attackType); 202 this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows", attackTimers.prepare, attackTimers.repeat / roundCount, {}); 203 178 204 }; 179 205 180 206 BuildingAI.prototype.GetDefaultArrowCount = function() … … 189 215 return ApplyTechModificationsToEntity("BuildingAI/GarrisonArrowMultiplier", arrowMult, this.entity); 190 216 }; 191 217 218 BuildingAI.prototype.GetGarrisonArrowClasses = function() 219 { 220 var string = this.template.GarrisonArrowClasses._string || ""; 221 return string.split(/\s+/); 222 }; 223 192 224 /** 193 225 * Returns the number of arrows which needs to be fired. 194 226 * DefaultArrowCount + Garrisoned Archers(ie., any unit capable … … 200 232 var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); 201 233 if (cmpGarrisonHolder) 202 234 { 203 count += Math.round(cmpGarrisonHolder.GetGarrisonedArcherCount( ) * this.GetGarrisonArrowMultiplier());235 count += Math.round(cmpGarrisonHolder.GetGarrisonedArcherCount(this.GetGarrisonArrowClasses()) * this.GetGarrisonArrowMultiplier()); 204 236 } 205 237 return count; 206 238 }; 207 239 208 240 /** 209 * Fires arrows. Called every N times every 2 seconds 210 * where N is the number of Arrows 241 * Fires arrows. Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range 211 242 */ 212 243 BuildingAI.prototype.FireArrows = function() 213 244 { 245 246 if (!this.targetUnits.length && this.timer) 247 { 248 // stop the timer 249 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 250 cmpTimer.CancelTimer(this.timer); 251 this.timer = undefined; 252 return; 253 } 254 214 255 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 215 if (cmpAttack) 256 if (!cmpAttack) 257 return; 258 259 var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 260 if (cmpUnitAI) 216 261 { 217 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 218 this.timer = cmpTimer.SetTimeout(this.entity, IID_BuildingAI, "FireArrows", timerInterval, {}); 219 var arrowsToFire = 0; 220 if (this.currentRound > (roundCount - 1)) 221 { 222 //Reached end of rounds. Reset count 223 this.currentRound = 0; 224 } 225 226 if (this.currentRound == 0) 227 { 228 //First round. Calculate arrows to fire 229 this.arrowsLeft = this.GetArrowCount(); 230 } 231 232 if (this.currentRound == (roundCount - 1)) 233 { 234 //Last round. Need to fire all left-over arrows 235 arrowsToFire = this.arrowsLeft; 236 } 262 var orders = cmpUnitAI.GetOrders(); 263 if (orders.length && orders[0].type == 'Attack' && orders[0].data.force) 264 // user is forcing this entity to attack a certian target 265 var forcedTarget = +orders[0].data.target; 266 } 267 268 var arrowsToFire = 0; 269 270 if (this.currentRound === 0) 271 this.arrowsLeft = this.GetArrowCount(); 272 273 if (this.currentRound === (roundCount - 1)) 274 { 275 //Last round. Need to fire all left-over arrows 276 arrowsToFire = this.arrowsLeft; 277 } 278 else 279 { 280 //Fire N arrows, 0 <= N <= Number of arrows left 281 arrowsToFire = Math.min( 282 Math.round(2*Math.random() * this.GetArrowCount()/roundCount), 283 this.arrowsLeft 284 ); 285 } 286 287 for (var i = 0; i < arrowsToFire; ++i) 288 { 289 var target; 290 if (forcedTarget && this.targetUnits.indexOf(forcedTarget) > -1) 291 // user forced to attack a certain one, and we're able to attack the target 292 target = forcedTarget; 237 293 else 238 { 239 //Fire N arrows, 0 <= N <= Number of arrows left 240 arrowsToFire = Math.floor(Math.random() * this.arrowsLeft); 241 } 242 if (this.targetUnits.length > 0) 243 { 244 for (var i = 0;i < arrowsToFire;i++) 245 { 246 cmpAttack.PerformAttack("Ranged", this.targetUnits[Math.floor(Math.random() * this.targetUnits.length)]); 247 PlaySound("arrowfly", this.entity); 248 } 249 this.arrowsLeft -= arrowsToFire; 250 } 251 this.currentRound++; 294 target = this.targetUnits[Math.floor(Math.random() * this.targetUnits.length)]; 295 296 cmpAttack.PerformAttack(attackType, target); 297 // TODO use Sound.js sounds 298 PlaySound("arrowfly", this.entity); 252 299 } 300 this.arrowsLeft -= arrowsToFire; 301 302 this.currentRound = ++this.currentRound % roundCount; 303 253 304 }; 254 305 255 306 Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI); -
binaries/data/mods/public/simulation/components/GarrisonHolder.js
78 78 * Get number of garrisoned units capable of shooting arrows 79 79 * Not necessarily archers 80 80 */ 81 GarrisonHolder.prototype.GetGarrisonedArcherCount = function( )81 GarrisonHolder.prototype.GetGarrisonedArcherCount = function(garrisonArrowClasses) 82 82 { 83 83 var count = 0; 84 84 for each (var entity in this.entities) … … 85 85 { 86 86 var cmpIdentity = Engine.QueryInterface(entity, IID_Identity); 87 87 var classes = cmpIdentity.GetClassesList(); 88 if (classes. indexOf("Infantry") != -1 || classes.indexOf("Ranged") != -1)88 if (classes.some(function(c){return garrisonArrowClasses.indexOf(c) > -1;})) 89 89 count++; 90 90 } 91 91 return count; -
binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml
3 3 <BuildingAI> 4 4 <DefaultArrowCount>3</DefaultArrowCount> 5 5 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 6 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 6 7 </BuildingAI> 7 8 <BuildRestrictions> 8 9 <Territory>own ally neutral</Territory> -
binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml
23 23 <Spread>1.5</Spread> 24 24 </Ranged> 25 25 </Attack> 26 <BuildingAI> 27 <DefaultArrowCount>3</DefaultArrowCount> 28 <GarrisonArrowMultiplier>0.5</GarrisonArrowMultiplier> 29 </BuildingAI> 30 <BuildRestrictions> 31 <Territory>own neutral enemy</Territory> 26 <BuildingAI> 27 <DefaultArrowCount>3</DefaultArrowCount> 28 <GarrisonArrowMultiplier>0.5</GarrisonArrowMultiplier> 29 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 30 </BuildingAI> 31 <BuildRestrictions> 32 <Territory>own neutral enemy</Territory> 32 33 <Category>Fortress</Category> 33 34 </BuildRestrictions> 34 35 <Cost> -
binaries/data/mods/public/simulation/templates/template_structure.xml
13 13 <BuildingAI> 14 14 <DefaultArrowCount>0</DefaultArrowCount> 15 15 <GarrisonArrowMultiplier>0</GarrisonArrowMultiplier> 16 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 16 17 </BuildingAI> 17 18 <BuildRestrictions> 18 19 <PlacementType>land</PlacementType> -
binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml
10 10 <ProjectileSpeed>75.0</ProjectileSpeed> 11 11 <PrepareTime>1200</PrepareTime> 12 12 <RepeatTime>2000</RepeatTime> 13 <RestrictedClasses datatype="tokens">Structure</RestrictedClasses> 13 14 <Spread>1.5</Spread> 14 15 </Ranged> 15 16 </Attack> 16 <BuildingAI> 17 <DefaultArrowCount>1</DefaultArrowCount> 18 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 19 </BuildingAI> 20 <BuildRestrictions> 21 <Category>DefenseTower</Category> 17 <BuildingAI> 18 <DefaultArrowCount>1</DefaultArrowCount> 19 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 20 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 21 </BuildingAI> 22 <BuildRestrictions> 23 <Category>DefenseTower</Category> 22 24 </BuildRestrictions> 23 25 <Cost> 24 26 <BuildTime>120</BuildTime> -
binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml
20 20 <ProjectileSpeed>75.0</ProjectileSpeed> 21 21 <PrepareTime>1200</PrepareTime> 22 22 <RepeatTime>2000</RepeatTime> 23 <RestrictedClasses datatype="tokens">Structure</RestrictedClasses> 23 24 <Spread>2.0</Spread> 24 25 </Ranged> 25 26 </Attack> 26 27 <BuildingAI> 27 28 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 29 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 28 30 </BuildingAI> 29 31 <BuildRestrictions> 30 32 <Territory>own neutral</Territory> -
binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml
10 10 <ProjectileSpeed>75.0</ProjectileSpeed> 11 11 <PrepareTime>1200</PrepareTime> 12 12 <RepeatTime>2000</RepeatTime> 13 <RestrictedClasses datatype="tokens">Structure</RestrictedClasses> 13 14 <Spread>1.5</Spread> 14 15 </Ranged> 15 16 </Attack> … … 16 17 <BuildingAI> 17 18 <DefaultArrowCount>3</DefaultArrowCount> 18 19 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 20 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 19 21 </BuildingAI> 20 22 <BuildRestrictions> 21 23 <Category>Fortress</Category> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml
16 16 <BuildingAI> 17 17 <DefaultArrowCount>2</DefaultArrowCount> 18 18 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 19 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 19 20 </BuildingAI> 20 21 <Cost> 21 22 <Population>2</Population> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml
2 2 <Entity parent="template_unit_mechanical_ship"> 3 3 <Attack> 4 4 <Ranged> 5 <Hack> 0.0</Hack>6 <Pierce> 40.0</Pierce>7 <Crush> 100.0</Crush>5 <Hack>30.0</Hack> 6 <Pierce>10.0</Pierce> 7 <Crush>30.0</Crush> 8 8 <MaxRange>65.0</MaxRange> 9 9 <MinRange>20.0</MinRange> 10 10 <ProjectileSpeed>40.0</ProjectileSpeed> 11 <PrepareTime> 2000</PrepareTime>11 <PrepareTime>5000</PrepareTime> 12 12 <RepeatTime>4000</RepeatTime> 13 13 <Spread>1.5</Spread> 14 14 </Ranged> … … 21 21 <metal>200</metal> 22 22 </Resources> 23 23 </Cost> 24 <BuildingAI> 25 <DefaultArrowCount>0</DefaultArrowCount> 26 <GarrisonArrowMultiplier>0.5</GarrisonArrowMultiplier> 27 <GarrisonArrowClasses datatype="tokens">Ballista</GarrisonArrowClasses> 28 </BuildingAI> 24 29 <Footprint> 25 30 <Square width="12.0" depth="48.0"/> 26 31 <Height>8.0</Height> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml
16 16 <BuildingAI> 17 17 <DefaultArrowCount>3</DefaultArrowCount> 18 18 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 19 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 19 20 </BuildingAI> 20 21 <Cost> 21 22 <Population>3</Population> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_onager.xml
53 53 <Identity> 54 54 <GenericName>Siege Catapult</GenericName> 55 55 <Tooltip>Bonused vs. Structures and Massed Infantry.</Tooltip> 56 <Classes datatype="tokens">Ballista</Classes> 56 57 </Identity> 57 58 <Loot> 58 59 <xp>300</xp> -
binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_tower.xml
15 15 <ProjectileSpeed>75.0</ProjectileSpeed> 16 16 <PrepareTime>1200</PrepareTime> 17 17 <RepeatTime>2000</RepeatTime> 18 <RestrictedClasses datatype="tokens">Structure</RestrictedClasses> 18 19 <Spread>1.5</Spread> 19 20 </Ranged> 20 21 </Attack> … … 21 22 <BuildingAI> 22 23 <DefaultArrowCount>1</DefaultArrowCount> 23 24 <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier> 25 <GarrisonArrowClasses datatype="tokens">Infanty Ranged</GarrisonArrowClasses> 24 26 </BuildingAI> 25 27 <Cost> 26 28 <Population>5</Population>