Ticket #2577: 2577.diff

File 2577.diff, 30.8 KB (added by Stan, 9 years ago)

This patch follows the order of the the parent, so it can capture, and attack while moving. Since the parent is always sending attack commands though, it will only be able to attack on unit at a time. Still need the fix for atlas, and * maur champion chariot * hero darius * hero xerxes Apart from that it's functionnal

  • binaries/data/mods/public/art/actors/units/celts/boudicca_chariot.xml

     
    1212      <props>
    1313        <prop actor="units/celts/boudicca_chariot_h1.xml" attachpoint="horseright"/>
    1414        <prop actor="units/celts/boudicca_chariot_h2.xml" attachpoint="horseleft"/>
    15         <prop actor="units/celts/boudicca_r2.xml" attachpoint="rider"/>
    1615        <prop actor="units/celts/champion_unit_4_d.xml" attachpoint="driver"/>
    1716      </props>
    1817      <textures><texture file="structural/celt_chariot_b.dds" name="baseTex"/></textures>
  • binaries/data/mods/public/art/actors/units/celts/champion_unit_4.xml

     
    1313        <prop actor="units/celts/champion_unit_4_h.xml" attachpoint="horseright"/>
    1414        <prop actor="units/celts/champion_unit_4_h2.xml" attachpoint="horseleft"/>
    1515        <prop actor="units/celts/champion_unit_4_d.xml" attachpoint="driver"/>
    16         <prop actor="units/celts/champion_unit_4_r.xml" attachpoint="rider"/>
    1716      </props>
    1817      <textures><texture file="structural/celt_chariot_a.dds" name="baseTex"/></textures>
    1918    </variant>
  • binaries/data/mods/public/art/actors/units/mauryans/hero_chariot.xml

     
    1414        <prop actor="units/persians/pers_chariot_archer_e_h2.xml" attachpoint="horse2"/>
    1515        <prop actor="units/persians/pers_chariot_archer_e_h3.xml" attachpoint="horse3"/>
    1616        <prop actor="units/persians/pers_chariot_archer_e_h4.xml" attachpoint="horse4"/>
    17         <prop actor="units/mauryans/hero_ashoka_rider.xml" attachpoint="rider1"/>
    18         <prop actor="units/mauryans/hero_chariot_maiden_archer.xml" attachpoint="rider2"/>
    1917        <prop actor="units/mauryans/hero_chariot_maiden_parasol.xml" attachpoint="rider3"/>
    2018      </props>
    2119      <textures>
  • binaries/data/mods/public/art/actors/units/persians/cavalry_archer_a.xml

     
    1414        <prop actor="units/persians/pers_chariot_archer_a_h2.xml" attachpoint="horse2"/>
    1515        <prop actor="units/persians/pers_chariot_archer_a_h3.xml" attachpoint="horse3"/>
    1616        <prop actor="units/persians/pers_chariot_archer_a_h4.xml" attachpoint="horse4"/>
    17         <prop actor="units/persians/cavalry_archer_a_r.xml" attachpoint="rider1"/>
    1817        <prop actor="units/persians/cavalry_archer_a_d.xml" attachpoint="rider2"/>
    1918      </props>
    2019      <textures><texture file="structural/pers_chariot_a.png" name="baseTex"/></textures>
  • binaries/data/mods/public/art/actors/units/persians/cavalry_archer_e.xml

     
    1515        <prop actor="units/persians/pers_chariot_archer_e_h2.xml" attachpoint="horse2"/>
    1616        <prop actor="units/persians/pers_chariot_archer_e_h3.xml" attachpoint="horse3"/>
    1717        <prop actor="units/persians/pers_chariot_archer_e_h4.xml" attachpoint="horse4"/>
    18         <prop actor="units/persians/cavalry_archer_e_r.xml" attachpoint="rider1"/>
    1918        <prop actor="units/persians/cavalry_archer_e_d.xml" attachpoint="rider2"/>
    2019      </props>
    2120      <textures><texture file="structural/pers_chariot_e.png" name="baseTex"/></textures>
  • binaries/data/mods/public/simulation/components/Attack.js

     
    155155                        "</interleave>" +
    156156                    "</element>" +
    157157                "</optional>" +
     158                "<optional>"+
     159                    "<element name='TurretsOnly' a:help='When set to \"true\", will only accept attacks coming from turrets.'><text/></element>" +
     160                "</optional>" +
    158161            "</interleave>" +
    159162        "</element>" +
    160163    "</optional>" +
     
    202205
    203206Attack.prototype.Init = function()
    204207{
     208    this.latestTarget = INVALID_ENTITY;
    205209};
    206210
    207 Attack.prototype.Serialize = null; // we have no dynamic state to save
     211Attack.prototype.Serialize = null; // we have no dynamic state to save 
    208212
    209213Attack.prototype.GetAttackTypes = function()
    210214{
     
    492496 * and should only be called after GetTimers().repeat msec has passed since the last
    493497 * call to PerformAttack.
    494498 */
    495 Attack.prototype.PerformAttack = function(type, target)
     499Attack.prototype.PerformAttack = function(type, target, turretId)
    496500{
     501    if(this.template[type].TurretsOnly)
     502        if (!turretId && this.template[type].TurretsOnly == "true")
     503            return;
     504
    497505    // If this is a ranged attack, then launch a projectile
    498506    if (type == "Ranged")
    499507    {
     
    561569        var graphicalPosition = Vector3D.mult(missileDirection, 2).add(realTargetPosition);
    562570        // Launch the graphical projectile
    563571        var cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
    564         var id = cmpProjectileManager.LaunchProjectileAtPoint(this.entity, realTargetPosition, horizSpeed, gravity);
     572        var id = cmpProjectileManager.LaunchProjectileAtPoint(turretId || this.entity, realTargetPosition, horizSpeed, gravity);
    565573
    566574        var playerId = Engine.QueryInterface(this.entity, IID_Ownership).GetOwner();
    567575        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
  • binaries/data/mods/public/simulation/components/interfaces/TurretAI.js

     
     1Engine.RegisterInterface("TurretAI");
  • binaries/data/mods/public/simulation/components/interfaces/TurretHolder.js

     
     1Engine.RegisterInterface("TurretHolder");
     2
  • binaries/data/mods/public/simulation/components/TurretAI.js

     
     1function TurretAI() {}
     2TurretAI.prototype.Schema =
     3    "<empty/>";
     4
     5TurretAI.prototype.g_MaxPreferenceBonus = 2;
     6TurretAI.prototype.g_LatestTarget = 0   ;
     7
     8/**
     9 * Initialize TurretAI Component.
     10 */
     11TurretAI.prototype.Init = function()
     12{
     13};
     14
     15/**
     16 * Get the turrent parent.
     17 */
     18TurretAI.prototype.GetTurretParent = function()
     19{
     20    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     21    if (!cmpPosition)
     22        return INVALID_ENTITY;
     23    return cmpPosition.GetTurretParent();
     24};
     25
     26/**
     27 * Get the attack component
     28 */
     29TurretAI.prototype.GetCmpAttack = function()
     30{
     31    // use own attack, or turretHolder's attack
     32    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
     33    if (cmpAttack)
     34        return cmpAttack;
     35    return Engine.QueryInterface(this.GetTurretParent(), IID_Attack);
     36};
     37
     38/**
     39 * Sends the message to change ownership
     40 */
     41TurretAI.prototype.OnOwnershipChanged = function(msg)
     42{
     43    var cmpAttack = this.GetCmpAttack();
     44    if (!cmpAttack)
     45        return;
     46    //Return the first possible Attack Type, Capturing being the last.
     47    this.bestAttack = cmpAttack.GetAttackTypes()[0];
     48   
     49    // Remove current targets, to prevent them from being added twice
     50    this.targetUnits = [];
     51
     52    if (msg.to != -1)
     53        this.SetupRangeQuery(msg.to);
     54
     55    // Non-Gaia buildings should attack certain Gaia units.
     56    if (msg.to != 0 || this.gaiaUnitsQuery)
     57        this.SetupGaiaRangeQuery(msg.to);
     58};
     59
     60/**
     61 * Change Diplomacy State
     62 */
     63TurretAI.prototype.OnDiplomacyChanged = function(msg)
     64{
     65    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     66    if (cmpOwnership && cmpOwnership.GetOwner() == msg.player)
     67    {
     68        // Remove now allied/neutral units
     69        this.targetUnits = [];
     70        this.SetupRangeQuery(msg.player);
     71    }
     72};
     73
     74/**
     75 * Cleanup on destroy
     76 */
     77TurretAI.prototype.OnDestroy = function()
     78{
     79    if (this.timer)
     80    {
     81        let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     82        cmpTimer.CancelTimer(this.timer);
     83        this.timer = undefined;
     84    }
     85
     86    // Clean up range queries
     87    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     88    if (this.enemyUnitsQuery)
     89        cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
     90    if (this.gaiaUnitsQuery)
     91        cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
     92};
     93
     94/**
     95 * Setup the Range Query to detect units coming in & out of range
     96 */
     97TurretAI.prototype.SetupRangeQuery = function(owner)
     98{
     99    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     100    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     101    var cmpAttack = this.GetCmpAttack();
     102    if (!cmpAttack)
     103        return;
     104
     105    if (this.enemyUnitsQuery)
     106    {
     107        cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
     108        this.enemyUnitsQuery = undefined;
     109    }
     110   
     111    var players = [];
     112    var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(owner), IID_Player);
     113    var numPlayers = cmpPlayerManager.GetNumPlayers();
     114
     115    for (let i = 1; i < numPlayers; ++i)
     116    {
     117        // TODO: How to handle neutral players - Special query to attack military only?
     118        if (cmpPlayer.IsEnemy(i))
     119            players.push(i);
     120    }
     121
     122    var range = cmpAttack.GetRange(this.bestAttack);
     123    this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(this.entity, range.min, range.max, range.elevationBonus, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
     124    cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
     125};
     126
     127/**
     128 *Set up a range query for Gaia units within LOS range which can be attacked.
     129 * This should be called whenever our ownership changes.
     130 */
     131TurretAI.prototype.SetupGaiaRangeQuery = function()
     132{
     133    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     134    var owner = cmpOwnership.GetOwner();
     135
     136    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     137    var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     138    var cmpAttack = this.GetCmpAttack();
     139    if (!cmpAttack)
     140        return;
     141
     142    if (this.gaiaUnitsQuery)
     143    {
     144        cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
     145        this.gaiaUnitsQuery = undefined;
     146    }
     147
     148    if (owner == -1)
     149        return;
     150
     151    var cmpPlayer = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player);
     152    if (!cmpPlayer.IsEnemy(0))
     153        return;
     154
     155    var range = cmpAttack.GetRange(this.bestAttack);
     156
     157    // This query is only interested in Gaia entities that can attack.
     158    this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(this.entity, range.min, range.max, range.elevationBonus, [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
     159    cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
     160};
     161
     162/**
     163 * Called when units enter or leave range
     164 */
     165TurretAI.prototype.OnRangeUpdate = function(msg)
     166{
     167    var cmpAttack = this.GetCmpAttack();
     168    if (!cmpAttack)
     169        return;
     170
     171    if (msg.tag == this.gaiaUnitsQuery)
     172    {
     173        const filter = function(e) {
     174            let cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
     175            return (cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal()));
     176        };
     177
     178        if (msg.added.length)
     179            msg.added = msg.added.filter(filter);
     180
     181        // Removed entities may not have cmpUnitAI.
     182        for (let i = 0; i < msg.removed.length; ++i)
     183            if (this.targetUnits.indexOf(msg.removed[i]) == -1)
     184                msg.removed.splice(i--, 1);
     185    }
     186    else if (msg.tag != this.enemyUnitsQuery)
     187        return;
     188
     189    if (msg.added.length > 0)
     190        for (let entity of msg.added)
     191            if (cmpAttack.CanAttack(entity))
     192                this.targetUnits.push(entity);
     193           
     194    if (msg.removed.length > 0)
     195        for (let entity of msg.removed)
     196        {   
     197            let index = this.targetUnits.indexOf(entity);
     198            if (index > -1)
     199                this.targetUnits.splice(index, 1);
     200        }
     201
     202    if (!this.targetUnits.length || this.timer)
     203        return;
     204
     205    var attackTimers = cmpAttack.GetTimers(this.bestAttack);
     206    this.SelectAnimation("attack_" + this.bestAttack.toLowerCase(), false, 1.0, "attack");
     207    this.SetAnimationSync(attackTimers.prepare, attackTimers.repeat);
     208    // units entered the range, prepare to shoot
     209    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     210    this.timer = cmpTimer.SetInterval(this.entity, IID_TurretAI, "Attack", attackTimers.prepare, attackTimers.repeat, null);
     211};
     212
     213/**
     214 * Get Previous Target
     215 */
     216TurretAI.prototype.GetPreviousTarget = function()
     217{
     218    var cmpAttack = this.GetCmpAttack();
     219    if (!cmpAttack)
     220        return INVALID_ENTITY;
     221    var previousTarget = this.g_LatestTarget;
     222    var cmpUnitAI = Engine.QueryInterface(this.GetTurretParent(), IID_UnitAI);
     223    // if a unit ai, use that to overcome the difference between rangeManager range and unitMotion range
     224    if (cmpUnitAI)
     225    {
     226        if (cmpUnitAI.CheckTargetAttackRange(previousTarget, this.bestAttack))
     227            return previousTarget;
     228        return INVALID_ENTITY;
     229    }
     230    // else just use the range manager (which gives us the list of possible targets);
     231    if (this.targetUnits.indexOf(previousTarget) != -1)
     232        return previousTarget;
     233    return INVALID_ENTITY;
     234};
     235
     236/**
     237 * Attack other entities
     238 */
     239TurretAI.prototype.Attack = function()
     240{
     241    if (!this.targetUnits.length)
     242    {
     243        if (this.timer)
     244        {
     245            // stop the timer
     246            let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     247            cmpTimer.CancelTimer(this.timer);
     248            this.timer = undefined;
     249        }
     250        this.SelectAnimation("idle");
     251        return;
     252    }
     253   
     254    var cmpAttack = this.GetCmpAttack();
     255    if (!cmpAttack)
     256        return;
     257    var target = this.GetPreviousTarget();
     258    // if no target, select a random one
     259    if (target == INVALID_ENTITY)
     260    {
     261        var selectedIndex = -1;
     262        var targets = new WeightedList();
     263        for (let i = 0; i < this.targetUnits.length; i++)
     264        {
     265            let target = this.targetUnits[i];
     266            let preference = cmpAttack.GetPreference(target);
     267            let weight = 1;
     268            if (preference !== null && preference !== undefined)
     269            {
     270                // Lower preference scores indicate a higher preference so they should result in a higher weight.
     271                weight = 1 + this.g_MaxPreferenceBonus / (1 + preference);
     272            }
     273            targets.push(target, weight);
     274        }
     275        selectedIndex = targets.randomIndex()
     276        target = targets.itemAt(selectedIndex);
     277    }
     278    // now we hope there's a target
     279    if (target != INVALID_ENTITY)
     280    {
     281        let cmpUnitAI = Engine.QueryInterface(this.GetTurretParent(), IID_UnitAI);
     282   
     283        if (cmpUnitAI.order.data.target){
     284            target = cmpUnitAI.order.data.target
     285            let allowCapture = cmpUnitAI.order.data.allowCapture;
     286            this.TurnTowardsTarget(target);
     287            cmpAttack.PerformAttack(cmpUnitAI.order.data.attackType, target, this.entity);         
     288            this.g_LatestTarget = target;
     289        }
     290        else{
     291            this.TurnTowardsTarget(target);
     292            cmpAttack.PerformAttack(this.bestAttack, target, this.entity);
     293            this.g_LatestTarget = target;
     294        }
     295    }
     296};
     297
     298/**
     299 * Selection the animations for the  turret
     300 */
     301TurretAI.prototype.SelectAnimation = function(name, once = false, speed = 1.0, sound)
     302{
     303    var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     304    if (!cmpVisual)
     305        return;
     306
     307    var soundgroup;
     308    if (sound)
     309    {
     310        let cmpSound = Engine.QueryInterface(this.entity, IID_Sound);
     311        if (cmpSound)
     312            soundgroup = cmpSound.GetSoundGroup(sound);
     313    }
     314    cmpVisual.SelectAnimation(name, once, speed, soundgroup || "");
     315};
     316
     317/**
     318 * Synchronise Animations
     319 */
     320TurretAI.prototype.SetAnimationSync = function(actiontime, repeattime)
     321{
     322    var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     323    if (!cmpVisual)
     324        return;
     325
     326    cmpVisual.SetAnimationSyncRepeat(repeattime);
     327    cmpVisual.SetAnimationSyncOffset(actiontime);
     328};
     329
     330/**
     331 * Orient the turret toward his foe.
     332 */
     333TurretAI.prototype.TurnTowardsTarget = function(target)
     334{
     335    var cmpThisPosition = Engine.QueryInterface(this.entity, IID_Position);
     336    var cmpTargetPosition = Engine.QueryInterface(target, IID_Position);
     337    if (!cmpThisPosition || !cmpTargetPosition || !cmpThisPosition.IsInWorld() || !cmpTargetPosition.IsInWorld())
     338        return;
     339
     340    var pos = cmpTargetPosition.GetPosition2D().sub(cmpThisPosition.GetPosition2D());
     341    cmpThisPosition.TurnTo(Math.atan2(pos.x, pos.y));
     342};
     343
     344Engine.RegisterComponentType(IID_TurretAI, "TurretAI", TurretAI);
  • binaries/data/mods/public/simulation/components/TurretHolder.js

     
     1function TurretHolder() {}
     2
     3TurretHolder.prototype.Schema =
     4    "<element name='TurretPoints'>" +
     5        "<zeroOrMore>" +
     6            "<element a:help='Element containing the offset coordinates and the template'>" +
     7                "<anyName/>" +
     8                "<interleave>" +
     9                    "<element name='Template'>" +
     10                        "<text/>" +
     11                    "</element>" +
     12                    "<element name='X'>" +
     13                        "<data type='decimal'/>" +
     14                    "</element>" +
     15                    "<element name='Y'>" +
     16                        "<data type='decimal'/>" +
     17                    "</element>" +
     18                    "<element name='Z'>" +
     19                        "<data type='decimal'/>" +
     20                    "</element>" +
     21                "</interleave>" +
     22            "</element>" +
     23        "</zeroOrMore>" +
     24    "</element>";
     25
     26/**
     27 * Initialize TurretHolder Component.
     28 */
     29TurretHolder.prototype.Init = function()
     30{
     31    this.turrets = [];
     32    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     33    // hack for atlas, don't create the turrets in Atlas, as the references get lost
     34    // TODO implement some sort of tag for the turrets so they never get saved by Atlas
     35/*  if (cmpTimer.GetTime() == 0)
     36        cmpTimer.SetTimeout(this.entity, IID_TurretHolder, "CreateTurrets", 100, null);
     37    else*/
     38        this.CreateTurrets();
     39};
     40
     41/**
     42 * Create the Turrets.
     43 */
     44TurretHolder.prototype.CreateTurrets = function()
     45{
     46    for each (let turretPoint in this.template.TurretPoints)
     47    {
     48        var ent = Engine.AddEntity(turretPoint.Template);
     49        var offset = new Vector3D(+turretPoint.X, +turretPoint.Y, +turretPoint.Z);
     50        var cmpPosition = Engine.QueryInterface(ent, IID_Position);
     51        if (cmpPosition)
     52            cmpPosition.SetTurretParent(this.entity, offset);
     53        this.turrets.push(ent);
     54    }
     55    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     56    if (cmpOwnership && cmpOwnership.GetOwner() != -1)
     57        this.ChangeTurretOwnership(cmpOwnership.GetOwner());
     58};
     59
     60/**
     61 * Return the list of entities garrisoned inside.
     62 */
     63TurretHolder.prototype.GetTurrets = function()
     64{
     65    return this.turrets;
     66};
     67
     68/**
     69 * Destroys the entities.
     70 */
     71TurretHolder.prototype.OnDestroy = function()
     72{
     73    for (let ent of this.turrets)
     74        Engine.DestroyEntity(ent);
     75};
     76
     77/**
     78 * Change the ownership of the turret.
     79 */
     80TurretHolder.prototype.OnOwnershipChanged = function(msg)
     81{
     82    this.ChangeTurretOwnership(msg.to);
     83};
     84
     85/**
     86 * Set the ownership of all present turrets to the same owner.
     87 */
     88TurretHolder.prototype.ChangeTurretOwnership = function(owner)
     89{
     90    for (let ent of this.turrets)
     91    {
     92        var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
     93        if (cmpOwnership)
     94            cmpOwnership.SetOwner(owner);
     95    }
     96};
     97
     98Engine.RegisterComponentType(IID_TurretHolder, "TurretHolder", TurretHolder);
     99
  • binaries/data/mods/public/simulation/templates/template_turret.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_entity_full">
     3    <Decay>
     4        <Active>false</Active>
     5        <SinkingAnim>false</SinkingAnim>
     6        <DelayTime>80.0</DelayTime>
     7        <SinkRate>0.01</SinkRate>
     8        <SinkAccel>0.0</SinkAccel>
     9    </Decay>
     10    <Minimap>
     11        <Type>unit</Type>
     12    </Minimap>
     13    <OverlayRenderer/>
     14    <Selectable disable=""/>
     15    <Sound>
     16        <SoundGroups>
     17            <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
     18        </SoundGroups>
     19    </Sound>
     20    <TurretAI/>
     21    <Visibility>
     22        <RetainInFog>false</RetainInFog>
     23        <AlwaysVisible>false</AlwaysVisible>
     24        <Preview>true</Preview>
     25        <Corpse>true</Corpse>
     26    </Visibility>
     27  <Vision>
     28    <Range>100</Range>
     29  </Vision>
     30    <VisualActor>
     31        <SilhouetteDisplay>true</SilhouetteDisplay>
     32        <SilhouetteOccluder>false</SilhouetteOccluder>
     33        <VisibleInAtlasOnly>false</VisibleInAtlasOnly>
     34    </VisualActor>
     35</Entity>
  • binaries/data/mods/public/simulation/templates/units/brit_champion_cavalry.xml

    Property changes on: binaries/data/mods/public/simulation/templates/template_turret.xml
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/xml
    \ No newline at end of property
     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_unit_champion_cavalry_javelinist">
     3  <Attack>
     4    <Ranged>
     5      <TurretsOnly>true</TurretsOnly>
     6    </Ranged>
     7  </Attack>
    38  <Footprint replace="">
    49    <Square width="10.0" depth="10.0"/>
    510    <Height>5.0</Height>
     
    1318    <History>The Britons were one of the last European peoples to use two-horse chariots in combat. They had two iron-rimmed wheels and a flat riding platform that typically carried a driver and a warrior. Useless as shock weapons against tightly packed troops, they were useful for running down individual soldiers and as a stable mount to launch javelins from. The heads of defeated opponents often adorned the chassis to show the warrior's prowess.</History>
    1419    <Icon>units/celt_champion_cavalry_brit.png</Icon>
    1520  </Identity>
     21  <TurretHolder>
     22    <TurretPoints>
     23      <Archer>
     24        <Template>units/brit_champion_cavalry_r</Template>
     25        <X>0</X>
     26        <Y>1.4</Y>
     27        <Z>-2.5</Z>
     28      </Archer>
     29    </TurretPoints>
     30  </TurretHolder>
    1631  <VisualActor>
    1732    <Actor>units/celts/champion_unit_4.xml</Actor>
    1833  </VisualActor>
  • binaries/data/mods/public/simulation/templates/units/brit_champion_cavalry_r.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_turret">
     3  <VisualActor>
     4    <Actor>units/celts/champion_unit_4_r.xml</Actor>
     5  </VisualActor>
     6</Entity>
  • binaries/data/mods/public/simulation/templates/units/brit_hero_bouddica_r.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_turret">
     3  <VisualActor>
     4    <Actor>units/celts/boudicca_r2.xml</Actor>
     5  </VisualActor>
     6</Entity>
  • binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_unit_hero_cavalry_javelinist">
     3  <Attack>
     4    <Ranged>
     5      <TurretsOnly>true</TurretsOnly>
     6    </Ranged>
     7  </Attack>
    38  <Auras>
    49    <Aura1>
    510      <Type>global</Type>
     
    2631    <History>Ammianus Marcellinus described how difficult it would be for a band of foreigners to deal with a Celt if he called in the help of his wife. For she was stronger than he was and could rain blows and kicks upon the assailants equal in force to the shots of a catapult. Boudicca, queen of the Iceni, was said to be 'very tall and terrifying in appearance; her voice was very harsh and a great mass of red hair fell over her shoulders. She wore a tunic of many colors over which a thick cloak was fastened by a brooch.</History>
    2732    <Icon>units/celt_hero_boudicca.png</Icon>
    2833  </Identity>
     34    <TurretHolder>
     35        <TurretPoints>
     36            <Archer>
     37                <Template>units/brit_hero_bouddica_r</Template>
     38                    <X>0</X>
     39                    <Y>1.4</Y>
     40                    <Z>-2.5</Z>
     41            </Archer>
     42        </TurretPoints>
     43    </TurretHolder>
    2944  <VisualActor>
    3045    <Actor>units/celts/boudicca_chariot.xml</Actor>
    3146  </VisualActor>
  • binaries/data/mods/public/simulation/templates/units/maur_champion_maiden_r.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_turret">
     3  <VisualActor>
     4    <Actor>units/mauryans/hero_chariot_maiden_archer.xml</Actor>
     5  </VisualActor>
     6</Entity>
  • binaries/data/mods/public/simulation/templates/units/maur_hero_ashoka.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_unit_hero_cavalry_archer">
     3  <Attack>
     4    <Ranged>
     5      <TurretsOnly>true</TurretsOnly>
     6    </Ranged>
     7  </Attack>
    38  <Footprint replace="">
    49    <Square width="6.0" depth="12.0"/>
    510    <Height>5.0</Height>
     
    1520Hero Special: "Edicts of Ashoka" - Edict Pillars of Ashoka can be built during Ashoka's lifetime.</Tooltip>
    1621    <History>TBD.</History>
    1722  </Identity>
     23    <TurretHolder>
     24        <TurretPoints>
     25            <Archer1>
     26                <Template>units/maur_champion_maiden_r</Template>
     27                    <X>0.9</X>
     28                    <Y>1.4</Y>
     29                    <Z>-3</Z>
     30            </Archer1>
     31            <Archer2>
     32                <Template>units/maur_hero_ashoka_r</Template>
     33                    <X>-0.9</X>
     34                    <Y>1.4</Y>
     35                    <Z>-3</Z>
     36            </Archer2>
     37        </TurretPoints>
     38    </TurretHolder>
    1839  <VisualActor>
    1940    <Actor>units/mauryans/hero_chariot.xml</Actor>
    2041  </VisualActor>
  • binaries/data/mods/public/simulation/templates/units/maur_hero_ashoka_r.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_turret">
     3  <VisualActor>
     4    <Actor>units/mauryans/hero_ashoka_rider.xml</Actor>
     5  </VisualActor>
     6</Entity>
  • binaries/data/mods/public/simulation/templates/units/pers_cavalry_archer_a.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="units/pers_cavalry_archer_b">
     3  <Attack>
     4    <Ranged>
     5      <TurretsOnly>true</TurretsOnly>
     6    </Ranged>
     7  </Attack>
    38  <Identity>
    49    <Rank>Advanced</Rank>
    510  </Identity>
     
    611  <Promotion>
    712    <Entity>units/pers_cavalry_archer_e</Entity>
    813  </Promotion>
     14  <TurretHolder>
     15    <TurretPoints>
     16      <Archer>
     17        <Template>units/pers_cavalry_archer_rider_a</Template>
     18        <X>1</X>
     19         <Y>2.2</Y>
     20         <Z>-4.0</Z>
     21      </Archer>
     22    </TurretPoints>
     23  </TurretHolder>
    924  <VisualActor>
    1025    <Actor>units/persians/cavalry_archer_a.xml</Actor>
    1126  </VisualActor>
  • binaries/data/mods/public/simulation/templates/units/pers_cavalry_archer_e.xml

     
    44    <Rank>Elite</Rank>
    55  </Identity>
    66  <Promotion disable=""/>
     7  <TurretHolder>
     8    <TurretPoints>
     9      <Archer>
     10        <Template>units/pers_cavalry_archer_rider_e</Template>
     11        <X>1</X>
     12         <Y>2.2</Y>
     13         <Z>-4.0</Z>
     14      </Archer>
     15    </TurretPoints>
     16  </TurretHolder>
    717  <VisualActor>
    818    <Actor>units/persians/cavalry_archer_e.xml</Actor>
    919  </VisualActor>
  • binaries/data/mods/public/simulation/templates/units/pers_cavalry_archer_rider_a.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_turret">
     3  <VisualActor>
     4    <Actor>units/persians/cavalry_archer_a_r.xml</Actor>
     5  </VisualActor>
     6</Entity>
  • binaries/data/mods/public/simulation/templates/units/pers_cavalry_archer_rider_e.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_turret">
     3  <VisualActor>
     4    <Actor>units/persians/cavalry_archer_e_r.xml</Actor>
     5  </VisualActor>
     6</Entity>