Ticket #2010: buildingAI_with_preferred_classes.diff

File buildingAI_with_preferred_classes.diff, 28.1 KB (added by sanderd17, 11 years ago)
  • binaries/data/mods/public/simulation/components/BuildingAI.js

     
    11//Number of rounds of firing per 2 seconds
    22const roundCount = 10;
    33const timerInterval = 2000 / roundCount;
     4const attackType = "Ranged";
     5// chance an arrow will be aimed at the forced target
     6const forcedTargetHitChance = 0.5;
     7// chance an arrow will be aimed at a target from the first preferred class
     8// exponentially lowered for the later preferred classes
     9const preferredTargetHitChance = 0.8;
    410
    511function BuildingAI() {}
    612
    713BuildingAI.prototype.Schema =
    8     "<element name='DefaultArrowCount'>" +
     14    "<element name='DefaultProjectileCount'>" +
    915        "<data type='nonNegativeInteger'/>" +
    1016    "</element>" +
    11     "<element name='GarrisonArrowMultiplier'>" +
     17    "<element name='GarrisonProjectileMultiplier'>" +
    1218        "<ref name='nonNegativeDecimal'/>" +
     19    "</element>" +
     20    "<element name='MaxNumberOfProjectiles'>" +
     21        "<data type='nonNegativeInteger'/>" +
     22    "</element>" +
     23    "<element name='GarrisonProjectileClasses'>" +
     24        "<attribute name='datatype'>" +
     25            "<value>tokens</value>" +
     26        "</attribute>" +
     27        "<text/>" +
    1328    "</element>";
    1429
     30
     31   
     32
    1533/**
    1634 * Initialize BuildingAI Component
    1735 */
    1836BuildingAI.prototype.Init = function()
    1937{
    20     if (this.GetDefaultArrowCount() > 0 || this.GetGarrisonArrowMultiplier() > 0)
     38    if (this.GetDefaultProjectileCount() > 0 || this.GetGarrisonProjectileMultiplier() > 0)
    2139    {
    22         var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    2340        this.currentRound = 0;
    24         //Arrows left to fire
    25         this.arrowsLeft = 0;
    26         this.timer = cmpTimer.SetTimeout(this.entity, IID_BuildingAI, "FireArrows", timerInterval, {});
     41        //Projectiles left to fire
     42        this.projectilesLeft = 0;
    2743        this.targetUnits = [];
     44        this.targetUnitsPerPreference = [];
    2845    }
    2946};
    3047
     
    3249{
    3350    // Remove current targets, to prevent them from being added twice
    3451    this.targetUnits = [];
     52    this.targetUnitsPerPreference = [];
    3553
    3654    if (msg.to != -1)
    3755        this.SetupRangeQuery(msg.to);
     
    4866    {
    4967        // Remove maybe now allied/neutral units
    5068        this.targetUnits = [];
     69        this.targetUnitsPerPreference = [];
    5170        this.SetupRangeQuery(msg.player);
    5271    }
    5372};
     
    96115            players.push(i);
    97116    }
    98117    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     }
     118    if (!cmpAttack)
     119        return;
     120   
     121    var range = cmpAttack.GetRange(attackType);
     122    this.enemyUnitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
     123    cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
    105124};
    106125
    107126// Set up a range query for Gaia units within LOS range which can be attacked.
     
    111130    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    112131    var owner = cmpOwnership.GetOwner();
    113132
    114     var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     133    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    115134    var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
    116135
    117136    if (this.gaiaUnitsQuery)
    118137    {
    119         rangeMan.DestroyActiveQuery(this.gaiaUnitsQuery);
     138        cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
    120139        this.gaiaUnitsQuery = undefined;
    121140    }
    122141
     
    128147        return;
    129148
    130149    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
    131     if (cmpAttack)
    132     {
    133         var range = cmpAttack.GetRange("Ranged");
     150    if (!cmpAttack)
     151        return;
     152   
     153    var range = cmpAttack.GetRange(attackType);
    134154
    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     }
     155    // This query is only interested in Gaia entities that can attack.
     156    this.gaiaUnitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
     157    cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
    139158};
    140159
    141160/**
     
    143162 */
    144163BuildingAI.prototype.OnRangeUpdate = function(msg)
    145164{
     165
     166    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
     167    if (!cmpAttack)
     168        return;
     169
    146170    if (msg.tag == this.gaiaUnitsQuery)
    147171    {
    148172        const filter = function(e) {
     
    161185    else if (msg.tag != this.enemyUnitsQuery)
    162186        return;
    163187
     188    const restrictedClasses = cmpAttack.GetRestrictedClasses(attackType);
     189    const preferredClasses = cmpAttack.GetPreferredClasses(attackType);
     190
    164191    if (msg.added.length > 0)
    165192    {
    166193        for each (var entity in msg.added)
    167194        {
    168             this.targetUnits.push(entity);
     195            var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
     196            var targetClasses = cmpIdentity.GetClassesList();
     197
     198            if (!targetClasses.some(function(c){return restrictedClasses.indexOf(c) > -1;}))
     199            {
     200                for (var i = 0; i < preferredClasses.length; ++i)
     201                {
     202                    if (targetClasses.indexOf(preferredClasses[i]) > -1)
     203                    {
     204                        if (!targetUnitsPerPreference[i])
     205                            targetUnitsPerPreference[i] = [];
     206
     207                        this.targetUnitsPerPreference[i].push(entity);
     208                    }
     209                }
     210                // also add all targets to index -1 for easy accessing
     211                this.targetUnits.push(entity);
     212            }
    169213        }
    170214    }
    171215    if (msg.removed.length > 0)
     
    172216    {
    173217        for each (var entity in msg.removed)
    174218        {
    175             this.targetUnits.splice(this.targetUnits.indexOf(entity), 1);
     219            for (var i = 0 ; i < preferredClasses.length; ++i)
     220            {
     221                if (!targetUnitsPerPreference[i])
     222                    continue;
     223
     224                var index = this.targetUnitsPerPreference[i].indexOf(entity);
     225                if (index > -1)
     226                    this.targetUnitsPerPreference[i].splice(index, 1);
     227            }
     228            var index = this.targetUnits.indexOf(entity);
     229            if (index > -1)
     230                this.targetUnits.splice(index, 1);
    176231        }
    177232    }
     233   
     234    if (!this.targetUnits.length || this.timer)
     235        return;
     236    // units entered the range, prepare to shoot   
     237    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     238    var attackTimers = cmpAttack.GetTimers(attackType);
     239    this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireProjectiles", attackTimers.prepare, attackTimers.repeat / roundCount, {});
     240   
    178241};
    179242
    180 BuildingAI.prototype.GetDefaultArrowCount = function()
     243BuildingAI.prototype.GetDefaultProjectileCount = function()
    181244{
    182     var arrowCount = +this.template.DefaultArrowCount;
    183     return ApplyTechModificationsToEntity("BuildingAI/DefaultArrowCount", arrowCount, this.entity);
     245    var projectileCount = +this.template.DefaultProjectileCount;
     246    return ApplyTechModificationsToEntity("BuildingAI/DefaultProjectileCount", projectileCount, this.entity);
    184247};
    185248
    186 BuildingAI.prototype.GetGarrisonArrowMultiplier = function()
     249BuildingAI.prototype.GetGarrisonProjectileMultiplier = function()
    187250{
    188     var arrowMult = +this.template.GarrisonArrowMultiplier;
    189     return ApplyTechModificationsToEntity("BuildingAI/GarrisonArrowMultiplier", arrowMult, this.entity);
     251    var projectileMult = +this.template.GarrisonProjectileMultiplier;
     252    return ApplyTechModificationsToEntity("BuildingAI/GarrisonProjectileMultiplier", projectileMult, this.entity);
    190253};
    191254
     255BuildingAI.prototype.GetMaxNumberOfProjectiles = function()
     256{
     257    var maxNum = +this.template.MaxNumberOfProjectiles;
     258    return ApplyTechModificationsToEntity("BuildingAI/MaxNumberOfProjectiles", maxNum, this.entity);
     259};
     260
     261BuildingAI.prototype.GetGarrisonProjectileClasses = function()
     262{
     263    var string = this.template.GarrisonProjectileClasses._string || "";
     264    return string.split(/\s+/);
     265};
     266
    192267/**
    193  * Returns the number of arrows which needs to be fired.
    194  * DefaultArrowCount + Garrisoned Archers(ie., any unit capable
    195  * of shooting arrows from inside buildings)
     268 * Returns the number of projectiles which needs to be fired.
     269 * DefaultProjectileCount + Garrisoned Archers(ie., any unit capable
     270 * of shooting projectiles from inside buildings)
    196271 */
    197 BuildingAI.prototype.GetArrowCount = function()
     272BuildingAI.prototype.GetProjectileCount = function()
    198273{
    199     var count = this.GetDefaultArrowCount();
     274    var count = this.GetDefaultProjectileCount();
    200275    var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
    201276    if (cmpGarrisonHolder)
    202277    {
    203         count += Math.round(cmpGarrisonHolder.GetGarrisonedArcherCount() * this.GetGarrisonArrowMultiplier());
     278        count += Math.round(cmpGarrisonHolder.GetGarrisonedArcherCount(this.GetGarrisonProjectileClasses()) * this.GetGarrisonProjectileMultiplier());
    204279    }
    205     return count;
     280    return Math.min(this.GetMaxNumberOfProjectiles(), count);
    206281};
    207282
    208283/**
    209  * Fires arrows. Called every N times every 2 seconds
    210  * where N is the number of Arrows
     284 * Fires projectiles. Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range
    211285 */
    212 BuildingAI.prototype.FireArrows = function()
     286BuildingAI.prototype.FireProjectiles = function()
    213287{
     288
     289   
     290    if (!this.targetUnits.length && this.timer)
     291    {
     292        // stop the timer
     293        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     294        cmpTimer.CancelTimer(this.timer);
     295        this.timer = undefined;
     296        return;
     297    }
     298
    214299    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
    215     if (cmpAttack)
     300    if (!cmpAttack)
     301        return;
     302
     303    var numberOfPreferredClasses = cmpAttack.GetPreferredClasses().length;
     304
     305    var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
     306    if (cmpUnitAI)
    216307    {
    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))
     308        var orders = cmpUnitAI.GetOrders();
     309        if (orders.length && orders[0].type == 'Attack' && orders[0].data.force)
     310            // user is forcing this entity to attack a certian target
     311            this.forcedTarget = +orders[0].data.target;
     312        else
     313            this.forcedTarget = undefined;
     314    }
     315
     316    var projectilesToFire = 0;
     317   
     318    if (this.currentRound === 0)
     319        this.projectilesLeft = this.GetProjectileCount();
     320   
     321    if (this.currentRound === (roundCount - 1))
     322    {
     323        //Last round. Need to fire all left-over projectiles
     324        projectilesToFire = this.projectilesLeft;
     325    }
     326    else
     327    {
     328        //Fire N projectiles, 0 <= N <= Number of projectiles left
     329        projectilesToFire = Math.min(
     330            Math.round(2*Math.random() * this.GetProjectileCount()/roundCount), 
     331            this.projectilesLeft
     332        );
     333    }
     334   
     335    for (var i = 0; i < projectilesToFire; ++i)
     336    {
     337        var target;
     338        var hitFactor = Math.random();
     339        if (this.forcedTarget
     340               && this.targetUnits.indexOf(forcedTarget) > -1
     341               && hitFactor < forcedTargetHitChance)
    221342        {
    222             //Reached end of rounds. Reset count
    223             this.currentRound = 0;
     343            // user forced to attack a certain one, and we're able to attack the target
     344            target = this.forcedTarget;
    224345        }
    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         }
    237346        else
    238347        {
    239             //Fire N arrows, 0 <= N <= Number of arrows left
    240             arrowsToFire = Math.floor(Math.random() * this.arrowsLeft);
     348            var preferredClass = -1;
     349            while (hitFactor > preferredTargetHitChance && preferredClass++ < numberOfPreferredClasses)
     350                hitFactor *= hitFactor;
     351           
     352            if (preferredClass < numberOfPreferredClasses
     353                   && this.targetUnitsPerPreference[preferredClass])
     354                target = this.targetUnitsPerPreference[preferredClass]
     355                    [Math.floor(Math.random() * this.targetUnitsPerPreference[preferredClass].length)];
     356            else
     357                target = this.targetUnits
     358                    [Math.floor(Math.random() * this.targetUnits.length)];
    241359        }
    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++;
     360
     361        cmpAttack.PerformAttack(attackType, target);
     362        // TODO use Sound.js sounds
     363        PlaySound("projectilefly", this.entity);
    252364    }
     365    this.projectilesLeft -= projectilesToFire;
     366   
     367    this.currentRound = ++this.currentRound % roundCount;
     368   
    253369};
    254370
    255371Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI);
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
    7878 * Get number of garrisoned units capable of shooting arrows
    7979 * Not necessarily archers
    8080 */
    81 GarrisonHolder.prototype.GetGarrisonedArcherCount = function()
     81GarrisonHolder.prototype.GetGarrisonedArcherCount = function(garrisonProjectileClasses)
    8282{
    8383    var count = 0;
    8484    for each (var entity in this.entities)
     
    8585    {
    8686        var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
    8787        var classes = cmpIdentity.GetClassesList();
    88         if (classes.indexOf("Infantry") != -1 || classes.indexOf("Ranged") != -1)
     88        if (classes.some(function(c){return garrisonProjectileClasses.indexOf(c) > -1;}))
    8989            count++;
    9090    }
    9191    return count;
  • binaries/data/mods/public/simulation/templates/campaigns/campaign_city_minor_test.xml

     
    1313    </Ranged>
    1414  </Attack>
    1515  <BuildingAI>
    16     <DefaultArrowCount>3</DefaultArrowCount>
    17     <GarrisonArrowMultiplier>0.5</GarrisonArrowMultiplier>
     16    <DefaultProjectileCount>3</DefaultProjectileCount>
     17    <GarrisonProjectileMultiplier>0.5</GarrisonProjectileMultiplier>
    1818  </BuildingAI>
    1919  <Footprint replace="">
    2020    <Circle radius="26.0"/>
  • binaries/data/mods/public/simulation/templates/campaigns/campaign_city_test.xml

     
    1313    </Ranged>
    1414  </Attack>
    1515  <BuildingAI>
    16     <DefaultArrowCount>5</DefaultArrowCount>
    17     <GarrisonArrowMultiplier>0.5</GarrisonArrowMultiplier>
     16    <DefaultProjectileCount>5</DefaultProjectileCount>
     17    <GarrisonProjectileMultiplier>0.5</GarrisonProjectileMultiplier>
    1818  </BuildingAI>
    1919  <Footprint replace="">
    2020    <Circle radius="26.0"/>
  • binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_civic_civil_centre">
    33  <BuildingAI>
    4     <DefaultArrowCount>3</DefaultArrowCount>
    5     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     4    <DefaultProjectileCount>3</DefaultProjectileCount>
     5    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
    66  </BuildingAI>
    77  <BuildRestrictions>
    88    <Territory>own ally neutral</Territory>
  • binaries/data/mods/public/simulation/templates/structures/iber_defense_tower.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_structure_defense_defense_tower">
    33  <BuildingAI>
    4     <DefaultArrowCount>2</DefaultArrowCount>
     4    <DefaultProjectileCount>2</DefaultProjectileCount>
    55  </BuildingAI>
    66  <Cost>
    77    <PopulationBonus>5</PopulationBonus>
  • binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml

     
    2020      <ProjectileSpeed>75.0</ProjectileSpeed>
    2121      <PrepareTime>1200</PrepareTime>
    2222      <RepeatTime>2000</RepeatTime>
    23       <Spread>1.5</Spread>
    24     </Ranged>
    25   </Attack>
    26   <BuildingAI>
    27     <DefaultArrowCount>3</DefaultArrowCount>
    28     <GarrisonArrowMultiplier>0.5</GarrisonArrowMultiplier>
    29   </BuildingAI>
    30   <BuildRestrictions>
    31     <Territory>own neutral enemy</Territory>
    32     <Category>Fortress</Category>
    33   </BuildRestrictions>
    34   <Cost>
     23      <Spread>1.5</Spread>
     24    </Ranged>
     25  </Attack>
     26  <BuildingAI>
     27    <DefaultProjectileCount>3</DefaultProjectileCount>
     28    <GarrisonProjectileMultiplier>0.5</GarrisonProjectileMultiplier>
     29    <GarrisonProjectileClasses datatype="tokens">Infanty Ranged</GarrisonProjectileClasses>
     30  </BuildingAI>
     31  <BuildRestrictions>
     32    <Territory>own neutral enemy</Territory>
     33    <Category>Fortress</Category>
     34  </BuildRestrictions>
     35  <Cost>
    3536    <PopulationBonus>5</PopulationBonus>
    3637    <BuildTime>160</BuildTime>
    3738    <Resources>
  • binaries/data/mods/public/simulation/templates/template_structure.xml

     
    1111    </Foundation>
    1212  </Armour>
    1313  <BuildingAI>
    14     <DefaultArrowCount>0</DefaultArrowCount>
    15     <GarrisonArrowMultiplier>0</GarrisonArrowMultiplier>
     14    <DefaultProjectileCount>0</DefaultProjectileCount>
     15    <GarrisonProjectileMultiplier>0</GarrisonProjectileMultiplier>
     16    <MaxNumberOfProjectiles>20</MaxNumberOfProjectiles>
     17    <GarrisonProjectileClasses datatype="tokens">Infanty Ranged</GarrisonProjectileClasses>
    1618  </BuildingAI>
    1719  <BuildRestrictions>
    1820    <PlacementType>land</PlacementType>
  • binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml

     
    1414    </Ranged>
    1515  </Attack>
    1616  <BuildingAI>
    17     <DefaultArrowCount>3</DefaultArrowCount>
    18     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     17    <DefaultProjectileCount>3</DefaultProjectileCount>
     18    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
    1919  </BuildingAI>
    2020  <BuildRestrictions>
    2121    <Territory>own neutral</Territory>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml

     
    77      <Crush>0.0</Crush>
    88      <MaxRange>70.0</MaxRange>
    99      <MinRange>16.0</MinRange>
    10       <ProjectileSpeed>75.0</ProjectileSpeed>
    11       <PrepareTime>1200</PrepareTime>
    12       <RepeatTime>2000</RepeatTime>
    13       <Spread>1.5</Spread>
    14     </Ranged>
    15   </Attack>
    16   <BuildingAI>
    17     <DefaultArrowCount>1</DefaultArrowCount>
    18     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
    19   </BuildingAI>
    20   <BuildRestrictions>
    21     <Category>DefenseTower</Category>
    22   </BuildRestrictions>
    23   <Cost>
    24     <BuildTime>120</BuildTime>
     10      <ProjectileSpeed>75.0</ProjectileSpeed>
     11      <PrepareTime>1200</PrepareTime>
     12      <RepeatTime>2000</RepeatTime>
     13      <RestrictedClasses datatype="tokens">Structure</RestrictedClasses>
     14      <Spread>1.5</Spread>
     15    </Ranged>
     16  </Attack>
     17  <BuildingAI>
     18    <DefaultProjectileCount>1</DefaultProjectileCount>
     19    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
     20  </BuildingAI>
     21  <BuildRestrictions>
     22    <Category>DefenseTower</Category>
     23  </BuildRestrictions>
     24  <Cost>
     25    <BuildTime>120</BuildTime>
    2526    <Resources>
    2627      <wood>100</wood>
    2728      <stone>100</stone>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml

     
    2020      <ProjectileSpeed>75.0</ProjectileSpeed>
    2121      <PrepareTime>1200</PrepareTime>
    2222      <RepeatTime>2000</RepeatTime>
     23      <RestrictedClasses datatype="tokens">Structure</RestrictedClasses>
    2324      <Spread>2.0</Spread>
    2425    </Ranged>
    2526  </Attack>
    2627  <BuildingAI>
    27     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     28    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
    2829  </BuildingAI>
    2930  <BuildRestrictions>
    3031    <Territory>own neutral</Territory>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml

     
    1414    </Ranged>
    1515  </Attack>
    1616  <BuildingAI>
    17     <DefaultArrowCount>1</DefaultArrowCount>
    18     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     17    <DefaultProjectileCount>1</DefaultProjectileCount>
     18    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
    1919  </BuildingAI>
    2020  <BuildRestrictions>
    2121    <PlacementType>land-shore</PlacementType>
  • binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml

     
    1010      <ProjectileSpeed>75.0</ProjectileSpeed>
    1111      <PrepareTime>1200</PrepareTime>
    1212      <RepeatTime>2000</RepeatTime>
     13      <RestrictedClasses datatype="tokens">Structure</RestrictedClasses>
    1314      <Spread>1.5</Spread>
    1415    </Ranged>
    1516  </Attack>
    1617  <BuildingAI>
    17     <DefaultArrowCount>3</DefaultArrowCount>
    18     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     18    <DefaultProjectileCount>3</DefaultProjectileCount>
     19    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
    1920  </BuildingAI>
    2021  <BuildRestrictions>
    2122    <Category>Fortress</Category>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml

     
    1414    </Ranged>
    1515  </Attack>
    1616  <BuildingAI>
    17     <DefaultArrowCount>2</DefaultArrowCount>
    18     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     17    <DefaultProjectileCount>2</DefaultProjectileCount>
     18    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
     19    <GarrisonProjectileClasses datatype="tokens">Infanty Ranged</GarrisonProjectileClasses>
     20    <MaxNumberOfProjectiles>20</MaxNumberOfProjectiles>
    1921  </BuildingAI>
    2022  <Cost>
    2123    <Population>2</Population>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml

     
    22<Entity parent="template_unit_mechanical_ship">
    33  <Attack>
    44    <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>
    88      <MaxRange>65.0</MaxRange>
    99      <MinRange>20.0</MinRange>
    1010      <ProjectileSpeed>40.0</ProjectileSpeed>
    11       <PrepareTime>2000</PrepareTime>
     11      <PrepareTime>5000</PrepareTime>
    1212      <RepeatTime>4000</RepeatTime>
    1313      <Spread>1.5</Spread>
    1414    </Ranged>
     
    2121      <metal>200</metal>
    2222    </Resources>
    2323  </Cost>
     24  <BuildingAI>
     25    <DefaultProjectileCount>0</DefaultProjectileCount>
     26    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
     27    <GarrisonProjectileClasses datatype="tokens">Ballista</GarrisonProjectileClasses>
     28    <MaxNumberOfProjectiles>6</MaxNumberOfProjectiles>
     29  </BuildingAI>
    2430  <Footprint>
    2531    <Square width="12.0" depth="48.0"/>
    2632    <Height>8.0</Height>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml

     
    1414    </Ranged>
    1515  </Attack>
    1616  <BuildingAI>
    17     <DefaultArrowCount>3</DefaultArrowCount>
    18     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     17    <DefaultProjectileCount>3</DefaultProjectileCount>
     18    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
     19    <GarrisonProjectileClasses datatype="tokens">Infanty Ranged</GarrisonProjectileClasses>
     20    <MaxNumberOfProjectiles>20</MaxNumberOfProjectiles>
    1921  </BuildingAI>
    2022  <Cost>
    2123    <Population>3</Population>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_onager.xml

     
    5353  <Identity>
    5454    <GenericName>Siege Catapult</GenericName>
    5555    <Tooltip>Bonused vs. Structures and Massed Infantry.</Tooltip>
     56    <Classes datatype="tokens">Ballista</Classes>
    5657  </Identity>
    5758  <Loot>
    5859    <xp>300</xp>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_tower.xml

     
    1515      <ProjectileSpeed>75.0</ProjectileSpeed>
    1616      <PrepareTime>1200</PrepareTime>
    1717      <RepeatTime>2000</RepeatTime>
     18      <RestrictedClasses datatype="tokens">Structure</RestrictedClasses>
    1819      <Spread>1.5</Spread>
    1920    </Ranged>
    2021  </Attack>
    2122  <BuildingAI>
    22     <DefaultArrowCount>1</DefaultArrowCount>
    23     <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     23    <DefaultProjectileCount>1</DefaultProjectileCount>
     24    <GarrisonProjectileMultiplier>1</GarrisonProjectileMultiplier>
     25    <GarrisonProjectileClasses datatype="tokens">Infanty Ranged</GarrisonProjectileClasses>
     26    <MaxNumberOfProjectiles>20</MaxNumberOfProjectiles>
    2427  </BuildingAI>
    2528  <Cost>
    2629    <Population>5</Population>