Ticket #1724: collectiveBehavior-v3.patch
File collectiveBehavior-v3.patch, 14.6 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/simulation/templates/gaia/fauna_elephant.xml
11 11 <Identity> 12 12 <Civ>gaia</Civ> 13 13 <Classes datatype="tokens">Elephant</Classes> 14 <Species>Elephant</Species> 14 15 <SpecificName>Elephant</SpecificName> 15 16 <Icon>gaia/fauna_elephant.png</Icon> 16 17 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_lion.xml
15 15 </Footprint> 16 16 <Identity> 17 17 <Civ>gaia</Civ> 18 <Species>Panthera leo</Species> 18 19 <SpecificName>Lion</SpecificName> 19 20 <Icon>gaia/fauna_lion.png</Icon> 20 21 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_wolf_snow.xml
15 15 </Footprint> 16 16 <Identity> 17 17 <Civ>gaia</Civ> 18 <Species>Canis lupus</Species> 18 19 <SpecificName>Snow Wolf</SpecificName> 19 20 <Icon>gaia/fauna_wolf_snow.png</Icon> 20 21 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_african_bush.xml
44 44 <Identity> 45 45 <Civ>gaia</Civ> 46 46 <Classes datatype="tokens">Elephant</Classes> 47 <Species>Elephant</Species> 47 48 <SpecificName>African Bush Elephant</SpecificName> 48 49 <Icon>gaia/fauna_elephant_african_bush.png</Icon> 49 50 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_wolf.xml
15 15 </Footprint> 16 16 <Identity> 17 17 <Civ>gaia</Civ> 18 <Species>Canis lupus</Species> 18 19 <SpecificName>Wolf</SpecificName> 19 20 <Icon>gaia/fauna_wolf.png</Icon> 20 21 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_north_african.xml
31 31 <Identity> 32 32 <Civ>gaia</Civ> 33 33 <Classes datatype="tokens">Elephant</Classes> 34 <Species>Elephant</Species> 34 35 <SpecificName>North African Elephant</SpecificName> 35 36 <Icon>gaia/fauna_elephant_north_african.png</Icon> 36 37 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_lioness.xml
15 15 </Footprint> 16 16 <Identity> 17 17 <Civ>gaia</Civ> 18 <Species>Panthera leo</Species> 18 19 <SpecificName>Lion</SpecificName> 19 20 <Icon>gaia/fauna_lion.png</Icon> 20 21 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_asian.xml
44 44 <Identity> 45 45 <Civ>gaia</Civ> 46 46 <Classes datatype="tokens">Elephant</Classes> 47 <Species>Elephant</Species> 47 48 <SpecificName>Asian Elephant</SpecificName> 48 49 <Icon>gaia/fauna_elephant_african_bush.png</Icon> 49 50 </Identity> -
binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_african_infant.xml
12 12 <Identity> 13 13 <Civ>gaia</Civ> 14 14 <Classes datatype="tokens">Elephant</Classes> 15 <Species>Elephant</Species> 15 16 <SpecificName>African Elephant (Infant)</SpecificName> 16 17 <Icon>gaia/fauna_elephant_african_infant.png</Icon> 17 18 </Identity> -
binaries/data/mods/public/simulation/components/UnitAI.js
1 //range of influence for flee 2 const fleeInfluence = 28; // TODO find best value 3 1 4 function UnitAI() {} 2 5 3 6 UnitAI.prototype.Schema = … … 306 309 }, 307 310 308 311 "Order.Flee": function(msg) { 309 // We use the distance between the enities to account for ranged attacks 310 var distance = DistanceBetweenEntities(this.entity, this.order.data.target) + (+this.template.FleeDistance); 311 var ok = this.MoveToTargetRangeExplicit(this.order.data.target, distance, -1); 312 var ok = this.PerformFlee(this.order.data); 312 313 if (ok) 313 314 { 314 315 // We've started fleeing from the given target … … 318 319 this.SetNextState("INDIVIDUAL.FLEEING"); 319 320 } 320 321 else 321 {322 // We are already at the target, or can't move at all323 this.StopMoving();324 322 this.FinishOrder(); 325 }326 323 }, 327 324 328 325 "Order.Attack": function(msg) { … … 1218 1215 // Return to our original position 1219 1216 if (this.GetStance().respondHoldGround) 1220 1217 this.WalkToHeldPosition(); 1218 // If wild animal, roam in case we are far from our territory 1219 else if (this.territory) 1220 this.SetNextState("ROAMING"); 1221 1221 } 1222 1222 }, 1223 1223 … … 1397 1397 // Return to our original position 1398 1398 if (this.GetStance().respondHoldGround) 1399 1399 this.WalkToHeldPosition(); 1400 // If wild animal, roam in case we are far from our territory 1401 else if (this.territory) 1402 this.SetNextState("ROAMING"); 1400 1403 } 1401 1404 }, 1402 1405 … … 2127 2130 this.template.NaturalBehaviour == "passive") 2128 2131 { 2129 2132 this.Flee(msg.data.attacker, false); 2133 this.NearbyAnimalsRespondToAttack(msg.data.attacker); 2130 2134 } 2131 2135 else if (this.IsDangerousAnimal() || this.template.NaturalBehaviour == "defensive") 2132 2136 { 2133 2137 if (this.CanAttack(msg.data.attacker)) 2134 2138 this.Attack(msg.data.attacker, false); 2139 this.NearbyAnimalsRespondToAttack(msg.data.attacker); 2135 2140 } 2136 2141 else if (this.template.NaturalBehaviour == "domestic") 2137 2142 { … … 2210 2215 2211 2216 "leave": function() { 2212 2217 this.StopTimer(); 2218 // If not yet done, setup territory (initialize here as animals start in feeding state) 2219 this.SetUpTerritory(); 2213 2220 }, 2214 2221 2215 2222 "LosRangeUpdate": function(msg) { … … 3271 3278 3272 3279 if (this.GetStance().respondFlee) 3273 3280 { 3274 this.PushOrderFront("Flee", { " target": ents[0], "force": false });3281 this.PushOrderFront("Flee", { "attacker": ents[0], "target": undefined, "force": false }); 3275 3282 return true; 3276 3283 } 3277 3284 … … 3750 3757 /** 3751 3758 * Adds flee order to the queue, not forced, so it can be 3752 3759 * interrupted by attacks. 3760 * (target is undefined when the unit is the target of the attack) 3753 3761 */ 3754 UnitAI.prototype.Flee = function( target, queued)3762 UnitAI.prototype.Flee = function(attacker, queued, target) 3755 3763 { 3756 this.AddOrder("Flee", { " target": target, "force": false }, queued);3764 this.AddOrder("Flee", { "attacker": attacker, "target": target, "force": false }, queued); 3757 3765 }; 3758 3766 3759 3767 /** 3768 * Internal function to abstract the details of the runaway 3769 * data.attacker is the attacker 3770 * data.target is the real target of the attack when it is not the unit itself, otherwise undefined 3771 */ 3772 UnitAI.prototype.PerformFlee = function(data) 3773 { 3774 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 3775 if (!cmpPosition || !cmpPosition.IsInWorld()) 3776 return false; 3777 var cmpAttackerPosition = Engine.QueryInterface(data.attacker, IID_Position); 3778 if (!cmpAttackerPosition || !cmpAttackerPosition.IsInWorld()) 3779 return false; 3780 3781 var pos = cmpPosition.GetPosition(); 3782 var posAttacker = cmpAttackerPosition.GetPosition(); 3783 var dx = posAttacker.x - pos.x; 3784 var dz = posAttacker.z - pos.z; 3785 var fleeDistance = (+this.template.FleeDistance); 3786 // allow for a small random flee direction : 3787 // take a distribution flat in sin between about -pi/4 and pi/4 3788 // and approximate cos by 1-sin*sin/2 for these small angles 3789 var sinmin = -0.7; 3790 var sinmax = 0.7; 3791 var sina = sinmin + (sinmax-sinmin)*Math.random(); 3792 var cosa = 1 - sina*sina/2; 3793 if (data.target) 3794 { 3795 // if the unit is not the target of the attack, it will escape preferentially on the left 3796 // or on the right depending on its position with respect to the target, 3797 // and its fleeDistance will be reduced. 3798 var cmpTargetPosition = Engine.QueryInterface(data.target, IID_Position); 3799 if (cmpTargetPosition && cmpTargetPosition.IsInWorld()) 3800 { 3801 var posTarget = cmpTargetPosition.GetPosition(); 3802 var ex = posAttacker.x - posTarget.x; 3803 var ez = posAttacker.z - posTarget.z; 3804 var crossprod = ex*dz - ez*dx; 3805 var cosn = cosa; 3806 if (crossprod > 0) 3807 { 3808 cosa = 0.866*cosn - 0.500*sina; 3809 sina = 0.866*sina + 0.500*cosn; 3810 } 3811 else 3812 { 3813 cosa = 0.866*cosn + 0.500*sina; 3814 sina = 0.866*sina - 0.500*cosn; 3815 } 3816 // Decrease the fleeDistance according to the distance between the unit and the target 3817 ex = posTarget.x - pos.x; 3818 ez = posTarget.z - pos.z; 3819 fleeDistance *= (1 - Math.min(1, (ex*ex+ez*ez)/(fleeInfluence*fleeInfluence))); 3820 } 3821 } 3822 var tx = cosa*dx - sina*dz + pos.x; 3823 var tz = sina*dx + cosa*dz + pos.z; 3824 // We add the distance between the unit and the attacker to account for ranged attacks 3825 var distance = fleeDistance + Math.sqrt(dx*dx + dz*dz); 3826 var ok = this.MoveToPointRange(tx, tz, distance, -1); 3827 if (!ok) this.StopMoving(); 3828 return ok; 3829 }; 3830 3831 /** 3760 3832 * Adds cheer order to the queue. Forced so it won't be interrupted by attacks. 3761 3833 */ 3762 3834 UnitAI.prototype.Cheer = function() … … 4180 4252 4181 4253 UnitAI.prototype.MoveRandomly = function(distance) 4182 4254 { 4183 // We want to walk in a random direction, but avoid getting stuck 4255 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 4256 if (!cmpPosition || !cmpPosition.IsInWorld()) 4257 return; 4258 var pos = cmpPosition.GetPosition(); 4259 4260 // If we are far away from our starting position, we try to move closer 4261 // with a probability increasing with the distance 4262 if (this.territory) 4263 { 4264 var dx = this.territory.x - pos.x; 4265 var dz = this.territory.z - pos.z; 4266 var dist = Math.sqrt(dx*dx + dz*dz); 4267 var proba = RandomInt(0, 100); 4268 if (20*dist/distance > Math.max(proba,30)) 4269 { 4270 dist -= distance; 4271 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 4272 if (!cmpMotion.MoveToPointRange(this.territory.x, this.territory.z, dist, dist)) 4273 this.territory = pos; 4274 return; 4275 } 4276 } 4277 4278 // Otherwise we want to walk in a random direction, but avoid getting stuck 4184 4279 // in obstacles or narrow spaces. 4185 4280 // So pick a circular range from approximately our current position, 4186 4281 // and move outwards to the nearest point on that circle, which will 4187 4282 // lead to us avoiding obstacles and moving towards free space. 4188 4283 4189 // TODO: we probably ought to have a 'home' point, and drift towards4190 // that, so we don't spread out all across the whole map4191 4192 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);4193 if (!cmpPosition)4194 return;4195 4196 if (!cmpPosition.IsInWorld())4197 return;4198 4199 var pos = cmpPosition.GetPosition();4200 4201 4284 var jitter = 0.5; 4202 4285 4203 4286 // Randomly adjust the range's center a bit, so we tend to prefer … … 4238 4321 ); 4239 4322 }; 4240 4323 4324 UnitAI.prototype.SetUpTerritory = function() 4325 { 4326 if (!this.IsAnimal() || this.IsDomestic()) 4327 return; 4328 if (this.territory) 4329 return; 4330 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 4331 if (cmpPosition && cmpPosition.IsInWorld()) 4332 this.territory = cmpPosition.GetPosition(); 4333 }; 4334 4335 /** 4336 * All wild animals in a given distance respond to the attack : 4337 * If skittish behaviour, they flee 4338 * If defensive behaviour, they attack if it is a member of their species which is involved 4339 */ 4340 UnitAI.prototype.NearbyAnimalsRespondToAttack = function(attacker) 4341 { 4342 var cmpOwnIdentity = Engine.QueryInterface(this.entity, IID_Identity); 4343 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 4344 // Get other animals ; range = fleeInfluence, players = [0] (gaia only) 4345 var nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, fleeInfluence, [0], IID_UnitAI); 4346 for each (var ent in nearby) 4347 { 4348 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 4349 if (cmpUnitAI.template.NaturalBehaviour == "skittish" || 4350 cmpUnitAI.template.NaturalBehaviour == "passive") 4351 { 4352 cmpUnitAI.Flee(attacker, false, this.entity); 4353 } 4354 else if (cmpOwnIdentity && cmpOwnIdentity.template.Species && 4355 (cmpUnitAI.IsDangerousAnimal() || cmpUnitAI.template.NaturalBehaviour == "defensive")) 4356 { 4357 var cmpIdentity = Engine.QueryInterface(ent, IID_Identity); 4358 if (cmpIdentity && cmpIdentity.template.Species && 4359 cmpIdentity.template.Species == cmpOwnIdentity.template.Species) 4360 { 4361 if(cmpUnitAI.CanAttack(attacker)) 4362 cmpUnitAI.Attack(attacker, false); 4363 } 4364 } 4365 } 4366 }; 4367 4241 4368 Engine.RegisterComponentType(IID_UnitAI, "UnitAI", UnitAI); -
binaries/data/mods/public/simulation/components/Identity.js
15 15 "<text/>" + 16 16 "</element>" + 17 17 "<optional>" + 18 "<element name='Species' a:help='Species this unit belongs to'>" + 19 "<text/>" + 20 "</element>" + 21 "</optional>" + 22 "<optional>" + 18 23 "<element name='SpecificName' a:help='Specific native-language name for this unit type'>" + 19 24 "<text/>" + 20 25 "</element>" +