Ticket #2577: turrets_scripted.diff

File turrets_scripted.diff, 21.3 KB (added by sanderd17, 10 years ago)
  • binaries/data/mods/public/art/actors/props/units/turret_ptol_champ_ele.xml

     
    55    <variant frequency="1" name="Ptolemaic elephant champion howdah gray">
    66      <mesh>props/ptol_howdah.dae</mesh>
    77      <props>
    8         <prop actor="units/seleucids/champion_elephant_rider1.xml" attachpoint="root"/>
     8        <!--<prop actor="units/seleucids/champion_elephant_rider1.xml" attachpoint="root"/>-->
    99        <prop actor="props/units/shields/ptol_hero_1.xml" attachpoint="shield1"/>
    1010        <prop actor="props/units/shields/ptol_hero_1.xml" attachpoint="shield2"/>
    1111      </props>
     
    1818    <variant frequency="1" name="Ptolemaic elephant champion howdah brown">
    1919      <mesh>props/ptol_howdah.dae</mesh>
    2020      <props>
    21         <prop actor="units/seleucids/champion_elephant_rider1.xml" attachpoint="root"/>
     21        <!--<prop actor="units/seleucids/champion_elephant_rider1.xml" attachpoint="root"/>-->
    2222        <prop actor="props/units/shields/ptol_hero_2.xml" attachpoint="shield1"/>
    2323        <prop actor="props/units/shields/ptol_hero_2.xml" attachpoint="shield2"/>
    2424      </props>
     
    3131    <variant frequency="1" name="Ptolemaic elephant champion howdah white">
    3232      <mesh>props/ptol_howdah.dae</mesh>
    3333      <props>
    34         <prop actor="units/seleucids/champion_elephant_rider1.xml" attachpoint="root"/>
     34        <!--<prop actor="units/seleucids/champion_elephant_rider1.xml" attachpoint="root"/>-->
    3535        <prop actor="props/units/shields/ptol_hero_1.xml" attachpoint="shield1"/>
    3636        <prop actor="props/units/shields/ptol_hero_1.xml" attachpoint="shield2"/>
    3737      </props>
  • binaries/data/mods/public/simulation/components/TurretAI.js

     
    1 //Number of rounds of firing per 2 seconds
    2 const roundCount = 10;
    3 const attackType = "Ranged";
     1function TurretAI() {}
    42
    5 function BuildingAI() {}
     3TurretAI.prototype.Schema =
     4    "<empty/>";
    65
    7 BuildingAI.prototype.Schema =
    8     "<element name='DefaultArrowCount'>" +
    9         "<data type='nonNegativeInteger'/>" +
    10     "</element>" +
    11     "<element name='GarrisonArrowMultiplier'>" +
    12         "<ref name='nonNegativeDecimal'/>" +
    13     "</element>" +
    14     "<element name='GarrisonArrowClasses'>" +
    15         "<text/>" +
    16     "</element>";
     6TurretAI.prototype.MAX_PREFERENCE_BONUS = 2;
    177
    18 BuildingAI.prototype.MAX_PREFERENCE_BONUS = 2;
    19 
    208/**
    21  * Initialize BuildingAI Component
     9 * Initialize TurretAI Component
    2210 */
    23 BuildingAI.prototype.Init = function()
     11TurretAI.prototype.Init = function()
    2412{
    25     if (this.GetDefaultArrowCount() > 0 || this.GetGarrisonArrowMultiplier() > 0)
    26     {
    27         this.currentRound = 0;
    28         //Arrows left to fire
    29         this.arrowsLeft = 0;
    30         this.targetUnits = [];
    31     }
     13    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
     14    if (!cmpAttack)
     15        return;
     16    this.bestAttack = cmpAttack.GetBestAttack();
    3217};
    3318
    34 BuildingAI.prototype.OnOwnershipChanged = function(msg)
     19TurretAI.prototype.OnOwnershipChanged = function(msg)
    3520{
    3621    // Remove current targets, to prevent them from being added twice
    3722    this.targetUnits = [];
     
    4429        this.SetupGaiaRangeQuery(msg.to);
    4530};
    4631
    47 BuildingAI.prototype.OnDiplomacyChanged = function(msg)
     32TurretAI.prototype.OnDiplomacyChanged = function(msg)
    4833{
    4934    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    5035    if (cmpOwnership && cmpOwnership.GetOwner() == msg.player)
     
    5843/**
    5944 * Cleanup on destroy
    6045 */
    61 BuildingAI.prototype.OnDestroy = function()
     46TurretAI.prototype.OnDestroy = function()
    6247{
    6348    if (this.timer)
    6449    {
     
    7863/**
    7964 * Setup the Range Query to detect units coming in & out of range
    8065 */
    81 BuildingAI.prototype.SetupRangeQuery = function(owner)
     66TurretAI.prototype.SetupRangeQuery = function(owner)
    8267{
    8368    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    8469    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     
    10388            players.push(i);
    10489    }
    10590
    106     var range = cmpAttack.GetRange(attackType);
     91    var range = cmpAttack.GetRange(this.bestAttack);
    10792    this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(this.entity, range.min, range.max, range.elevationBonus, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
    10893    cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
    10994};
     
    11095
    11196// Set up a range query for Gaia units within LOS range which can be attacked.
    11297// This should be called whenever our ownership changes.
    113 BuildingAI.prototype.SetupGaiaRangeQuery = function()
     98TurretAI.prototype.SetupGaiaRangeQuery = function()
    11499{
    115100    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    116101    var owner = cmpOwnership.GetOwner();
     
    134119    if (!cmpPlayer.IsEnemy(0))
    135120        return;
    136121
    137     var range = cmpAttack.GetRange(attackType);
     122    var range = cmpAttack.GetRange(this.bestAttack);
    138123
    139124    // This query is only interested in Gaia entities that can attack.
    140125    this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(this.entity, range.min, range.max, range.elevationBonus, [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
     
    144129/**
    145130 * Called when units enter or leave range
    146131 */
    147 BuildingAI.prototype.OnRangeUpdate = function(msg)
     132TurretAI.prototype.OnRangeUpdate = function(msg)
    148133{
    149134
    150135    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
     
    190175    if (!this.targetUnits.length || this.timer)
    191176        return;
    192177
     178    var attackTimers = cmpAttack.GetTimers(this.bestAttack);
     179    this.SelectAnimation("attack_" + this.bestAttack.toLowerCase(), false, 1.0, "attack");
     180    this.SetAnimationSync(attackTimers.prepare, attackTimers.repeat);
    193181    // units entered the range, prepare to shoot
    194182    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    195     var attackTimers = cmpAttack.GetTimers(attackType);
    196     this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows", attackTimers.prepare, attackTimers.repeat / roundCount, null);
     183    this.timer = cmpTimer.SetInterval(this.entity, IID_TurretAI, "Attack", attackTimers.prepare, attackTimers.repeat, null);
    197184};
    198185
    199 BuildingAI.prototype.GetDefaultArrowCount = function()
     186TurretAI.prototype.Attack = function()
    200187{
    201     var arrowCount = +this.template.DefaultArrowCount;
    202     return ApplyValueModificationsToEntity("BuildingAI/DefaultArrowCount", arrowCount, this.entity);
    203 };
    204 
    205 BuildingAI.prototype.GetGarrisonArrowMultiplier = function()
    206 {
    207     var arrowMult = +this.template.GarrisonArrowMultiplier;
    208     return ApplyValueModificationsToEntity("BuildingAI/GarrisonArrowMultiplier", arrowMult, this.entity);
    209 };
    210 
    211 BuildingAI.prototype.GetGarrisonArrowClasses = function()
    212 {
    213     var string = this.template.GarrisonArrowClasses;
    214     if (string)
    215         return string.split(/\s+/);
    216     return [];
    217 };
    218 
    219 /**
    220  * Returns the number of arrows which needs to be fired.
    221  * DefaultArrowCount + Garrisoned Archers(ie., any unit capable
    222  * of shooting arrows from inside buildings)
    223  */
    224 BuildingAI.prototype.GetArrowCount = function()
    225 {
    226     var count = this.GetDefaultArrowCount();
    227     var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
    228     if (cmpGarrisonHolder)
    229     {
    230         count += Math.round(cmpGarrisonHolder.GetGarrisonedArcherCount(this.GetGarrisonArrowClasses()) * this.GetGarrisonArrowMultiplier());
    231     }
    232     return count;
    233 };
    234 
    235 /**
    236  * Fires arrows. Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range
    237  */
    238 BuildingAI.prototype.FireArrows = function()
    239 {
    240188    if (!this.targetUnits.length)
    241189    {
    242190        if (this.timer)
     
    246194            cmpTimer.CancelTimer(this.timer);
    247195            this.timer = undefined;
    248196        }
     197        this.SelectAnimation("idle");
    249198        return;
    250199    }
    251200
     
    252201    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
    253202    if (!cmpAttack)
    254203        return;
    255 
    256     var arrowsToFire = 0;
    257     if (this.currentRound > (roundCount - 1))
     204    while (true)
    258205    {
    259         //Reached end of rounds. Reset count
    260         this.currentRound = 0;
    261     }
    262    
    263     if (this.currentRound == 0)
    264     {
    265         //First round. Calculate arrows to fire
    266         this.arrowsLeft = this.GetArrowCount();
    267     }
    268    
    269     if (this.currentRound == (roundCount - 1))
    270     {
    271         //Last round. Need to fire all left-over arrows
    272         arrowsToFire = this.arrowsLeft;
    273     }
    274     else
    275     {
    276         //Fire N arrows, 0 <= N <= Number of arrows left
    277         arrowsToFire = Math.min(
    278             Math.round(2*Math.random() * this.GetArrowCount()/roundCount), 
    279             this.arrowsLeft
    280         );
    281     }
    282     if (arrowsToFire <= 0)
    283     {
    284         this.currentRound++;
    285         return;
    286     }
    287     var targets = new WeightedList();
    288     for (var i = 0; i < this.targetUnits.length; i++)
    289     {
    290         var target = this.targetUnits[i];
    291         var preference = cmpAttack.GetPreference(target);
    292         var weight = 1;
    293         if (preference !== null && preference !== undefined)
     206        var selectedIndex = -1;
     207        // if we had a target, stick to it
     208        if (!this.target || this.targetUnits.indexOf(this.target) == -1)
    294209        {
    295             // Lower preference scores indicate a higher preference so they
    296             // should result in a higher weight.
    297             weight = 1 + this.MAX_PREFERENCE_BONUS / (1 + preference);
     210            var targets = new WeightedList();
     211            for (var i = 0; i < this.targetUnits.length; i++)
     212            {
     213                var target = this.targetUnits[i];
     214                var preference = cmpAttack.GetPreference(target);
     215                var weight = 1;
     216                if (preference !== null && preference !== undefined)
     217                {
     218                    // Lower preference scores indicate a higher preference so they
     219                    // should result in a higher weight.
     220                    weight = 1 + this.MAX_PREFERENCE_BONUS / (1 + preference);
     221                }
     222                targets.push(target, weight);
     223            }
     224            selectedIndex = targets.randomIndex()
     225            this.target = targets.itemAt(selectedIndex);
    298226        }
    299         targets.push(target, weight);
    300     }
    301     for (var i = 0;i < arrowsToFire;i++)
    302     {
    303         var selectedIndex = targets.randomIndex();
    304         var selectedTarget = targets.itemAt(selectedIndex);
    305         if (selectedTarget && this.CheckTargetVisible(selectedTarget))
     227        if (this.target && this.CheckTargetVisible(this.target))
    306228        {
    307             cmpAttack.PerformAttack(attackType, selectedTarget);
    308             PlaySound("attack", this.entity);
     229            this.TurnTowardsTarget();
     230            cmpAttack.PerformAttack(this.bestAttack, this.target);
     231            break;
    309232        }
    310233        else
    311234        {
    312             targets.removeAt(selectedIndex);
    313             i--; // one extra arrow left to fire
    314             if(targets.length() < 1)
     235            this.target = 0;
     236            if (selectedIndex != -1)
    315237            {
    316                 this.arrowsLeft += arrowsToFire;
    317                 // no targets found in this round, save arrows and go to next round
    318                 break;
     238                targets.removeAt(selectedIndex);
     239                if(targets.length() < 1)
     240                    break;
    319241            }
    320242        }
    321243    }
    322 
    323     this.arrowsLeft -= arrowsToFire;
    324     this.currentRound++;
    325244};
    326245
    327246/**
    328247 * Returns true if the target entity is visible through the FoW/SoD.
    329248 */
    330 BuildingAI.prototype.CheckTargetVisible = function(target)
     249TurretAI.prototype.CheckTargetVisible = function(target)
    331250{
    332251    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    333252    if (!cmpOwnership)
     
    342261    return true;
    343262};
    344263
    345 Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI);
     264TurretAI.prototype.SelectAnimation = function(name, once, speed, sound)
     265{
     266    var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     267    if (!cmpVisual)
     268        return;
     269
     270    var soundgroup;
     271    if (sound)
     272    {
     273        var cmpSound = Engine.QueryInterface(this.entity, IID_Sound);
     274        if (cmpSound)
     275            soundgroup = cmpSound.GetSoundGroup(sound);
     276    }
     277
     278    // Set default values if unspecified
     279    if (once === undefined)
     280        once = false;
     281    if (speed === undefined)
     282        speed = 1.0;
     283    if (soundgroup === undefined)
     284        soundgroup = "";
     285
     286    cmpVisual.SelectAnimation(name, once, speed, soundgroup);
     287};
     288
     289TurretAI.prototype.SetAnimationSync = function(actiontime, repeattime)
     290{
     291    var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     292    if (!cmpVisual)
     293        return;
     294
     295    cmpVisual.SetAnimationSyncRepeat(repeattime);
     296    cmpVisual.SetAnimationSyncOffset(actiontime);
     297};
     298
     299TurretAI.prototype.TurnTowardsTarget = function()
     300{
     301    var cmpThisPosition = Engine.QueryInterface(this.entity, IID_Position);
     302    var cmpTargetPosition = Engine.QueryInterface(this.target, IID_Position);
     303    if (!cmpThisPosition || !cmpTargetPosition || !cmpThisPosition.IsInWorld() || !cmpTargetPosition.IsInWorld())
     304        return;
     305
     306    var pos = cmpTargetPosition.GetPosition2D().sub(cmpThisPosition.GetPosition2D());
     307    cmpThisPosition.TurnTo(Math.atan2(pos.x, pos.y));
     308};
     309
     310Engine.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/*  if (cmpTimer.GetTime() == 0)
     34        cmpTimer.SetTimeout(
     35    else*/
     36        this.CreateTurrets();
     37};
     38
     39TurretHolder.prototype.CreateTurrets = function()
     40{
     41    for each (var turretPoint in this.template.TurretPoints)
     42    {
     43        var ent = Engine.AddEntity(turretPoint.Template);
     44        var offset = new Vector3D(+turretPoint.X, +turretPoint.Y, +turretPoint.Z);
     45        var cmpPosition = Engine.QueryInterface(ent, IID_Position);
     46        if (cmpPosition)
     47            cmpPosition.SetTurretParent(this.entity, offset);
     48        this.turrets.push(ent);
     49    }
     50    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     51    if (cmpOwnership && cmpOwnership.GetOwner() != -1)
     52        this.ChangeTurretOwnership(cmpOwnership.GetOwner());
     53};
     54
     55/**
     56 * Return the list of entities garrisoned inside
     57 */
     58TurretHolder.prototype.GetTurrets = function()
     59{
     60    return this.turrets;
     61};
     62
     63TurretHolder.prototype.OnDestroy = function()
     64{
     65    for (var ent of this.turrets)
     66        Engine.DestroyEntity(ent);
     67};
     68
     69TurretHolder.prototype.OnOwnershipChanged = function(msg)
     70{
     71    this.ChangeTurretOwnership(msg.to);
     72};
     73
     74/**
     75 * Set the ownership of all present turrets to the same owner
     76 */
     77TurretHolder.prototype.ChangeTurretOwnership = function(owner)
     78{
     79    for (var ent of this.turrets)
     80    {
     81        var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
     82        if (cmpOwnership)
     83            cmpOwnership.SetOwner(owner);
     84    }
     85};
     86
     87Engine.RegisterComponentType(IID_TurretHolder, "TurretHolder", TurretHolder);
     88
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    42744274        return false;
    42754275    var range = cmpGarrisonHolder.GetLoadingRange();
    42764276
     4277    var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
     4278    if (cmpObstruction)
     4279        range.max += cmpObstruction.GetUnitRadius()*1.5; // multiply by something larger than sqrt(2)
     4280
    42774281    var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);
    42784282    return cmpUnitMotion.MoveToTargetRange(target, range.min, range.max);
    42794283};
  • binaries/data/mods/public/simulation/components/interfaces/TurretAI.js

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

     
     1Engine.RegisterInterface("TurretHolder");
     2
  • 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    <Inactive/>
     5    <DelayTime>80.0</DelayTime>
     6    <SinkRate>0.01</SinkRate>
     7    <SinkAccel>0.0</SinkAccel>
     8  </Decay>
     9  <Identity>
     10    <GenericName>Unit</GenericName>
     11    <Classes datatype="tokens">Turret</Classes>
     12  </Identity>
     13  <Looter/>
     14  <Minimap>
     15    <Type>unit</Type>
     16  </Minimap>
     17  <OverlayRenderer/>
     18  <Selectable>
     19    <Overlay>
     20      <Texture>
     21        <MainTexture>circle/128x128.png</MainTexture>
     22        <MainTextureMask>circle/128x128_mask.png</MainTextureMask>
     23      </Texture>
     24    </Overlay>
     25  </Selectable>
     26  <Sound>
     27    <SoundGroups>
     28      <attacked>interface/alarm/alarm_attackplayer.xml</attacked>
     29    </SoundGroups>
     30  </Sound>
     31  <StatusBars>
     32    <BarWidth>2.0</BarWidth>
     33    <BarHeight>0.333</BarHeight>
     34    <HeightOffset>5.0</HeightOffset>
     35  </StatusBars>
     36  <TurretAI/>
     37  <Vision>
     38    <Range>60</Range>
     39    <RetainInFog>false</RetainInFog>
     40    <AlwaysVisible>false</AlwaysVisible>
     41  </Vision>
     42  <VisualActor>
     43    <SilhouetteDisplay>true</SilhouetteDisplay>
     44    <SilhouetteOccluder>false</SilhouetteOccluder>
     45    <VisibleInAtlasOnly>false</VisibleInAtlasOnly>
     46  </VisualActor>
     47</Entity>
  • binaries/data/mods/public/simulation/templates/units/sele_champion_elephant.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
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_unit_champion_elephant_melee">
     3  <TurretHolder>
     4    <TurretPoints>
     5      <Pike>
     6        <Template>units/sele_champion_elephant_turret</Template>
     7        <X>0</X><Y>7</Y><Z>0</Z>
     8      </Pike>
     9    </TurretPoints>
     10  </TurretHolder>
    311  <Identity>
    412    <Civ>sele</Civ>
    513    <GenericName>Armored War Elephant</GenericName>
     
    1119  <VisualActor>
    1220    <Actor>units/seleucids/champion_elephant.xml</Actor>
    1321  </VisualActor>
    14 </Entity>
    15  No newline at end of file
     22</Entity>
  • binaries/data/mods/public/simulation/templates/units/sele_champion_elephant_turret.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    2 <Entity parent="template_unit_champion_infantry_pikeman">
     2<Entity parent="template_turret">
     3   <Attack>
     4    <Melee>
     5      <Hack>10.0</Hack>
     6      <Pierce>0.0</Pierce>
     7      <Crush>0.0</Crush>
     8      <MaxRange>20.0</MaxRange>
     9      <RepeatTime>1000</RepeatTime>
     10      <Bonuses>
     11        <BonusCavalry>
     12          <Classes>Cavalry</Classes>
     13          <Multiplier>2.0</Multiplier>
     14        </BonusCavalry>
     15        <BonusEles>
     16          <Classes>Elephant</Classes>
     17          <Multiplier>1.5</Multiplier>
     18        </BonusEles>
     19      </Bonuses>
     20    </Melee>
     21  </Attack>
    322  <Identity>
    423    <Civ>sele</Civ>
    524    <GenericName>Silver Shield Pikeman</GenericName>
     
    827    <Icon>units/sele_champion_infantry_pikeman.png</Icon>
    928    <RequiredTechnology>successors/unlock_traditional_army</RequiredTechnology>
    1029  </Identity>
     30  <Sound>
     31    <SoundGroups>
     32      <select>voice/hellenes/civ/civ_male_select.xml</select>
     33      <order_walk>voice/hellenes/civ/civ_male_ack.xml</order_walk>
     34      <order_attack>voice/hellenes/civ/civ_male_attack.xml</order_attack>
     35      <order_gather>voice/hellenes/civ/civ_male_ack.xml</order_gather>
     36      <order_repair>voice/hellenes/civ/civ_male_ack.xml</order_repair>
     37      <walk>actor/human/movement/walk.xml</walk>
     38      <run>actor/human/movement/walk.xml</run>
     39      <attack>attack/weapon/sword.xml</attack>
     40      <death>actor/human/death/death.xml</death>
     41    </SoundGroups>
     42  </Sound>
    1143  <VisualActor>
    1244    <Actor>units/seleucids/champion_infantry_pikeman.xml</Actor>
    1345  </VisualActor>