Ticket #1724: collectiveBehavior-v4.diff

File collectiveBehavior-v4.diff, 14.6 KB (added by mimo, 11 years ago)

basically the same as previous patch, but some cleanings added

  • binaries/data/mods/public/simulation/templates/gaia/fauna_wolf.xml

     
    1515  </Footprint>
    1616  <Identity>
    1717    <Civ>gaia</Civ>
     18    <Species>Canis lupus</Species>
    1819    <SpecificName>Wolf</SpecificName>
    1920    <Icon>gaia/fauna_wolf.png</Icon>
    2021  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_asian.xml

     
    4444  <Identity>
    4545    <Civ>gaia</Civ>
    4646    <Classes datatype="tokens">Elephant</Classes>
     47    <Species>Elephant</Species>
    4748    <SpecificName>Asian Elephant</SpecificName>
    4849    <Icon>gaia/fauna_elephant_african_bush.png</Icon>
    4950  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_african_infant.xml

     
    1212  <Identity>
    1313    <Civ>gaia</Civ>
    1414    <Classes datatype="tokens">Elephant</Classes>
     15    <Species>Elephant</Species>
    1516    <SpecificName>African Elephant (Infant)</SpecificName>
    1617    <Icon>gaia/fauna_elephant_african_infant.png</Icon>
    1718  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_elephant.xml

     
    1111  <Identity>
    1212    <Civ>gaia</Civ>
    1313    <Classes datatype="tokens">Elephant</Classes>
     14    <Species>Elephant</Species>
    1415    <SpecificName>Elephant</SpecificName>
    1516    <Icon>gaia/fauna_elephant.png</Icon>
    1617  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_wolf_snow.xml

     
    1515  </Footprint>
    1616  <Identity>
    1717    <Civ>gaia</Civ>
     18    <Species>Canis lupus</Species>
    1819    <SpecificName>Snow Wolf</SpecificName>
    1920    <Icon>gaia/fauna_wolf_snow.png</Icon>
    2021  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_lion.xml

     
    1515  </Footprint>
    1616  <Identity>
    1717    <Civ>gaia</Civ>
     18    <Species>Panthera leo</Species>
    1819    <SpecificName>Lion</SpecificName>
    1920    <Icon>gaia/fauna_lion.png</Icon>
    2021  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_lioness.xml

     
    1515  </Footprint>
    1616  <Identity>
    1717    <Civ>gaia</Civ>
     18    <Species>Panthera leo</Species>
    1819    <SpecificName>Lion</SpecificName>
    1920    <Icon>gaia/fauna_lion.png</Icon>
    2021  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_north_african.xml

     
    3131  <Identity>
    3232    <Civ>gaia</Civ>
    3333    <Classes datatype="tokens">Elephant</Classes>
     34    <Species>Elephant</Species>
    3435    <SpecificName>North African Elephant</SpecificName>
    3536    <Icon>gaia/fauna_elephant_north_african.png</Icon>
    3637  </Identity>
  • binaries/data/mods/public/simulation/templates/gaia/fauna_elephant_african_bush.xml

     
    4444  <Identity>
    4545    <Civ>gaia</Civ>
    4646    <Classes datatype="tokens">Elephant</Classes>
     47    <Species>Elephant</Species>
    4748    <SpecificName>African Bush Elephant</SpecificName>
    4849    <Icon>gaia/fauna_elephant_african_bush.png</Icon>
    4950  </Identity>
  • binaries/data/mods/public/simulation/components/Identity.js

     
    1515        "<text/>" +
    1616    "</element>" +
    1717    "<optional>" +
     18        "<element name='Species' a:help='Species this unit belongs to'>" +
     19            "<text/>" +
     20        "</element>" +
     21    "</optional>" +
     22    "<optional>" +
    1823        "<element name='SpecificName' a:help='Specific native-language name for this unit type'>" +
    1924            "<text/>" +
    2025        "</element>" +
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    333333    },
    334334
    335335    "Order.Flee": function(msg) {
    336         // We use the distance between the enities to account for ranged attacks
    337         var distance = DistanceBetweenEntities(this.entity, this.order.data.target) + (+this.template.FleeDistance);
    338         var ok = this.MoveToTargetRangeExplicit(this.order.data.target, distance, -1);
     336        var ok = this.PerformFlee(this.order.data);
    339337        if (ok)
    340338        {
    341339            // We've started fleeing from the given target
     
    345343                this.SetNextState("INDIVIDUAL.FLEEING");
    346344        }
    347345        else
    348         {
    349             // We are already at the target, or can't move at all
    350             this.StopMoving();
    351346            this.FinishOrder();
    352         }
    353347    },
    354348
    355349    "Order.Attack": function(msg) {
     
    13421336                        // Return to our original position
    13431337                        if (this.GetStance().respondHoldGround)
    13441338                            this.WalkToHeldPosition();
     1339                        else if (this.IsAnimal())
     1340                            this.SetNextState("ROAMING");
    13451341                    }
    13461342                },
    13471343
     
    15261522                        // Return to our original position
    15271523                        if (this.GetStance().respondHoldGround)
    15281524                            this.WalkToHeldPosition();
     1525                        else if (this.IsAnimal())
     1526                            this.SetNextState("ROAMING");
    15291527                    }
    15301528                },
    15311529
     
    22562254                this.template.NaturalBehaviour == "passive")
    22572255            {
    22582256                this.Flee(msg.data.attacker, false);
     2257                this.NearbyAnimalsRespondToAttack(msg.data.attacker);
    22592258            }
    22602259            else if (this.IsDangerousAnimal() || this.template.NaturalBehaviour == "defensive")
    22612260            {
    22622261                if (this.CanAttack(msg.data.attacker))
    22632262                    this.Attack(msg.data.attacker, false);
     2263                this.NearbyAnimalsRespondToAttack(msg.data.attacker);
    22642264            }
    22652265            else if (this.template.NaturalBehaviour == "domestic")
    22662266            {
     
    23392339
    23402340            "leave": function() {
    23412341                this.StopTimer();
     2342                // If not yet done, setup heldPosition for wild animals
     2343                // (initialize here as animals start in feeding state)
     2344                if (!this.IsDomestic() && !this.heldPosition)
     2345                {
     2346                    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     2347                    if (cmpPosition && cmpPosition.IsInWorld())
     2348                        this.heldPosition = cmpPosition.GetPosition();
     2349                }
    23422350            },
    23432351
    23442352            "LosRangeUpdate": function(msg) {
     
    34083416
    34093417    if (this.GetStance().respondFlee)
    34103418    {
    3411         this.PushOrderFront("Flee", { "target": ents[0], "force": false });
     3419        this.PushOrderFront("Flee", { "attacker": ents[0], "target": undefined, "force": false });
    34123420        return true;
    34133421    }
    34143422
     
    38953903};
    38963904
    38973905/**
    3898  * Adds flee order to the queue, not forced, so it can be
    3899  * interrupted by attacks.
     3906 * Adds flee order to the queue, not forced, so it can be interrupted by attacks.
     3907 * (target is undefined when the unit is itself the target of the attack)
    39003908 */
    3901 UnitAI.prototype.Flee = function(target, queued)
     3909UnitAI.prototype.Flee = function(attacker, queued, target)
    39023910{
    3903     this.AddOrder("Flee", { "target": target, "force": false }, queued);
     3911    this.AddOrder("Flee", { "attacker": attacker, "target": target, "force": false }, queued);
    39043912};
    39053913
    39063914/**
     3915 * Internal function to abstract the details of the runaway
     3916 * data.attacker is the attacker
     3917 * data.target is the real target of the attack when it is not the unit itself, otherwise undefined
     3918 */
     3919UnitAI.prototype.PerformFlee = function(data)
     3920{
     3921    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     3922    if (!cmpPosition || !cmpPosition.IsInWorld())
     3923        return false;
     3924    var cmpAttackerPosition = Engine.QueryInterface(data.attacker, IID_Position);
     3925    if (!cmpAttackerPosition || !cmpAttackerPosition.IsInWorld())
     3926        return false;
     3927
     3928    var pos = cmpPosition.GetPosition();
     3929    var posAttacker = cmpAttackerPosition.GetPosition();
     3930    var dx = posAttacker.x - pos.x;
     3931    var dz = posAttacker.z - pos.z;
     3932    var fleeDistance = (+this.template.FleeDistance);
     3933    // allow for a small random flee direction :
     3934    // take a distribution flat in sin between about -pi/4 and pi/4
     3935    // and approximate cos by 1-sin*sin/2 for these small angles
     3936    var sinmin = -0.7;
     3937    var sinmax =  0.7;
     3938    var sina = sinmin + (sinmax-sinmin)*Math.random();
     3939    var cosa = 1 - sina*sina/2;
     3940    if (data.target)
     3941    {
     3942        // if the unit is not the target of the attack, it will escape preferentially on the left
     3943        // or on the right depending on its position with respect to the target,
     3944        // and its fleeDistance will be reduced.
     3945        var cmpTargetUnitAI = Engine.QueryInterface(data.target, IID_UnitAI);
     3946        var cmpTargetPosition = Engine.QueryInterface(data.target, IID_Position);
     3947        if (cmpTargetUnitAI && cmpTargetPosition && cmpTargetPosition.IsInWorld())
     3948        {
     3949            var posTarget = cmpTargetPosition.GetPosition();
     3950            var ex = posAttacker.x - posTarget.x;
     3951            var ez = posAttacker.z - posTarget.z;
     3952            var crossprod = ex*dz - ez*dx;
     3953            var cosn = cosa;
     3954            if (crossprod > 0)
     3955            {
     3956                cosa = 0.866*cosn - 0.500*sina;
     3957                sina = 0.866*sina + 0.500*cosn;
     3958            }
     3959            else
     3960            {
     3961                cosa = 0.866*cosn + 0.500*sina;
     3962                sina = 0.866*sina - 0.500*cosn;
     3963            }
     3964            // Decrease the fleeDistance according to the distance between the unit and the target
     3965            var fleeInfluence = (+cmpTargetUnitAI.template.FleeDistance);
     3966            ex = posTarget.x - pos.x;
     3967            ez = posTarget.z - pos.z;
     3968            fleeDistance *= (1 - Math.min(1, (ex*ex+ez*ez)/(fleeInfluence*fleeInfluence)));
     3969        }
     3970    }
     3971    var tx = cosa*dx - sina*dz + pos.x;
     3972    var tz = sina*dx + cosa*dz + pos.z;
     3973    // We add the distance between the unit and the attacker to account for ranged attacks
     3974        var distance = fleeDistance + Math.sqrt(dx*dx + dz*dz);
     3975        var ok = this.MoveToPointRange(tx, tz, distance, -1);
     3976        if (!ok) this.StopMoving();
     3977        return ok;
     3978};
     3979
     3980/**
    39073981 * Adds cheer order to the queue. Forced so it won't be interrupted by attacks.
    39083982 */
    39093983UnitAI.prototype.Cheer = function()
     
    43274401
    43284402UnitAI.prototype.MoveRandomly = function(distance)
    43294403{
    4330     // We want to walk in a random direction, but avoid getting stuck
     4404    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     4405    if (!cmpPosition || !cmpPosition.IsInWorld())
     4406        return;
     4407    var pos = cmpPosition.GetPosition();
     4408
     4409    // If we are far away from our starting position, we try to move closer
     4410    // with a probability increasing with the distance
     4411    if (this.heldPosition)
     4412    {
     4413        var dx = this.heldPosition.x - pos.x;
     4414        var dz = this.heldPosition.z - pos.z;
     4415        var dist = Math.sqrt(dx*dx + dz*dz);
     4416        var proba = RandomInt(0, 100);
     4417        if (20*dist/distance > Math.max(proba,30))
     4418        {
     4419            dist -= distance;
     4420            var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
     4421            if (!cmpMotion.MoveToPointRange(this.heldPosition.x, this.heldPosition.z, dist, dist))
     4422                this.heldPosition = pos;
     4423            return;
     4424        }
     4425    }
     4426
     4427    // Otherwise we want to walk in a random direction, but avoid getting stuck
    43314428    // in obstacles or narrow spaces.
    43324429    // So pick a circular range from approximately our current position,
    43334430    // and move outwards to the nearest point on that circle, which will
    43344431    // lead to us avoiding obstacles and moving towards free space.
    43354432
    4336     // TODO: we probably ought to have a 'home' point, and drift towards
    4337     // that, so we don't spread out all across the whole map
    4338 
    4339     var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    4340     if (!cmpPosition)
    4341         return;
    4342 
    4343     if (!cmpPosition.IsInWorld())
    4344         return;
    4345 
    4346     var pos = cmpPosition.GetPosition();
    4347 
    43484433    var jitter = 0.5;
    43494434
    43504435    // Randomly adjust the range's center a bit, so we tend to prefer
     
    43854470    );
    43864471};
    43874472
     4473/**
     4474 * All wild animals in a given distance respond to the attack :
     4475 * If skittish behaviour, they flee
     4476 * If defensive behaviour, they attack if it is a member of their species which is involved
     4477 */
     4478UnitAI.prototype.NearbyAnimalsRespondToAttack = function(attacker)
     4479{
     4480    var cmpOwnIdentity = Engine.QueryInterface(this.entity, IID_Identity);
     4481    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     4482    // Get other animals ; range = fleeDistance, players = [0] (gaia only)
     4483    var range = (+this.template.FleeDistance);
     4484    var nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, range, [0], IID_UnitAI);
     4485    for each (var ent in nearby)
     4486    {
     4487        var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     4488        if (cmpUnitAI.template.NaturalBehaviour == "skittish" ||
     4489            cmpUnitAI.template.NaturalBehaviour == "passive")
     4490        {
     4491            cmpUnitAI.Flee(attacker, false, this.entity);
     4492        }
     4493        else if (cmpOwnIdentity && cmpOwnIdentity.template.Species &&
     4494                 (cmpUnitAI.IsDangerousAnimal() || cmpUnitAI.template.NaturalBehaviour == "defensive"))
     4495        {
     4496            var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
     4497            if (cmpIdentity && cmpIdentity.template.Species &&
     4498                cmpIdentity.template.Species == cmpOwnIdentity.template.Species)
     4499            {
     4500                if(cmpUnitAI.CanAttack(attacker))
     4501                    cmpUnitAI.Attack(attacker, false);
     4502            }
     4503        }
     4504    }
     4505};
     4506
    43884507Engine.RegisterComponentType(IID_UnitAI, "UnitAI", UnitAI);