Ticket #252: t252_secondattack_7.diff

File t252_secondattack_7.diff, 112.9 KB (added by bb, 8 years ago)
  • binaries/data/config/default.cfg

     
    274274[hotkey.session]
    275275kill = Delete                ; Destroy selected units
    276276stop = "H"                   ; Stop the current action
    277 attack = Ctrl                ; Modifier to attack instead of another action (eg capture)
    278 attackmove = Ctrl            ; Modifier to attackmove when clicking on a point
    279 attackmoveUnit = "Ctrl+Q"    ; Modifier to attackmove targeting only units when clicking on a point (should contain the attackmove keys)
     277attack = Ctrl                ; Modifier to primary attack instead of another action (eg capture)
     278attackmove = Ctrl            ; Modifier to primary attackmove when clicking on a point
     279attackmoveUnit = "Ctrl+Q"    ; Modifier to primary attackmove targeting only units when clicking on a point (should contain the attackmove keys)
    280280garrison = Ctrl              ; Modifier to garrison when clicking on building
    281281autorallypoint = Ctrl        ; Modifier to set the rally point on the building itself
     282meleeattack = Alt            ; Modifier to melee attack instead of another action
     283meleeattackmove = Alt        ; Modifier to melee attackmove when clicking on a point
     284meleeattackmoveUnit = "Alt+Q"; Modifier to melee attackmove targeting only units when clicking on a point
     285rangedattack = space         ; Modifier to ranged attack instead of another action
     286rangedattackmove = space     ; Modifier to ranged attackmove when clicking on a point
     287rangedattackmoveUnit = "space+Q"; Modifier to ranged attackmove targeting only units when clicking on a point
    282288guard = "G"                  ; Modifier to escort/guard when clicking on unit/building
    283289queue = Shift                ; Modifier to queue unit orders instead of replacing
    284290batchtrain = Shift           ; Modifier to train units in batches
  • binaries/data/mods/public/art/actors/units/athenians/infantry_archer_a.xml

     
    3030  <group>
    3131    <variant frequency="100" name="Idle"/>
    3232    <variant file="biped/attack_ranged_archer.xml"/>
     33    <variant file="biped/attack_melee_ranged.xml"/>
    3334    <variant file="biped/attack_capture.xml"/>
    3435    <variant file="biped/attack_slaughter.xml"/>
    3536    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_archer_b.xml

     
    2222  <group>
    2323    <variant frequency="100" name="Idle"/>
    2424    <variant file="biped/attack_ranged_archer.xml"/>
     25    <variant file="biped/attack_melee_ranged.xml"/>
    2526    <variant file="biped/attack_capture.xml"/>
    2627    <variant file="biped/attack_slaughter.xml"/>
    2728    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_archer_e.xml

     
    2323  <group>
    2424    <variant frequency="100" name="Idle"/>
    2525    <variant file="biped/attack_ranged_archer.xml"/>
     26    <variant file="biped/attack_melee_ranged.xml"/>
    2627    <variant file="biped/attack_capture.xml"/>
    2728    <variant file="biped/attack_slaughter.xml"/>
    2829    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_javelinist_a.xml

     
    3939  <group>
    4040    <variant frequency="100" name="Idle"/>
    4141    <variant file="biped/attack_ranged_javelinist.xml"/>
     42    <variant file="biped/attack_melee_ranged.xml"/>
    4243    <variant file="biped/attack_capture.xml"/>
    4344    <variant file="biped/attack_slaughter.xml"/>
    4445    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_javelinist_b.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_javelinist.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_javelinist_e.xml

     
    3636  <group>
    3737    <variant frequency="100" name="Idle"/>
    3838    <variant file="biped/attack_ranged_javelinist.xml"/>
     39    <variant file="biped/attack_melee_ranged.xml"/>
    3940    <variant file="biped/attack_capture.xml"/>
    4041    <variant file="biped/attack_slaughter.xml"/>
    4142    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_slinger_a.xml

     
    2626  <group>
    2727    <variant frequency="1" name="Idle"/>
    2828    <variant file="biped/attack_ranged_slinger.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_slinger_b.xml

     
    2222  <group>
    2323    <variant frequency="1" name="Idle"/>
    2424    <variant file="biped/attack_ranged_slinger.xml"/>
     25    <variant file="biped/attack_melee_ranged.xml"/>
    2526    <variant file="biped/attack_capture.xml"/>
    2627    <variant file="biped/attack_slaughter.xml"/>
    2728    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_slinger_e.xml

     
    2323  <group>
    2424    <variant frequency="1" name="Idle"/>
    2525    <variant file="biped/attack_ranged_slinger.xml"/>
     26    <variant file="biped/attack_melee_ranged.xml"/>
    2627    <variant file="biped/attack_capture.xml"/>
    2728    <variant file="biped/attack_slaughter.xml"/>
    2829    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_archer_a.xml

     
    2323  <group>
    2424    <variant frequency="100" name="Idle"/>
    2525    <variant file="biped/attack_ranged_archer.xml"/>
     26    <variant file="biped/attack_melee_ranged.xml"/>
    2627    <variant file="biped/attack_capture.xml"/>
    2728    <variant file="biped/attack_slaughter.xml"/>
    2829    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_archer_b.xml

     
    2222  <group>
    2323    <variant frequency="100" name="Idle"/>
    2424    <variant file="biped/attack_ranged_archer.xml"/>
     25    <variant file="biped/attack_melee_ranged.xml"/>
    2526    <variant file="biped/attack_capture.xml"/>
    2627    <variant file="biped/attack_slaughter.xml"/>
    2728    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_archer_e.xml

     
    2424  <group>
    2525    <variant frequency="100" name="Idle"/>
    2626    <variant file="biped/attack_ranged_archer.xml"/>
     27    <variant file="biped/attack_melee_ranged.xml"/>
    2728    <variant file="biped/attack_capture.xml"/>
    2829    <variant file="biped/attack_slaughter.xml"/>
    2930    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_javelinist_a.xml

     
    2626  <group>
    2727    <variant frequency="100" name="Idle"/>
    2828    <variant file="biped/attack_ranged_javelinist.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_javelinist_b.xml

     
    3131  <group>
    3232    <variant frequency="100" name="Idle"/>
    3333    <variant file="biped/attack_ranged_javelinist.xml"/>
     34    <variant file="biped/attack_melee_ranged.xml"/>
    3435    <variant file="biped/attack_capture.xml"/>
    3536    <variant file="biped/attack_slaughter.xml"/>
    3637    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_javelinist_e.xml

     
    2626  <group>
    2727    <variant frequency="100" name="Idle"/>
    2828    <variant file="biped/attack_ranged_javelinist.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_slinger_a.xml

     
    2727  <group>
    2828    <variant frequency="1" name="Idle"/>
    2929    <variant file="biped/attack_ranged_slinger.xml"/>
     30    <variant file="biped/attack_melee_ranged.xml"/>
    3031    <variant file="biped/attack_capture.xml"/>
    3132    <variant file="biped/attack_slaughter.xml"/>
    3233    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_slinger_b.xml

     
    2929  <group>
    3030    <variant frequency="1" name="Idle"/>
    3131    <variant file="biped/attack_ranged_slinger.xml"/>
     32    <variant file="biped/attack_melee_ranged.xml"/>
    3233    <variant file="biped/attack_capture.xml"/>
    3334    <variant file="biped/attack_slaughter.xml"/>
    3435    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_slinger_e.xml

     
    2828  <group>
    2929    <variant frequency="1" name="Idle"/>
    3030    <variant file="biped/attack_ranged_slinger.xml"/>
     31    <variant file="biped/attack_melee_ranged.xml"/>
    3132    <variant file="biped/attack_capture.xml"/>
    3233    <variant file="biped/attack_slaughter.xml"/>
    3334    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_swordsman_2_a.xml

     
    4545  <group>
    4646    <variant frequency="1" name="Idle"/>
    4747    <variant file="biped/attack_melee_swordsman.xml"/>
     48    <variant file="biped/attack_ranged_javelinist.xml">
     49      <props>
     50        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     51        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     52      </props>
     53    </variant>
    4854    <variant file="biped/attack_capture.xml"/>
    4955    <variant file="biped/attack_slaughter.xml"/>
    5056    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_swordsman_2_b.xml

     
    3838  <group>
    3939    <variant frequency="100" name="Idle"/>
    4040    <variant file="biped/attack_melee_swordsman.xml"/>
     41    <variant file="biped/attack_ranged_javelinist.xml">
     42      <props>
     43        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     44        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     45      </props>
     46    </variant>
    4147    <variant file="biped/attack_capture.xml"/>
    4248    <variant file="biped/attack_slaughter.xml"/>
    4349    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/infantry_swordsman_2_e.xml

     
    5353  <group>
    5454    <variant frequency="1" name="Idle"/>
    5555    <variant file="biped/attack_melee_swordsman.xml"/>
     56    <variant file="biped/attack_ranged_javelinist.xml">
     57      <props>
     58        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     59        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     60      </props>
     61    </variant>
    5662    <variant file="biped/attack_capture.xml"/>
    5763    <variant file="biped/attack_slaughter.xml"/>
    5864    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/carthaginians/samnite_swordsman.xml

     
    4646  <group>
    4747    <variant frequency="1" name="Idle"/>
    4848    <variant file="biped/attack_capture.xml"/>
     49    <variant file="biped/attack_ranged_javelinist.xml">
     50      <props>
     51        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     52        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     53      </props>
     54    </variant>
    4955    <variant file="biped/attack_slaughter.xml"/>
    5056    <variant file="biped/gather_tree.xml"/>
    5157    <variant file="biped/gather_grain.xml"/>
  • binaries/data/mods/public/art/actors/units/celts/infantry_javelinist_a.xml

     
    6161  <group>
    6262    <variant frequency="100" name="Idle"/>
    6363    <variant file="biped/attack_ranged_javelinist.xml"/>
     64    <variant file="biped/attack_melee_ranged.xml"/>
    6465    <variant file="biped/attack_capture.xml"/>
    6566    <variant file="biped/attack_slaughter.xml"/>
    6667    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/celts/infantry_javelinist_b.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_javelinist.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/celts/infantry_javelinist_e.xml

     
    4646  <group>
    4747    <variant frequency="100" name="Idle"/>
    4848    <variant file="biped/attack_ranged_javelinist.xml"/>
     49    <variant file="biped/attack_melee_ranged.xml"/>
    4950    <variant file="biped/attack_capture.xml"/>
    5051    <variant file="biped/attack_slaughter.xml"/>
    5152    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/celts/infantry_slinger_a.xml

     
    5858  <group>
    5959    <variant frequency="100" name="Idle"/>
    6060    <variant file="biped/attack_ranged_slinger.xml"/>
     61    <variant file="biped/attack_melee_ranged.xml"/>
    6162    <variant file="biped/attack_capture.xml"/>
    6263    <variant file="biped/attack_slaughter.xml"/>
    6364    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/celts/infantry_slinger_b.xml

     
    2323  <group>
    2424    <variant frequency="100" name="Idle"/>
    2525    <variant file="biped/attack_ranged_slinger.xml"/>
     26    <variant file="biped/attack_melee_ranged.xml"/>
    2627    <variant file="biped/attack_capture.xml"/>
    2728    <variant file="biped/attack_slaughter.xml"/>
    2829    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/celts/infantry_slinger_e.xml

     
    4646  <group>
    4747    <variant frequency="100" name="Idle"/>
    4848    <variant file="biped/attack_ranged_slinger.xml"/>
     49    <variant file="biped/attack_melee_ranged.xml"/>
    4950    <variant file="biped/attack_capture.xml"/>
    5051    <variant file="biped/attack_slaughter.xml"/>
    5152    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_archer_a.xml

     
    3030  <group>
    3131    <variant frequency="100" name="Idle"/>
    3232    <variant file="biped/attack_ranged_archer.xml"/>
     33    <variant file="biped/attack_melee_ranged.xml"/>
    3334    <variant file="biped/attack_capture.xml"/>
    3435    <variant file="biped/attack_slaughter.xml"/>
    3536    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_archer_b.xml

     
    2222  <group>
    2323    <variant frequency="100" name="Idle"/>
    2424    <variant file="biped/attack_ranged_archer.xml"/>
     25    <variant file="biped/attack_melee_ranged.xml"/>
    2526    <variant file="biped/attack_capture.xml"/>
    2627    <variant file="biped/attack_slaughter.xml"/>
    2728    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_archer_e.xml

     
    2323  <group>
    2424    <variant frequency="100" name="Idle"/>
    2525    <variant file="biped/attack_ranged_archer.xml"/>
     26    <variant file="biped/attack_melee_ranged.xml"/>
    2627    <variant file="biped/attack_capture.xml"/>
    2728    <variant file="biped/attack_slaughter.xml"/>
    2829    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_javelinist_a.xml

     
    4040  <group>
    4141    <variant frequency="100" name="Idle"/>
    4242    <variant file="biped/attack_ranged_javelinist.xml"/>
     43    <variant file="biped/attack_melee_ranged.xml"/>
    4344    <variant file="biped/attack_capture.xml"/>
    4445    <variant file="biped/attack_slaughter.xml"/>
    4546    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_javelinist_b.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_javelinist.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_javelinist_e.xml

     
    3636  <group>
    3737    <variant frequency="100" name="Idle"/>
    3838    <variant file="biped/attack_ranged_javelinist.xml"/>
     39    <variant file="biped/attack_melee_ranged.xml"/>
    3940    <variant file="biped/attack_capture.xml"/>
    4041    <variant file="biped/attack_slaughter.xml"/>
    4142    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_slinger_a.xml

     
    2626  <group>
    2727    <variant frequency="1" name="Idle"/>
    2828    <variant file="biped/attack_ranged_slinger.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_slinger_b.xml

     
    2222  <group>
    2323    <variant frequency="1" name="Idle"/>
    2424    <variant file="biped/attack_ranged_slinger.xml"/>
     25    <variant file="biped/attack_melee_ranged.xml"/>
    2526    <variant file="biped/attack_capture.xml"/>
    2627    <variant file="biped/attack_slaughter.xml"/>
    2728    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/hellenes/infantry_slinger_e.xml

     
    2424  <group>
    2525    <variant frequency="1" name="Idle"/>
    2626    <variant file="biped/attack_ranged_slinger.xml"/>
     27    <variant file="biped/attack_melee_ranged.xml"/>
    2728    <variant file="biped/attack_capture.xml"/>
    2829    <variant file="biped/attack_slaughter.xml"/>
    2930    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_javelinist_a.xml

     
    2626  <group>
    2727    <variant frequency="100" name="Idle"/>
    2828    <variant file="biped/attack_ranged_javelinist.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_javelinist_b.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_javelinist.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_javelinist_e.xml

     
    2727    <variant frequency="100" name="Idle"/>
    2828    <variant frequency="100" name="Idle"/>
    2929    <variant file="biped/attack_ranged_javelinist.xml"/>
     30    <variant file="biped/attack_melee_ranged.xml"/>
    3031    <variant file="biped/attack_capture.xml"/>
    3132    <variant file="biped/attack_slaughter.xml"/>
    3233    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_slinger_a.xml

     
    2828  <group>
    2929    <variant frequency="1" name="Idle"/>
    3030    <variant file="biped/attack_ranged_slinger.xml"/>
     31    <variant file="biped/attack_melee_ranged.xml"/>
    3132    <variant file="biped/attack_capture.xml"/>
    3233    <variant file="biped/attack_slaughter.xml"/>
    3334    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_slinger_b.xml

     
    3030  <group>
    3131    <variant frequency="1" name="Idle"/>
    3232    <variant file="biped/attack_ranged_slinger.xml"/>
     33    <variant file="biped/attack_melee_ranged.xml"/>
    3334    <variant file="biped/attack_capture.xml"/>
    3435    <variant file="biped/attack_slaughter.xml"/>
    3536    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_slinger_e.xml

     
    3030    <variant frequency="1" name="Idle"/>
    3131    <variant frequency="1" name="Idle"/>
    3232    <variant file="biped/attack_ranged_slinger.xml"/>
     33    <variant file="biped/attack_melee_ranged.xml"/>
    3334    <variant file="biped/attack_capture.xml"/>
    3435    <variant file="biped/attack_slaughter.xml"/>
    3536    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_swordsman_a.xml

     
    3333  <group>
    3434    <variant frequency="1" name="Idle"/>
    3535    <variant file="biped/attack_melee_swordsman.xml"/>
     36    <variant file="biped/attack_ranged_javelinist.xml">
     37      <props>
     38        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     39        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     40      </props>
     41    </variant>
    3642    <variant file="biped/attack_capture.xml"/>
    3743    <variant file="biped/attack_slaughter.xml"/>
    3844    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_swordsman_b.xml

     
    3535  <group>
    3636    <variant frequency="1" name="Idle"/>
    3737    <variant file="biped/attack_melee_swordsman.xml"/>
     38    <variant file="biped/attack_ranged_javelinist.xml">
     39      <props>
     40        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     41        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     42      </props>
     43    </variant>
    3844    <variant file="biped/attack_capture.xml"/>
    3945    <variant file="biped/attack_slaughter.xml"/>
    4046    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/iberians/infantry_swordsman_e.xml

     
    3030  <group>
    3131    <variant frequency="1" name="Idle"/>
    3232    <variant file="biped/attack_melee_swordsman.xml"/>
     33    <variant file="biped/attack_ranged_javelinist.xml">
     34      <props>
     35        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     36        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     37      </props>
     38    </variant>
    3339    <variant file="biped/attack_capture.xml"/>
    3440    <variant file="biped/attack_slaughter.xml"/>
    3541    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/macedonians/infantry_javelinist_a.xml

     
    3434  <group>
    3535    <variant frequency="100" name="Idle"/>
    3636    <variant file="biped/attack_ranged_javelinist.xml"/>
     37    <variant file="biped/attack_melee_ranged.xml"/>
    3738    <variant file="biped/attack_capture.xml"/>
    3839    <variant file="biped/attack_slaughter.xml"/>
    3940    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/macedonians/infantry_javelinist_b.xml

     
    3333  <group>
    3434    <variant frequency="100" name="Idle"/>
    3535    <variant file="biped/attack_ranged_javelinist.xml"/>
     36    <variant file="biped/attack_melee_ranged.xml"/>
    3637    <variant file="biped/attack_capture.xml"/>
    3738    <variant file="biped/attack_slaughter.xml"/>
    3839    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/macedonians/infantry_javelinist_e.xml

     
    3939  <group>
    4040    <variant frequency="100" name="Idle"/>
    4141    <variant file="biped/attack_ranged_javelinist.xml"/>
     42    <variant file="biped/attack_melee_ranged.xml"/>
    4243    <variant file="biped/attack_capture.xml"/>
    4344    <variant file="biped/attack_slaughter.xml"/>
    4445    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/macedonians/infantry_slinger_a.xml

     
    2626  <group>
    2727    <variant frequency="1" name="Idle"/>
    2828    <variant file="biped/attack_ranged_slinger.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/macedonians/infantry_slinger_b.xml

     
    2222  <group>
    2323    <variant frequency="1" name="Idle"/>
    2424    <variant file="biped/attack_ranged_slinger.xml"/>
     25    <variant file="biped/attack_melee_ranged.xml"/>
    2526    <variant file="biped/attack_capture.xml"/>
    2627    <variant file="biped/attack_slaughter.xml"/>
    2728    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/macedonians/infantry_slinger_e.xml

     
    2424  <group>
    2525    <variant frequency="1" name="Idle"/>
    2626    <variant file="biped/attack_ranged_slinger.xml"/>
     27    <variant file="biped/attack_melee_ranged.xml"/>
    2728    <variant file="biped/attack_capture.xml"/>
    2829    <variant file="biped/attack_slaughter.xml"/>
    2930    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/mauryans/infantry_archer_a.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_archer.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/mauryans/infantry_archer_b.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_archer.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/mauryans/infantry_archer_e.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_archer.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/persians/champion_unit_1.xml

     
    4242  <group>
    4343    <variant frequency="1" name="Idle"/>
    4444    <variant file="biped/attack_capture.xml"/>
     45    <variant file="biped/attack_ranged_archer.xml">
     46      <props>
     47        <prop attachpoint="r_hand"/>
     48        <prop actor="props/units/weapons/bow_recurve.xml" attachpoint="l_hand"/>
     49      </props>
     50    </variant>
    4551  </group>
    4652  <material>player_trans.xml</material>
    4753</actor>
  • binaries/data/mods/public/art/actors/units/persians/infantry_archer_a.xml

     
    3636  <group>
    3737    <variant frequency="100" name="Idle"/>
    3838    <variant file="biped/attack_ranged_archer.xml"/>
     39    <variant file="biped/attack_melee_ranged.xml"/>
    3940    <variant file="biped/attack_capture.xml"/>
    4041    <variant file="biped/attack_slaughter.xml"/>
    4142    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/persians/infantry_archer_b.xml

     
    2424  <group>
    2525    <variant frequency="100" name="Idle"/>
    2626    <variant file="biped/attack_ranged_archer.xml"/>
     27    <variant file="biped/attack_melee_ranged.xml"/>
    2728    <variant file="biped/attack_capture.xml"/>
    2829    <variant file="biped/attack_slaughter.xml"/>
    2930    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/persians/infantry_archer_e.xml

     
    3737  <group>
    3838    <variant frequency="100" name="Idle"/>
    3939    <variant file="biped/attack_ranged_archer.xml"/>
     40    <variant file="biped/attack_melee_ranged.xml"/>
    4041    <variant file="biped/attack_capture.xml"/>
    4142    <variant file="biped/attack_slaughter.xml"/>
    4243    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/persians/infantry_javelinist_a.xml

     
    4141  <group>
    4242    <variant frequency="100" name="Idle"/>
    4343    <variant file="biped/attack_ranged_javelinist.xml"/>
     44    <variant file="biped/attack_melee_ranged.xml"/>
    4445    <variant file="biped/attack_capture.xml"/>
    4546    <variant file="biped/attack_slaughter.xml"/>
    4647    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/persians/infantry_javelinist_b.xml

     
    3333  <group>
    3434    <variant frequency="100" name="Idle"/>
    3535    <variant file="biped/attack_ranged_javelinist.xml"/>
     36    <variant file="biped/attack_melee_ranged.xml"/>
    3637    <variant file="biped/attack_capture.xml"/>
    3738    <variant file="biped/attack_slaughter.xml"/>
    3839    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/persians/infantry_javelinist_e.xml

     
    3434  <group>
    3535    <variant frequency="100" name="Idle"/>
    3636    <variant file="biped/attack_ranged_javelinist.xml"/>
     37    <variant file="biped/attack_melee_ranged.xml"/>
    3738    <variant file="biped/attack_capture.xml"/>
    3839    <variant file="biped/attack_slaughter.xml"/>
    3940    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/ptolemies/infantry_archer_b.xml

     
    2525  <group>
    2626    <variant frequency="100" name="Idle"/>
    2727    <variant file="biped/attack_ranged_archer.xml"/>
     28    <variant file="biped/attack_melee_ranged.xml"/>
    2829    <variant file="biped/attack_capture.xml"/>
    2930    <variant file="biped/attack_slaughter.xml"/>
    3031    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/ptolemies/infantry_swordsman_a.xml

     
    6161  <group>
    6262    <variant frequency="1" name="Idle"/>
    6363    <variant file="biped/attack_melee_swordsman.xml"/>
     64    <variant file="biped/attack_ranged_javelinist.xml">
     65      <props>
     66        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     67        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     68      </props>
     69    </variant>
    6470    <variant file="biped/attack_capture.xml"/>
    6571    <variant file="biped/attack_slaughter.xml"/>
    6672    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/ptolemies/infantry_swordsman_b.xml

     
    4545  <group>
    4646    <variant frequency="1" name="Idle"/>
    4747    <variant file="biped/attack_melee_swordsman.xml"/>
     48    <variant file="biped/attack_ranged_javelinist.xml">
     49      <props>
     50        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     51        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     52      </props>
     53    </variant>
    4854    <variant file="biped/attack_capture.xml"/>
    4955    <variant file="biped/attack_slaughter.xml"/>
    5056    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/ptolemies/infantry_swordsman_e.xml

     
    4141  <group>
    4242    <variant frequency="1" name="Idle"/>
    4343    <variant file="biped/attack_melee_swordsman.xml"/>
     44    <variant file="biped/attack_ranged_javelinist"/>
    4445    <variant file="biped/attack_capture.xml"/>
    4546    <variant file="biped/attack_slaughter.xml"/>
    4647    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/romans/infantry_javelinist_a.xml

     
    3333  <group>
    3434    <variant frequency="100" name="Idle"/>
    3535    <variant file="biped/attack_ranged_javelinist.xml"/>
     36    <variant file="biped/attack_melee_ranged.xml"/>
    3637    <variant file="biped/attack_capture.xml"/>
    3738    <variant file="biped/attack_slaughter.xml"/>
    3839    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/romans/infantry_javelinist_b.xml

     
    3333  <group>
    3434    <variant frequency="100" name="Idle"/>
    3535    <variant file="biped/attack_ranged_javelinist.xml"/>
     36    <variant file="biped/attack_melee_ranged.xml"/>
    3637    <variant file="biped/attack_capture.xml"/>
    3738    <variant file="biped/attack_slaughter.xml"/>
    3839    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/romans/infantry_javelinist_e.xml

     
    3333  <group>
    3434    <variant frequency="100" name="Idle"/>
    3535    <variant file="biped/attack_ranged_javelinist.xml"/>
     36    <variant file="biped/attack_melee_ranged.xml"/>
    3637    <variant file="biped/attack_capture.xml"/>
    3738    <variant file="biped/attack_slaughter.xml"/>
    3839    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/romans/infantry_swordsman_a.xml

     
    5353  <group>
    5454    <variant frequency="1" name="Idle"/>
    5555    <variant file="biped/attack_melee_swordsman.xml"/>
     56    <variant file="biped/attack_ranged_javelinist.xml">
     57      <props>
     58        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     59        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     60      </props>
     61    </variant>
    5662    <variant file="biped/attack_capture.xml"/>
    5763    <variant file="biped/attack_slaughter.xml"/>
    5864    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/romans/infantry_swordsman_b.xml

     
    4646  <group>
    4747    <variant frequency="1" name="Idle"/>
    4848    <variant file="biped/attack_melee_swordsman.xml"/>
     49    <variant file="biped/attack_ranged_javelinist.xml">
     50      <props>
     51        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     52        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     53      </props>
     54    </variant>
    4955    <variant file="biped/attack_capture.xml"/>
    5056    <variant file="biped/attack_slaughter.xml"/>
    5157    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/romans/infantry_swordsman_e.xml

     
    4848  <group>
    4949    <variant frequency="1" name="Idle"/>
    5050    <variant file="biped/attack_melee_swordsman.xml"/>
     51    <variant file="biped/attack_ranged_javelinist.xml">
     52      <props>
     53        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     54        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     55      </props>
     56    </variant>
    5157    <variant file="biped/attack_capture.xml"/>
    5258    <variant file="biped/attack_slaughter.xml"/>
    5359    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/seleucids/infantry_swordsman_a.xml

     
    6666  <group>
    6767    <variant frequency="1" name="Idle"/>
    6868    <variant file="biped/attack_melee_swordsman.xml"/>
     69    <variant file="biped/attack_ranged_javelinist.xml">
     70      <props>
     71        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     72        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     73      </props>
     74    </variant>
    6975    <variant file="biped/attack_capture.xml"/>
    7076    <variant file="biped/attack_slaughter.xml"/>
    7177    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/seleucids/infantry_swordsman_b.xml

     
    6868  <group>
    6969    <variant frequency="1" name="Idle"/>
    7070    <variant file="biped/attack_melee_swordsman.xml"/>
     71    <variant file="biped/attack_ranged_javelinist.xml">
     72      <props>
     73        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     74        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     75      </props>
     76    </variant>
    7177    <variant file="biped/attack_capture.xml"/>
    7278    <variant file="biped/attack_slaughter.xml"/>
    7379    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/seleucids/infantry_swordsman_e.xml

     
    6666  <group>
    6767    <variant frequency="1" name="Idle"/>
    6868    <variant file="biped/attack_melee_swordsman.xml"/>
     69    <variant file="biped/attack_ranged_javelinist.xml">
     70      <props>
     71        <prop actor="props/units/weapons/jav.xml" attachpoint="r_hand"/>
     72        <prop actor="props/units/weapons/jav.xml" attachpoint="projectile"/>
     73      </props>
     74    </variant>
    6975    <variant file="biped/attack_capture.xml"/>
    7076    <variant file="biped/attack_slaughter.xml"/>
    7177    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/spartans/infantry_javelinist_a.xml

     
    2626  <group>
    2727    <variant frequency="100" name="Idle"/>
    2828    <variant file="biped/attack_ranged_javelinist.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/spartans/infantry_javelinist_b.xml

     
    2626  <group>
    2727    <variant frequency="100" name="Idle"/>
    2828    <variant file="biped/attack_ranged_javelinist.xml"/>
     29    <variant file="biped/attack_melee_ranged.xml"/>
    2930    <variant file="biped/attack_capture.xml"/>
    3031    <variant file="biped/attack_slaughter.xml"/>
    3132    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/actors/units/spartans/infantry_javelinist_e.xml

     
    2727  <group>
    2828    <variant frequency="100" name="Idle"/>
    2929    <variant file="biped/attack_ranged_javelinist.xml"/>
     30    <variant file="biped/attack_melee_ranged.xml"/>
    3031    <variant file="biped/attack_capture.xml"/>
    3132    <variant file="biped/attack_slaughter.xml"/>
    3233    <variant file="biped/gather_tree.xml"/>
  • binaries/data/mods/public/art/textures/cursors/action-melee-attack.txt

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
     
     11 1
  • binaries/data/mods/public/art/textures/cursors/action-ranged-attack.txt

     
     11 1
  • binaries/data/mods/public/art/variants/biped/attack_melee_ranged.xml

     
     1<variant name="attack_melee">
     2  <animations>
     3    <animation event="0.5" file="infantry/sword/attack/isw_s_off_05.psa" name="attack_melee" speed="100"/>
     4  </animations>
     5  <props>
     6    <prop actor="props/units/weapons/knife.xml" attachpoint="r_hand"/>
     7  </props>
     8</variant>
  • binaries/data/mods/public/gui/common/tooltips.js

     
    166166
    167167    for (let type in template.attack)
    168168    {
     169        if (type == "ChangeDistance")
     170            continue; // not an attack type
    169171        if (type == "Slaughter")
    170172            continue; // Slaughter is not a real attack, so do not show it.
    171173        if (type == "Charge")
  • binaries/data/mods/public/gui/session/input.js

     
    205205                data.targetClasses = Engine.HotkeyIsPressed("session.attackmoveUnit") ? { "attack": ["Unit"] } : { "attack": ["Unit", "Structure"] };
    206206                cursor = "action-attack-move";
    207207            }
     208
     209            if (Engine.HotkeyIsPressed("session.meleeattackmove"))
     210            {
     211                data.command = "attack-walk";
     212                data.targetClasses = Engine.HotkeyIsPressed("session.meleeattackmoveUnit") ? { "attack": ["Unit"] } : { "attack": ["Unit", "Structure"] };
     213                cursor = "action-melee-attack-move";
     214            }
     215
     216            if (Engine.HotkeyIsPressed("session.rangedattackmove"))
     217            {
     218                data.command = "attack-walk";
     219                data.targetClasses = Engine.HotkeyIsPressed("session.rangedattackmoveUnit") ? { "attack": ["Unit"] } : { "attack": ["Unit", "Structure"] };
     220                cursor = "action-ranged-attack-move";
     221            }
     222
    208223            return { "possible": true, "data": data, "cursor": cursor };
    209224        }
    210225
  • binaries/data/mods/public/gui/session/unit_actions.js

     
    11/**
    2  * List of different actions units can execute, 
     2 * List of different actions units can execute,
    33 * this is mostly used to determine which actions can be executed
    44 *
    55 * "execute" is meant to send the command to the engine
    66 *
    7  * The next functions will always return false 
     7 * The next functions will always return false
    88 * in case you have to continue to seek
    9  * (i.e. look at the next entity for getActionInfo, the next 
     9 * (i.e. look at the next entity for getActionInfo, the next
    1010 * possible action for the actionCheck ...)
    1111 * They will return an object when the searching is finished
    1212 *
     
    2424 *
    2525 * "specificness" is used to determine how specific an action is,
    2626 * The lower the number, the more specific an action is, and the bigger
    27  * the chance of selecting that action when multiple actions are possible 
     27 * the chance of selecting that action when multiple actions are possible
    2828 */
    2929
    30 var unitActions = 
     30var unitActions =
    3131{
    3232    "move":
    3333    {
     
    5353                return {"type": "move"};
    5454            return false;
    5555        },
    56         "specificness": 12,
     56        "specificness": 13,
    5757    },
    5858
    59     "attack-move": 
     59    "attack-move":
    6060    {
    6161        "execute": function(target, action, selection, queued)
    6262        {
     
    6565            else
    6666                var targetClasses = { "attack": ["Unit", "Structure"] };
    6767
    68             Engine.PostNetworkCommand({"type": "attack-walk", "entities": selection, "x": target.x, "z": target.z, "targetClasses": targetClasses, "queued": queued});
     68            Engine.PostNetworkCommand({ "type": "attack-walk", "entities": selection, "x": target.x, "z": target.z, "targetClasses": targetClasses, "queued": queued, "prefType": "primary" });
    6969            Engine.GuiInterfaceCall("PlaySound", { "name": "order_walk", "entity": selection[0] });
    7070            return true;
    7171        },
     
    8181                return entState && entState.unitAI;
    8282            });
    8383            if (haveUnitAI && Engine.HotkeyIsPressed("session.attackmove") && getActionInfo("attack-move", target).possible)
    84                 return {"type": "attack-move", "cursor": "action-attack-move"};
     84                return { "type": "attack-move", "cursor": "action-attack-move" };
    8585            return false;
    8686        },
    8787        "specificness": 30,
    8888    },
    8989
    90     "capture":
     90    "melee-attack-move":
    9191    {
    9292        "execute": function(target, action, selection, queued)
    9393        {
    94             Engine.PostNetworkCommand({"type": "attack", "entities": selection, "target": action.target, "allowCapture": true, "queued": queued});
     94            if (Engine.HotkeyIsPressed("session.meleeattackmoveUnit"))
     95                var targetClasses = { "meleeattack": ["Unit"] };
     96            else
     97                var targetClasses = { "meleeattack": ["Unit", "Structure"] };
     98
     99            Engine.PostNetworkCommand({ "type": "attack-walk", "entities": selection, "x": target.x, "z": target.z, "targetClasses": targetClasses, "queued": queued, "prefType": "Melee" });
     100            Engine.GuiInterfaceCall("PlaySound", { "name": "order_walk", "entity": selection[0] });
     101            return true;
     102        },
     103        "getActionInfo": function(entState, targetState)
     104        {
     105            if (!entState || !targetState || !targetState.hitpoints) // hack
     106                return false;
     107            return { "possible": Engine.GuiInterfaceCall("CanAttackWithType", { "entity": entState.id, "target": targetState.id, "type": "Melee" }) };
     108        },
     109        "hotkeyActionCheck": function(target, selection)
     110        {
     111            // Work out whether at least part of the selection have UnitAI
     112            let haveUnitAi = selection.some(function(ent) {
     113                let entState = GetEntityState(ent);
     114                return entState && entState.unitAI && getActionInfo("melee-attack-move", target).possible;
     115            });
     116            if (!haveUnitAi || !Engine.HotkeyIsPressed("session.meleeattackmove"))
     117                return false;
     118
     119            // Work out whether at least part of the selection can ranged attack
     120            for (let ent of selection)
     121                if (target && unitActions["melee-attack-move"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     122                    return { "type": "melee-attack-move", "cursor": "action-melee-attack" };
     123            return false;
     124        },
     125        "specificness": 31,
     126    },
     127
     128    "ranged-attack-move":
     129    {
     130        "execute": function(target, action, selection, queued)
     131        {
     132            if (Engine.HotkeyIsPressed("session.rangedattackmoveUnit"))
     133                var targetClasses = { "rangedattack": ["Unit"] };
     134            else
     135                var targetClasses = { "rangedattack": ["Unit", "Structure"] };
     136
     137            Engine.PostNetworkCommand({ "type": "attack-walk", "entities": selection, "x": target.x, "z": target.z, "targetClasses": targetClasses, "queued": queued, "prefType": "Ranged" });
     138            Engine.GuiInterfaceCall("PlaySound", { "name": "order_walk", "entity": selection[0] });
     139            return true;
     140        },
     141        "getActionInfo": function(entState, targetState)
     142        {
     143            if (!entState || !targetState || !targetState.hitpoints) // hack
     144                return false;
     145            return { "possible": Engine.GuiInterfaceCall("CanAttackWithType", { "entity": entState.id, "target": targetState.id, "type": "Ranged" }) };
     146        },
     147        "hotkeyActionCheck": function(target, selection)
     148        {
     149            // Work out whether at least part of the selection have UnitAI
     150            let haveUnitAi = selection.some(function(ent) {
     151                let entState = GetEntityState(ent);
     152                return entState && entState.unitAI && getActionInfo("ranged-attack-move", target).possible;
     153            });
     154            if (!haveUnitAi || !Engine.HotkeyIsPressed("session.rangedattackmove"))
     155                return false;
     156
     157            // Work out whether at least part of the selection can ranged attack
     158            for (let ent of selection)
     159                if (target && unitActions["ranged-attack-move"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     160                    return { "type": "ranged-attack-move", "cursor": "action-ranged-attack" };
     161            return false;
     162        },
     163        "specificness": 32,
     164    },
     165
     166    "capture":
     167    {
     168        "execute": function(target, action, selection, queued)
     169        {
     170            Engine.PostNetworkCommand({ "type": "attack", "entities": selection, "target": action.target, "prefType": "Capture", "queued": queued });
    95171            Engine.GuiInterfaceCall("PlaySound", { "name": "order_attack", "entity": selection[0] });
    96172            return true;
    97173        },
     
    99175        {
    100176            if (!entState.attack || !targetState.hitpoints)
    101177                return false;
    102             return {"possible": Engine.GuiInterfaceCall("CanCapture", {"entity": entState.id, "target": targetState.id})};
     178            return { "possible": Engine.GuiInterfaceCall("CanCapture", { "entity": entState.id, "target": targetState.id }) };
    103179        },
    104         "actionCheck": function(target)
     180        "actionCheck": function(target, selection)
    105181        {
    106             if (getActionInfo("capture", target).possible)
    107                 return {"type": "capture", "cursor": "action-capture", "target": target};
     182            // Work out whether at least part of the selection can capture
     183            for (let ent of selection)
     184                if (target && unitActions["capture"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     185                    return { "type": "capture", "cursor": "action-capture", "target": target };
    108186            return false;
    109187        },
    110         "specificness": 9,
     188        "specificness": 7,
    111189    },
    112190
    113191    "attack":
     
    114192    {
    115193        "execute": function(target, action, selection, queued)
    116194        {
    117             Engine.PostNetworkCommand({"type": "attack", "entities": selection, "target": action.target, "queued": queued, "allowCapture": false});
     195            Engine.PostNetworkCommand({ "type": "attack", "entities": selection, "target": action.target, "queued": queued, "prefType": "primary" });
    118196            Engine.GuiInterfaceCall("PlaySound", { "name": "order_attack", "entity": selection[0] });
    119197            return true;
    120198        },
    121199        "getActionInfo": function(entState, targetState)
    122200        {
    123             if (!entState.attack || !targetState.hitpoints)
     201            if (!entState || !targetState || !targetState.hitpoints) // hack
    124202                return false;
    125             return {"possible": Engine.GuiInterfaceCall("CanAttack", {"entity": entState.id, "target": targetState.id})};
     203            return { "possible": Engine.GuiInterfaceCall("CanAttack", { "entity": entState.id, "target": targetState.id }) };
    126204        },
    127         "hotkeyActionCheck": function(target)
     205        "hotkeyActionCheck": function(target, selection)
    128206        {
    129             if (Engine.HotkeyIsPressed("session.attack") && getActionInfo("attack", target).possible)
    130                 return {"type": "attack", "cursor": "action-attack", "target": target};
     207            if (!Engine.HotkeyIsPressed("session.attack"))
     208                return false;
     209            // Work out whether at least part of the selection can attack
     210            for (let ent of selection)
     211                if (target && unitActions["attack"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     212                    return { "type": "attack", "cursor": "action-attack", "target": target };
    131213            return false;
    132214        },
    133         "actionCheck": function(target)
     215        "actionCheck": function(target, selection)
    134216        {
    135             if (getActionInfo("attack", target).possible)
    136                 return {"type": "attack", "cursor": "action-attack", "target": target};
     217            // Work out whether at least part of the selection can attack
     218            for (let ent of selection)
     219                if (target && unitActions["attack"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     220                    return { "type": "attack", "cursor": "action-attack", "target": target };
    137221            return false;
    138222        },
     223        "specificness": 8,
     224    },
     225
     226    "melee-attack":
     227    {
     228        "execute": function(target, action, selection, queued)
     229        {
     230            Engine.PostNetworkCommand({ "type": "attack", "entities": selection, "target": action.target, "queued": queued, "prefType": "Melee" });
     231            Engine.GuiInterfaceCall("PlaySound", { "name": "order_attack", "entity": selection[0] });
     232            return true;
     233        },
     234        "getActionInfo": function(entState, targetState)
     235        {
     236            if (!entState || !targetState || !targetState.hitpoints) // hack
     237                return false;
     238            return { "possible": Engine.GuiInterfaceCall("CanAttackWithType", { "entity": entState.id, "target": targetState.id, "type": "Melee" }) };
     239        },
     240        "hotkeyActionCheck": function(target, selection)
     241        {
     242            if (!Engine.HotkeyIsPressed("session.meleeattack"))
     243                return false;
     244            // Work out whether at least part of the selection can melee attack
     245            for (let ent of selection)
     246                if (target && unitActions["melee-attack"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     247                    return { "type": "melee-attack", "cursor": "action-melee-attack", "target": target };
     248            return false;
     249        },
     250        "actionCheck": function(target, selection)
     251        {
     252            // Work out whether at least part of the selection can melee attack
     253            for (let ent of selection)
     254                if (target && unitActions["melee-attack"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     255                    return { "type": "melee-attack", "cursor": "action-melee-attack", "target": target };
     256            return false;
     257        },
     258        "specificness": 9,
     259    },
     260
     261    "ranged-attack":
     262    {
     263        "execute": function(target, action, selection, queued)
     264        {
     265            Engine.PostNetworkCommand({ "type": "attack", "entities": selection, "target": action.target, "queued": queued, "prefType": "Ranged" });
     266            Engine.GuiInterfaceCall("PlaySound", { "name": "order_attack", "entity": selection[0] });
     267            return true;
     268        },
     269        "getActionInfo": function(entState, targetState)
     270        {
     271            if (!entState || !targetState || !targetState.hitpoints) // hack
     272                return false;
     273            return { "possible": Engine.GuiInterfaceCall("CanAttackWithType", { "entity": entState.id, "target": targetState.id, "type": "Ranged" }) };
     274        },
     275        "hotkeyActionCheck": function(target, selection)
     276        {
     277            if (!Engine.HotkeyIsPressed("session.rangedattack"))
     278                return false;
     279            // Work out whether at least part of the selection can range attack
     280            for (let ent of selection)
     281                if (target && unitActions["ranged-attack"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     282                    return { "type": "ranged-attack", "cursor": "action-ranged-attack", "target": target };
     283            return false;
     284        },
     285        "actionCheck": function(target, selection)
     286        {
     287            // Work out whether at least part of the selection can range attack
     288            for (let ent of selection)
     289                if (target && unitActions["ranged-attack"].getActionInfo(GetEntityState(ent), GetEntityState(target)).possible)
     290                    return { "type": "ranged-attack", "cursor": "action-ranged-attack", "target": target };
     291            return false;
     292        },
    139293        "specificness": 10,
    140294    },
    141295
    142     "heal": 
     296    "heal":
    143297    {
    144298        "execute": function(target, action, selection, queued)
    145299        {
    146             Engine.PostNetworkCommand({"type": "heal", "entities": selection, "target": action.target, "queued": queued});
     300            Engine.PostNetworkCommand({ "type": "heal", "entities": selection, "target": action.target, "queued": queued });
    147301            Engine.GuiInterfaceCall("PlaySound", { "name": "order_heal", "entity": selection[0] });
    148302            return true;
    149303        },
     
    176330                return {"type": "heal", "cursor": "action-heal", "target": target};
    177331            return false;
    178332        },
    179         "specificness": 7,
     333        "specificness": 6,
    180334    },
    181335
    182     "build": 
     336    "build":
    183337    {
    184338        "execute": function(target, action, selection, queued)
    185339        {
     
    202356        "specificness": 3,
    203357    },
    204358
    205     "repair": 
     359    "repair":
    206360    {
    207361        "execute": function(target, action, selection, queued)
    208362        {
     
    230384                return {"type": "build", "cursor": "action-repair", "target": target};
    231385            return false;
    232386        },
    233         "specificness": 11,
     387        "specificness": 12,
    234388    },
    235389
    236     "gather": 
     390    "gather":
    237391    {
    238392        "execute": function(target, action, selection, queued)
    239393        {
     
    260414        "specificness": 1,
    261415    },
    262416
    263     "returnresource": 
     417    "returnresource":
    264418    {
    265419        "execute": function(target, action, selection, queued)
    266420        {
     
    297451        "specificness": 2,
    298452    },
    299453
    300     "setup-trade-route": 
     454    "setup-trade-route":
    301455    {
    302456        "execute": function(target, action, selection, queued)
    303457        {
     
    362516        "specificness": 0,
    363517    },
    364518
    365     "garrison": 
     519    "garrison":
    366520    {
    367521        "execute": function(target, action, selection, queued)
    368522        {
     
    409563        "specificness": 20,
    410564    },
    411565
    412     "guard": 
     566    "guard":
    413567    {
    414568        "execute": function(target, action, selection, queued)
    415569        {
     
    446600        "specificness": 40,
    447601    },
    448602
    449     "remove-guard": 
     603    "remove-guard":
    450604    {
    451605        "execute": function(target, action, selection, queued)
    452606        {
     
    471625        "specificness": 41,
    472626    },
    473627
    474     "set-rallypoint": 
     628    "set-rallypoint":
    475629    {
    476630        "execute": function(target, action, selection, queued)
    477631        {
    478             // if there is a position set in the action then use this so that when setting a 
     632            // if there is a position set in the action then use this so that when setting a
    479633            // rally point on an entity it is centered on that entity
    480634            if (action.position)
    481635                target = action.position;
     
    507661                cursor = "action-attack-move";
    508662            }
    509663
     664            if (Engine.HotkeyIsPressed("session.meleeattackmove"))
     665            {
     666                if (Engine.HotkeyIsPressed("session.meleeattackmoveUnit"))
     667                    var targetClasses = { "melee-attack": ["Unit"] };
     668                else
     669                    var targetClasses = { "melee-attack": ["Unit", "Structure"] };
     670                data.command = "melee-attack-walk";
     671                data.targetClasses = targetClasses;
     672                cursor = "action-melee-attack-move";
     673            }
     674
     675            if (Engine.HotkeyIsPressed("session.rangedattackmove"))
     676            {
     677                if (Engine.HotkeyIsPressed("session.rangedattackmoveUnit"))
     678                    var targetClasses = { "ranged-attack": ["Unit"] };
     679                else
     680                    var targetClasses = { "ranged-attack": ["Unit", "Structure"] };
     681                data.command = "ranged-attack-walk";
     682                data.targetClasses = targetClasses;
     683                cursor = "action-ranged-attack-move";
     684            }
     685
    510686            if (targetState.garrisonHolder && playerCheck(entState, targetState, ["Player", "MutualAlly"]))
    511687            {
    512688                data.command = "garrison";
     
    610786                return false;
    611787            return {"type": "set-rallypoint", "cursor": actionInfo.cursor, "data": actionInfo.data, "tooltip": actionInfo.tooltip, "position": actionInfo.position};
    612788        },
    613         "specificness": 6,
     789        "specificness": 5,
    614790    },
    615791
    616     "unset-rallypoint": 
     792    "unset-rallypoint":
    617793    {
    618794        "execute": function(target, action, selection, queued)
    619795        {
     
    654830        "specificness": 11,
    655831    },
    656832
    657     "none": 
     833    "none":
    658834    {
    659835        "execute": function(target, action, selection, queued)
    660836        {
     
    668844 * Info and actions for the entity commands
    669845 * Currently displayed in the bottom of the central panel
    670846 */
    671 var g_EntityCommands = 
     847var g_EntityCommands =
    672848{
    673849    // Unload
    674850    "unload-all": {
  • binaries/data/mods/public/simulation/ai/common-api/entity.js

     
    744744    },
    745745
    746746    isGarrisonHolder: function() { return this.get("GarrisonHolder") !== undefined; },
     747    isCapturable: function() { return this.get("Capturable") !== undefined; },
    747748    garrisoned: function() { return this._entity.garrisoned; },
    748749    canGarrisonInside: function() { return this._entity.garrisoned.length < this.garrisonMax(); },
    749750
     
    757758        return this;
    758759    },
    759760
    760     attackMove: function(x, z, targetClasses, queued = false) {
    761         Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "targetClasses": targetClasses, "queued": queued });
     761    attackMove: function(x, z, targetClasses, queued = false, prefType = "primary") { // hack
     762        Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": [this.id()], "x": x, "z": z, "targetClasses": targetClasses, "queued": queued, "prefType": prefType });
    762763        return this;
    763764    },
    764765
     
    792793        return this;
    793794    },
    794795
    795     attack: function(unitId, allowCapture = true, queued = false) {
    796         Engine.PostCommand(PlayerID,{"type": "attack", "entities": [this.id()], "target": unitId, "allowCapture": allowCapture, "queued": queued});
     796    attack: function(unitId, prefType, queued = false) {
     797        Engine.PostCommand(PlayerID,{"type": "attack", "entities": [this.id()], "target": unitId, "prefType": prefType, "queued": queued});
    797798        return this;
    798799    },
    799800
  • binaries/data/mods/public/simulation/ai/common-api/entitycollection.js

     
    148148m.EntityCollection.prototype.attackMove = function(x, z, targetClasses, queued)
    149149{
    150150    queued = queued || false;
    151     Engine.PostCommand(PlayerID,{"type": "attack-walk", "entities": this.toIdArray(), "x": x, "z": z, "targetClasses": targetClasses, "queued": queued});
     151    Engine.PostCommand(PlayerID, { "type": "attack-walk", "entities": this.toIdArray(), "x": x, "z": z, "targetClasses": targetClasses, "queued": queued, "prefType": "primary" }); // hack
    152152    return this;
    153153};
    154154
     
    175175m.EntityCollection.prototype.attack = function(unit)
    176176{
    177177    var unitId = unit;
    178     Engine.PostCommand(PlayerID,{"type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false});
     178    Engine.PostCommand(PlayerID, { "type": "attack", "entities": this.toIdArray(), "target": unitId, "queued": false, "prefType": "Capture" });
    179179    return this;
    180180};
    181181
  • binaries/data/mods/public/simulation/ai/petra/attackPlan.js

     
    10781078                        continue;
    10791079                    if (!ent.isIdle())
    10801080                        continue;
    1081                     ent.attack(attacker.id(), !this.noCapture.has(attacker.id()));
     1081                    ent.attack(attacker.id(), m.prefType(ent, attacker));
    10821082                }
    10831083                break;
    10841084            }
     
    13141314                {
    13151315                    if (this.isSiegeUnit(gameState, ent))   // needed as mauryan elephants are not filtered out
    13161316                        continue;
    1317                     ent.attack(attacker.id(), !this.noCapture.has(attacker.id()));
     1317                    ent.attack(attacker.id(), m.prefType(ent, attacker));
    13181318                    ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
    13191319                }
    13201320                // And if this attacker is a non-ranged siege unit and our unit also, attack it
    13211321                if (this.isSiegeUnit(gameState, attacker) && attacker.hasClass("Melee") && ourUnit.hasClass("Melee"))
    13221322                {
    1323                     ourUnit.attack(attacker.id(), false);
     1323                    ourUnit.attack(attacker.id(), "Melee", false);
    13241324                    ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
    13251325                }
    13261326            }
     
    13311331                    let collec = this.unitCollection.filter(API3.Filters.byClass("Melee")).filterNearest(ourUnit.position(), 5);
    13321332                    for (let ent of collec.values())
    13331333                    {
    1334                         ent.attack(attacker.id(), false);
     1334                        ent.attack(attacker.id(), m.prefType(ent, attacker));
    13351335                        ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
    13361336                    }
    13371337                }
     
    13501350                                continue;
    13511351                        }
    13521352                    }
    1353                     ourUnit.attack(attacker.id(), !this.noCapture.has(attacker.id()));
     1353                    ourUnit.attack(attacker.id(), m.prefType(ourUnit, attacker));
    13541354                    ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time);
    13551355                }
    13561356            }
     
    15211521                        return (valb - vala);
    15221522                    });
    15231523                    if (mStruct[0].hasClass("Gates"))
    1524                         ent.attack(mStruct[0].id(), false);
     1524                        ent.attack(mStruct[0].id(), m.prefType(ent, mStruct[0]));
    15251525                    else
    15261526                    {
    15271527                        let rand = Math.floor(Math.random() * mStruct.length * 0.2);
    1528                         let newTargetId = mStruct[rand].id();
    1529                         ent.attack(newTargetId, !this.noCapture.has(newTargetId));
     1528                        let newTarget = mStruct[rand];
     1529                        ent.attack(newTarget.id(), m.prefType(ent, newTarget));
    15301530                    }
    15311531                }
    15321532                else
     
    15841584                        return valb - vala;
    15851585                    });
    15861586                    let rand = Math.floor(Math.random() * mUnit.length * 0.1);
    1587                     let newTargetId = mUnit[rand].id();
    1588                     ent.attack(newTargetId, !this.noCapture.has(newTargetId));
     1587                    let newTarget = mUnit[rand];
     1588                    ent.attack(newTarget.id(), m.prefType(ent, newTarget));
    15891589                }
    15901590                else if (API3.SquareVectorDistance(this.targetPos, ent.position()) > 2500 )
    15911591                {
     
    16281628                            return (valb - vala);
    16291629                        });
    16301630                        if (mStruct[0].hasClass("Gates"))
    1631                             ent.attack(mStruct[0].id(), false);
     1631                            ent.attack(mStruct[0].id(), m.prefType(ent, mStruct[0]));
    16321632                        else
    16331633                        {
    16341634                            let rand = Math.floor(Math.random() * mStruct.length * 0.2);
    1635                             let newTargetId = mStruct[rand].id();
    1636                             ent.attack(newTargetId, !this.noCapture.has(newTargetId));
     1635                            let newTarget = mStruct[rand];
     1636                            ent.attack(newTarget.id(), m.prefType(ent, newTarget));
    16371637                        }
    16381638                    }
    16391639                    else if (needsUpdate)  // really nothing   let's try to help our nearest unit
     
    16541654
    16551655                        });
    16561656                        if (attackerId)
    1657                             ent.attack(attackerId, !this.noCapture.has(attackerId));
     1657                            ent.attack(attackerId, m.prefType(ent, attackerId));
    16581658                    }
    16591659                }
    16601660            }
     
    18281828
    18291829    if (this.noCapture.has(targetId))
    18301830    {
    1831         ent.attack(targetId, false);
     1831        ent.attack(targetId, m.prefType(ent, target));
    18321832        return true;
    18331833    }
    18341834
     
    18401840    if (target.hasClass("Siege") && target.hasClass("Melee"))
    18411841    {
    18421842        this.noCapture.add(targetId);
    1843         ent.attack(targetId, false);
     1843        ent.attack(targetId, m.prefType(ent, target));
    18441844        return true;
    18451845    }
    18461846
     
    18571857    if (antiCapture >= this.captureStrength)
    18581858    {
    18591859        this.noCapture.add(targetId);
    1860         ent.attack(targetId, false);
     1860        ent.attack(targetId, "primary"); // hack
    18611861        return true;
    18621862    }
    18631863
     
    18661866        this.unitCollection.length < 2*target.garrisoned().length)
    18671867    {
    18681868        this.noCapture.add(targetId);
    1869         ent.attack(targetId, false);
     1869        ent.attack(targetId, "primary"); // hack
    18701870        return true;
    18711871    }
    18721872
  • binaries/data/mods/public/simulation/ai/petra/defenseArmy.js

     
    7777    {
    7878        this.assignedTo[entID] = idFoe;
    7979        this.assignedAgainst[idFoe].push(entID);
    80         ent.attack(idFoe, m.allowCapture(ent, foeEnt), queued);
     80        ent.attack(idFoe, m.prefType(ent, foeEnt), queued);
    8181    }
    8282    else
    8383        gameState.ai.HQ.navalManager.requireTransport(gameState, ent, ownIndex, foeIndex, foePosition);
     
    116116        else if (orderData.length && orderData[0].target && orderData[0].attackType && orderData[0].attackType === "Capture")
    117117        {
    118118            let target = gameState.getEntityById(orderData[0].target);
    119             if (target && !m.allowCapture(ent, target))
    120                 ent.attack(orderData[0].target, false);
     119            if (target)
     120                ent.attack(orderData[0].target, m.prefType(ent, target));
    121121        }
    122122    }
    123123
  • binaries/data/mods/public/simulation/ai/petra/entityExtend.js

     
    8181    return strength * ent.maxHitpoints() / 100.0;
    8282};
    8383
    84 // Decide if we should try to capture or destroy
    85 m.allowCapture = function(ent, target)
     84// Decide if we should try to capture, melee or range attack
     85// TODO make this function less hacky
     86m.prefType = function(ent, target)
    8687{
    87     return !target.hasClass("Siege") || !ent.hasClass("Melee") ||
    88         !target.isGarrisonHolder() || !target.garrisoned().length;
     88    if (target.hasClass("Siege"))
     89        return "Melee"; // Don't capture for now
     90    if (target.isCapturable() && (!target.isGarrisonHolder() || !target.garrisoned().length))
     91        return "Capture";
     92    return "primary";
    8993};
    9094
    9195// Makes the worker deposit the currently carried resources at the closest accessible dropsite
  • binaries/data/mods/public/simulation/components/Attack.js

     
    11function Attack() {}
    22
    3 Attack.prototype.bonusesSchema = 
     3Attack.prototype.bonusesSchema =
    44    "<optional>" +
    55        "<element name='Bonuses'>" +
    66            "<zeroOrMore>" +
     
    4141Attack.prototype.Schema =
    4242    "<a:help>Controls the attack abilities and strengths of the unit.</a:help>" +
    4343    "<a:example>" +
     44        "<ChangeDistance>20</ChangeDistance>" +
    4445        "<Melee>" +
     46            "<AttackOrder>primary</AttackOrder>" +
    4547            "<Hack>10.0</Hack>" +
    4648            "<Pierce>0.0</Pierce>" +
    4749            "<Crush>5.0</Crush>" +
     
    6264            "<PreferredClasses datatype=\"tokens\">Cavalry Infantry</PreferredClasses>" +
    6365        "</Melee>" +
    6466        "<Ranged>" +
     67            "<AttackOrder>secondary</AttackOrder>" +
    6568            "<Hack>0.0</Hack>" +
    6669            "<Pierce>10.0</Pierce>" +
    6770            "<Crush>0.0</Crush>" +
     
    103106        "</Slaughter>" +
    104107    "</a:example>" +
    105108    "<optional>" +
     109        "<element name='ChangeDistance' a:help='Distance to change between Melee and Ranged attack'>" +
     110            "<ref name='nonNegativeDecimal'/>" +
     111        "</element>" +
     112    "</optional>" +
     113    "<optional>" +
    106114        "<element name='Melee'>" +
     115            "<optional>" +
     116                "<element name='AttackOrder'>" +
     117                    "<choice>" +
     118                        "<value>primary</value>" +
     119                        "<value>secondary</value>" +
     120                    "</choice>" +
     121                "</element>" +
     122            "</optional>" +
    107123            "<interleave>" +
    108124                "<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" +
    109125                "<element name='Pierce' a:help='Pierce damage strength'><ref name='nonNegativeDecimal'/></element>" +
     
    120136    "</optional>" +
    121137    "<optional>" +
    122138        "<element name='Ranged'>" +
     139            "<optional>" +
     140                "<element name='AttackOrder'>" +
     141                    "<choice>" +
     142                        "<value>primary</value>" +
     143                        "<value>secondary</value>" +
     144                    "</choice>" +
     145                "</element>" +
     146            "</optional>" +
    123147            "<interleave>" +
    124148                "<element name='Hack' a:help='Hack damage strength'><ref name='nonNegativeDecimal'/></element>" +
    125149                "<element name='Pierce' a:help='Pierce damage strength'><ref name='nonNegativeDecimal'/></element>" +
     
    219243Attack.prototype.GetPreferredClasses = function(type)
    220244{
    221245    if (this.template[type] && this.template[type].PreferredClasses &&
    222         this.template[type].PreferredClasses._string)
    223     {
     246        this.template[type].PreferredClasses._string)
    224247        return this.template[type].PreferredClasses._string.split(/\s+/);
    225     }
    226248    return [];
    227249};
    228250
     
    229251Attack.prototype.GetRestrictedClasses = function(type)
    230252{
    231253    if (this.template[type] && this.template[type].RestrictedClasses &&
    232         this.template[type].RestrictedClasses._string)
    233     {
     254        this.template[type].RestrictedClasses._string)
    234255        return this.template[type].RestrictedClasses._string.split(/\s+/);
    235     }
    236256    return [];
    237257};
    238258
     
    253273    let heightDiff = Math.abs(cmpThisPosition.GetHeightOffset() - cmpTargetPosition.GetHeightOffset());
    254274
    255275    const cmpIdentity = Engine.QueryInterface(target, IID_Identity);
    256     if (!cmpIdentity) 
     276    if (!cmpIdentity)
    257277        return undefined;
    258278
    259279    const targetClasses = cmpIdentity.GetClassesList();
    260280
     281    let cmpEntityPlayer = QueryOwnerInterface(this.entity);
     282    let cmpTargetPlayer = QueryOwnerInterface(target);
     283    if (!cmpTargetPlayer || !cmpEntityPlayer)
     284        return false;
     285
     286    if (targetClasses.indexOf("Domestic") == -1 && !cmpEntityPlayer.IsEnemy(cmpTargetPlayer.GetPlayerID()))
     287        return false;
     288
    261289    for (let type of this.GetAttackTypes())
    262290    {
    263291        if (type == "Capture" && !QueryMiragedInterface(target, IID_Capturable))
     
    288316    return false;
    289317};
    290318
     319Attack.prototype.CanAttackWithType = function(target, type)
     320{
     321    if (this.template[type])
     322        return this.CanAttack(target);
     323    return false;
     324};
    291325/**
    292326 * Returns null if we have no preference or the lowest index of a preferred class.
    293327 */
     
    294328Attack.prototype.GetPreference = function(target)
    295329{
    296330    const cmpIdentity = Engine.QueryInterface(target, IID_Identity);
    297     if (!cmpIdentity) 
     331    if (!cmpIdentity)
    298332        return undefined;
    299333
    300334    const targetClasses = cmpIdentity.GetClassesList();
     
    327361        if (type == "Slaughter")
    328362            continue;
    329363        let range = this.GetRange(type);
    330         if (range.min < ret.min)
    331             ret.min = range.min;
    332         if (range.max > ret.max)
    333             ret.max = range.max;
     364        ret.min = Math.min(ret.min, range.min);
     365        ret.max = Math.max(ret.max, range.max);
    334366    }
    335367    return ret;
    336368};
    337369
    338 Attack.prototype.GetBestAttackAgainst = function(target, allowCapture)
     370Attack.prototype.GetBestAttackAgainst = function(target, prefType)
    339371{
    340372    let cmpFormation = Engine.QueryInterface(target, IID_Formation);
    341373    if (cmpFormation)
     
    350382    }
    351383
    352384    let cmpIdentity = Engine.QueryInterface(target, IID_Identity);
    353     if (!cmpIdentity) 
     385    if (!cmpIdentity)
    354386        return undefined;
    355387
    356388    let targetClasses = cmpIdentity.GetClassesList();
     
    357389    let isTargetClass = function (className) { return targetClasses.indexOf(className) != -1; };
    358390
    359391    // Always slaughter domestic animals instead of using a normal attack
    360     if (isTargetClass("Domestic") && this.template.Slaughter) 
     392    if (isTargetClass("Domestic") && this.template.Slaughter)
    361393        return "Slaughter";
    362394
    363395    let attack = this;
     
    365397
    366398    let types = this.GetAttackTypes().filter(isAllowed);
    367399
    368     // check if the target is capturable
    369     let captureIndex = types.indexOf("Capture");
    370     if (captureIndex != -1)
     400    if (prefType && prefType != "Capture" && types.indexOf(prefType) != -1)
     401        return prefType;
     402    else if (!prefType || prefType == "Capture")
    371403    {
    372         let cmpCapturable = QueryMiragedInterface(target, IID_Capturable);
    373 
    374         let cmpPlayer = QueryOwnerInterface(this.entity);
    375         if (allowCapture && cmpPlayer && cmpCapturable && cmpCapturable.CanCapture(cmpPlayer.GetPlayerID()))
    376             return "Capture";
    377         // not captureable, so remove this attack
    378         types.splice(captureIndex, 1);
     404        // check if the target is capturable
     405        let captureIndex = types.indexOf("Capture");
     406        if (captureIndex != -1)
     407        {
     408            let cmpCapturable = QueryMiragedInterface(target, IID_Capturable);
     409            let cmpPlayer = QueryOwnerInterface(this.entity);
     410            if (cmpPlayer && cmpCapturable && cmpCapturable.CanCapture(cmpPlayer.GetPlayerID()))
     411                return "Capture";
     412            // not captureable, so remove this attack
     413            types.splice(captureIndex, 1);
     414        }
    379415    }
    380416
    381     let isPreferred = function (className) { return attack.GetPreferredClasses(className).some(isTargetClass); };
    382     let byPreference = function (a, b) { return (types.indexOf(a) + (isPreferred(a) ? types.length : 0) ) - (types.indexOf(b) + (isPreferred(b) ? types.length : 0) ); };
     417    // ignore charges for now: TODO implement these
     418    let chargeIndex = types.indexOf("Charge");
     419    if (chargeIndex != -1)
     420        types.splice(chargeIndex, 1);
    383421
    384     return types.sort(byPreference).pop();
     422    // only ranged and/or melee attack left
     423    // if one attacktype left choose this one
     424    if (types.indexOf("Melee") == -1 || types.indexOf("Ranged") == -1)
     425        return types[0];
     426
     427        // assume ranged and melee attack
     428        // TODO stop assuming that?
     429    let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     430    if (!cmpPosition || !cmpPosition.IsInWorld())
     431        return undefined;
     432    let selfPosition = cmpPosition.GetPosition();
     433    let cmpTargetPosition = Engine.QueryInterface(target, IID_Position);
     434    if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld())
     435        return undefined;
     436    let targetPosition = cmpTargetPosition.GetPosition();
     437    let horizDistance = targetPosition.horizDistanceTo(selfPosition);
     438    if (horizDistance <= this.template.ChangeDistance)
     439        return "Melee";
     440    return "Ranged"
     441
    385442};
    386443
    387444Attack.prototype.CompareEntitiesByPreference = function(a, b)
     
    478535    return attackBonus;
    479536};
    480537
     538Attack.prototype.GetAttackTypeFromOrder = function(prefType)
     539{
     540    let types = this.GetAttackTypes();
     541    for (let type of types)
     542        if ((this.template[type].AttackOrder && this.template[type].AttackOrder == prefType) || prefType == type)
     543            return type;
     544
     545    if (types.indexOf("Melee") != -1 && types.indexOf("Ranged") != -1)
     546        return undefined; // we have a problem, should never happen
     547    return types.indexOf("Melee") != -1 ? "Melee": "Ranged";
     548};
     549
    481550// Returns a 2d random distribution scaled for a spread of scale 1.
    482551// The current implementation is a 2d gaussian with sigma = 1
    483552Attack.prototype.GetNormalDistribution = function(){
     
    486555    let a = Math.random();
    487556    let b = Math.random();
    488557
    489     let c = Math.sqrt(-2*Math.log(a)) * Math.cos(2*Math.PI*b);
    490     let d = Math.sqrt(-2*Math.log(a)) * Math.sin(2*Math.PI*b);
     558    let c = Math.sqrt(-2 * Math.log(a)) * Math.cos(2 * Math.PI * b);
     559    let d = Math.sqrt(-2 * Math.log(a)) * Math.sin(2 * Math.PI * b);
    491560
    492561    return [c, d];
    493562};
     
    503572    if (type == "Ranged")
    504573    {
    505574        let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    506         let turnLength = cmpTimer.GetLatestTurnLength()/1000;
     575        let turnLength = cmpTimer.GetLatestTurnLength() / 1000;
    507576        // In the future this could be extended:
    508577        //  * Obstacles like trees could reduce the probability of the target being hit
    509578        //  * Obstacles like walls should block projectiles entirely
     
    535604
    536605        let horizDistance = targetPosition.horizDistanceTo(selfPosition);
    537606
    538         // This is an approximation of the time ot the target, it assumes that the target has a constant radial
    539         // velocity, but since units move in straight lines this is not true.  The exact value would be more 
    540         // difficult to calculate and I think this is sufficiently accurate.  (I tested and for cavalry it was 
     607        // This is an approximation of the time to the target, it assumes that the target has a constant radial
     608        // velocity, but since units move in straight lines this is not true.  The exact value would be more
     609        // difficult to calculate and I think this is sufficiently accurate.  (I tested and for cavalry it was
    541610        // about 5% of the units radius out in the worst case)
    542611        let timeToTarget = horizDistance / (horizSpeed - radialSpeed);
    543612
     
    620689Attack.prototype.InterpolatedLocation = function(ent, lateness)
    621690{
    622691    let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    623     let turnLength = cmpTimer.GetLatestTurnLength()/1000;
     692    let turnLength = cmpTimer.GetLatestTurnLength() / 1000;
    624693    let cmpTargetPosition = Engine.QueryInterface(ent, IID_Position);
    625694    if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) // TODO: handle dead target properly
    626695        return undefined;
     
    658727        let d = Vector3D.sub(point, targetPosition);
    659728        d = Vector2D.from3D(d).rotate(-angle);
    660729
    661         return d.x < Math.abs(targetShape.width/2) && d.y < Math.abs(targetShape.depth/2);
     730        return d.x < Math.abs(targetShape.width / 2) && d.y < Math.abs(targetShape.depth / 2);
    662731    }
    663732};
    664733
     
    740809        return;
    741810
    742811    for (let type of this.GetAttackTypes())
    743         if (msg.valueNames.indexOf("Attack/"+type+"/MaxRange") !== -1)
     812        if (msg.valueNames.indexOf("Attack/" + type + "/MaxRange") !== -1)
    744813        {
    745814            cmpUnitAI.UpdateRangeQueries();
    746815            return;
  • binaries/data/mods/public/simulation/components/GuiInterface.js

     
    17481748    if (!cmpAttack)
    17491749        return false;
    17501750
    1751     let cmpEntityPlayer = QueryOwnerInterface(data.entity, IID_Player);
    1752     let cmpTargetPlayer = QueryOwnerInterface(data.target, IID_Player);
    1753     if (!cmpEntityPlayer || !cmpTargetPlayer)
     1751    return cmpAttack.CanAttack(data.target);
     1752};
     1753
     1754GuiInterface.prototype.CanAttackWithType = function(player, data)
     1755{
     1756    let cmpAttack = Engine.QueryInterface(data.entity, IID_Attack);
     1757    if (!cmpAttack)
    17541758        return false;
    17551759
    1756     // if the owner is an enemy, it's up to the attack component to decide
    1757     if (cmpEntityPlayer.IsEnemy(cmpTargetPlayer.GetPlayerID()))
    1758         return cmpAttack.CanAttack(data.target);
     1760    return cmpAttack.CanAttackWithType(data.target, data.type);
     1761};
    17591762
    1760     return false;
     1763GuiInterface.prototype.GetAttackGetAttackTypeFromOrder = function(player, data)
     1764{
     1765    let cmpAttack = Engine.QueryInterface(data.entity, IID_Attack);
     1766    if (!cmpAttack)
     1767        return undefined;
     1768
     1769    return cmpAttack.GetAttackGetAttackTypeFromOrder(data.attackOrder);
    17611770};
    17621771
    17631772/*
     
    19031912    "GetTradingDetails": 1,
    19041913    "CanCapture": 1,
    19051914    "CanAttack": 1,
     1915    "CanAttackWithType": 1,
     1916    "GetAttackGetAttackTypeFromOrder": 1,
    19061917    "GetBatchTime": 1,
    19071918
    19081919    "IsMapRevealed": 1,
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    416416        }
    417417
    418418        // Work out how to attack the given target
    419         var type = this.GetBestAttackAgainst(this.order.data.target, this.order.data.allowCapture);
     419        let type = this.GetBestAttackAgainst(this.order.data.target, this.order.data.prefType);
    420420        if (!type)
    421421        {
    422422            // Oops, we can't attack at all
     
    583583                return;
    584584            }
    585585
    586             this.PushOrderFront("Attack", { "target": this.order.data.target, "force": false, "hunting": true, "allowCapture": false });
     586            this.PushOrderFront("Attack", { "target": this.order.data.target, "force": false, "hunting": true, "prefType": undefined });
    587587            return;
    588588        }
    589589
     
    838838        },
    839839
    840840        "Order.Attack": function(msg) {
    841             var target = msg.data.target;
    842             var allowCapture = msg.data.allowCapture;
    843             var cmpTargetUnitAI = Engine.QueryInterface(target, IID_UnitAI);
     841            let target = msg.data.target;
     842            let prefType = msg.data.prefType;
     843            let cmpTargetUnitAI = Engine.QueryInterface(target, IID_UnitAI);
    844844            if (cmpTargetUnitAI && cmpTargetUnitAI.IsFormationMember())
    845845                target = cmpTargetUnitAI.GetFormationController();
    846846
     
    859859                this.FinishOrder();
    860860                return;
    861861            }
    862             this.CallMemberFunction("Attack", [target, false, allowCapture]);
     862            this.CallMemberFunction("Attack", [target, false, prefType]);
    863863            if (cmpAttack.CanAttackAsFormation())
    864864                this.SetNextState("COMBAT.ATTACKING");
    865865            else
     
    914914                    return;
    915915                }
    916916
    917                 this.PushOrderFront("Attack", { "target": msg.data.target, "hunting": true, "allowCapture": false });
     917                this.PushOrderFront("Attack", { "target": msg.data.target, "hunting": true, "prefType": undefined });
    918918                return;
    919919            }
    920920
     
    11511151
    11521152                "MoveCompleted": function(msg) {
    11531153                    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
    1154                     this.CallMemberFunction("Attack", [this.order.data.target, false, this.order.data.allowCapture]);
     1154                    this.CallMemberFunction("Attack", [this.order.data.target, false, this.order.data.prefType]);
    11551155                    if (cmpAttack.CanAttackAsFormation())
    11561156                        this.SetNextState("COMBAT.ATTACKING");
    11571157                    else
     
    11621162            "ATTACKING": {
    11631163                // Wait for individual members to finish
    11641164                "enter": function(msg) {
    1165                     var target = this.order.data.target;
    1166                     var allowCapture = this.order.data.allowCapture;
     1165                    let target = this.order.data.target;
     1166                    let prefType = this.order.data.prefType;
    11671167                    // Check if we are already in range, otherwise walk there
    11681168                    if (!this.CheckTargetAttackRange(target, target))
    11691169                    {
     
    11701170                        if (this.TargetIsAlive(target) && this.CheckTargetVisible(target))
    11711171                        {
    11721172                            this.FinishOrder();
    1173                             this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": allowCapture });
     1173                            this.PushOrderFront("Attack", { "target": target, "force": false, "prefType": prefType });
    11741174                            return true;
    11751175                        }
    11761176                        this.FinishOrder();
     
    11861186                },
    11871187
    11881188                "Timer": function(msg) {
    1189                     var target = this.order.data.target;
    1190                     var allowCapture = this.order.data.allowCapture;
     1189                    let target = this.order.data.target;
     1190                    let prefType = this.order.data.prefType;
    11911191                    // Check if we are already in range, otherwise walk there
    11921192                    if (!this.CheckTargetAttackRange(target, target))
    11931193                    {
     
    11941194                        if (this.TargetIsAlive(target) && this.CheckTargetVisible(target))
    11951195                        {
    11961196                            this.FinishOrder();
    1197                             this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": allowCapture });
     1197                            this.PushOrderFront("Attack", { "target": target, "force": false, "prefType": prefType });
    11981198                            return;
    11991199                        }
    12001200                        this.FinishOrder();
     
    14061406
    14071407            // target the unit
    14081408            if (this.CheckTargetVisible(msg.data.attacker))
    1409                 this.PushOrderFront("Attack", { "target": msg.data.attacker, "force": false, "allowCapture": true });
     1409                this.PushOrderFront("Attack", { "target": msg.data.attacker, "force": false, "prefType": undefined });
    14101410            else
    14111411            {
    14121412                var cmpPosition = Engine.QueryInterface(msg.data.attacker, IID_Position);
     
    18011801                        // Can't reach it - try to chase after it
    18021802                        if (this.ShouldChaseTargetedEntity(target, this.order.data.force))
    18031803                        {
     1804                            if (!this.order.data.force)
     1805                                this.order.data.attackType = this.GetBestAttackAgainst(target, undefined);
    18041806                            if (this.MoveToTargetAttackRange(target, this.order.data.attackType))
    18051807                            {
    18061808                                this.SetNextState("COMBAT.CHASING");
     
    19121914                        // Can't reach it - try to chase after it
    19131915                        if (this.ShouldChaseTargetedEntity(target, this.order.data.force))
    19141916                        {
     1917                            if (!this.order.data.force)
     1918                                this.order.data.attackType = this.GetBestAttackAgainst(target, undefined);
    19151919                            if (this.MoveToTargetRange(target, IID_Attack, this.order.data.attackType))
    19161920                            {
    19171921                                this.SetNextState("COMBAT.CHASING");
     
    45354539    return distance < range;
    45364540};
    45374541
    4538 UnitAI.prototype.GetBestAttackAgainst = function(target, allowCapture)
     4542UnitAI.prototype.GetBestAttackAgainst = function(target, prefType)
    45394543{
    45404544    var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
    45414545    if (!cmpAttack)
    45424546        return undefined;
    4543     return cmpAttack.GetBestAttackAgainst(target, allowCapture);
     4547    return cmpAttack.GetBestAttackAgainst(target, prefType);
    45444548};
    45454549
    45464550UnitAI.prototype.GetAttackBonus = function(type, target)
     
    45624566    if (!target)
    45634567        return false;
    45644568
    4565     this.PushOrderFront("Attack", { "target": target, "force": false, "forceResponse": forceResponse, "allowCapture": true });
     4569    this.PushOrderFront("Attack", { "target": target, "force": false, "forceResponse": forceResponse, "prefType": undefined });
    45664570    return true;
    45674571};
    45684572
     
    45754579{
    45764580    var target = ents.find(target =>
    45774581        this.CanAttack(target, forceResponse)
    4578         && this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, true))
     4582        && this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, true, undefined))
    45794583        && (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target))
    45804584    );
    45814585    if (!target)
    45824586        return false;
    45834587
    4584     this.PushOrderFront("Attack", { "target": target, "force": false, "forceResponse": forceResponse, "allowCapture": true });
     4588    this.PushOrderFront("Attack", { "target": target, "force": false, "forceResponse": forceResponse, "prefType": undefined });
    45854589    return true;
    45864590};
    45874591
     
    49784982 * to a player order, and so is forced.
    49794983 * If targetClasses is given, only entities matching the targetClasses can be attacked.
    49804984 */
    4981 UnitAI.prototype.WalkAndFight = function(x, z, targetClasses, queued)
     4985UnitAI.prototype.WalkAndFight = function(x, z, targetClasses, queued, prefType)
    49824986{
    4983     this.AddOrder("WalkAndFight", { "x": x, "z": z, "targetClasses": targetClasses, "force": true }, queued);
     4987    this.AddOrder("WalkAndFight", { "x": x, "z": z, "targetClasses": targetClasses, "force": true, "prefType": prefType }, queued);
    49844988};
    49854989
    49864990/**
     
    50015005/**
    50025006 * Adds attack order to the queue, forced by the player.
    50035007 */
    5004 UnitAI.prototype.Attack = function(target, queued, allowCapture)
     5008UnitAI.prototype.Attack = function(target, queued, prefType)
    50055009{
    50065010    if (!this.CanAttack(target))
    50075011    {
     
    50135017            this.WalkToTarget(target, queued);
    50145018        return;
    50155019    }
    5016     this.AddOrder("Attack", { "target": target, "force": true, "allowCapture": allowCapture}, queued);
     5020
     5021    this.AddOrder("Attack", { "target": target, "force": true, "prefType": prefType }, queued);
    50175022};
    50185023
    50195024/**
     
    54305435                    if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ])
    54315436                        continue;
    54325437                }
    5433                 this.PushOrderFront("Attack", { "target": targ, "force": true, "allowCapture": true });
     5438                this.PushOrderFront("Attack", { "target": targ, "force": true, "prefType": undefined });
    54345439                return true;
    54355440            }
    54365441        }
     
    54565461            if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ])
    54575462                continue;
    54585463        }
    5459         this.PushOrderFront("Attack", { "target": targ, "force": true, "allowCapture": true });
     5464        this.PushOrderFront("Attack", { "target": targ, "force": true, "prefType": undefined });
    54605465        return true;
    54615466    }
    54625467    return false;
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    157157
    158158    "attack-walk": function(player, cmd, data)
    159159    {
    160         GetFormationUnitAIs(data.entities, player).forEach(cmpUnitAI => {
    161             cmpUnitAI.WalkAndFight(cmd.x, cmd.z, cmd.targetClasses, cmd.queued);
    162         });
     160        for (let ent of data.entities)
     161        {
     162            let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     163            let cmpAttack = Engine.QueryInterface(ent, IID_Attack);
     164            if (cmpUnitAI && cmpAttack)
     165                cmpUnitAI.WalkAndFight(cmd.x, cmd.z, cmd.targetClasses, cmd.queued, cmpAttack.GetAttackTypeFromOrder(cmd.prefType));
     166        }
    163167    },
    164168
    165169    "attack": function(player, cmd, data)
     
    167171        if (g_DebugCommands && !(IsOwnedByEnemyOfPlayer(player, cmd.target) || IsOwnedByNeutralOfPlayer(player, cmd.target)))
    168172            warn("Invalid command: attack target is not owned by enemy of player "+player+": "+uneval(cmd));
    169173
    170         let allowCapture = cmd.allowCapture || cmd.allowCapture == null;
    171174        // See UnitAI.CanAttack for target checks
    172         GetFormationUnitAIs(data.entities, player).forEach(cmpUnitAI => {
    173             cmpUnitAI.Attack(cmd.target, cmd.queued, allowCapture);
    174         });
     175        for (let ent of data.entities)
     176        {
     177            let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     178            let cmpAttack = Engine.QueryInterface(ent, IID_Attack);
     179            if (cmpUnitAI && cmpAttack)
     180                cmpUnitAI.Attack(cmd.target, cmd.queued, cmpAttack.GetAttackTypeFromOrder(cmd.prefType));
     181        }
    175182    },
    176183
    177184    "heal": function(player, cmd, data)
  • binaries/data/mods/public/simulation/templates/template_unit_infantry_melee_swordsman.xml

     
    55    <Pierce>5</Pierce>
    66  </Armour>
    77  <Attack>
     8    <ChangeDistance>15</ChangeDistance>
     9    <Charge>
     10      <Hack>12.0</Hack>
     11    </Charge>
    812    <Melee>
     13      <AttackOrder>primary</AttackOrder>
    914      <Hack>5.5</Hack>
    1015      <Pierce>0</Pierce>
    1116      <MaxRange>2.0</MaxRange>
    1217      <RepeatTime>750</RepeatTime>
    1318    </Melee>
    14     <Charge>
    15       <Hack>12.0</Hack>
    16     </Charge>
     19    <Ranged>
     20      <AttackOrder>secondary</AttackOrder>
     21      <Hack>0</Hack>
     22      <Pierce>14.0</Pierce>
     23      <Crush>0</Crush>
     24      <MaxRange>24.0</MaxRange>
     25      <MinRange>7.0</MinRange>
     26      <ProjectileSpeed>56.0</ProjectileSpeed>
     27      <PrepareTime>2500</PrepareTime>
     28      <RepeatTime>2500</RepeatTime>
     29      <Spread>1.3</Spread>
     30    </Ranged>
    1731  </Attack>
    1832  <Cost>
    1933    <Resources>
  • binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged.xml

     
    66    <Crush>10</Crush>
    77  </Armour>
    88  <Attack>
     9    <ChangeDistance>15</ChangeDistance>
     10    <Melee>
     11      <AttackOrder>secondary</AttackOrder>
     12      <Hack>3</Hack>
     13      <Pierce>0</Pierce>
     14      <Crush>0</Crush>
     15      <MaxRange>4.0</MaxRange>
     16      <RepeatTime>1000</RepeatTime>
     17      <PreferredClasses datatype="tokens">Human</PreferredClasses>
     18    </Melee>
    919    <Ranged>
     20      <AttackOrder>primary</AttackOrder>
    1021      <Hack>0</Hack>
    1122      <Pierce>1.5</Pierce>
    1223      <Crush>0</Crush>
  • binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_archer.xml

     
    1010      <Pierce>6.0</Pierce>
    1111      <Crush>0</Crush>
    1212      <MaxRange>72.0</MaxRange>
    13       <MinRange>0.0</MinRange>
     13      <MinRange>10.0</MinRange>
    1414      <ProjectileSpeed>120.0</ProjectileSpeed>
    1515      <PrepareTime>1000</PrepareTime>
    1616      <RepeatTime>1000</RepeatTime>
  • binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_javelinist.xml

     
    1010      <Pierce>18.0</Pierce>
    1111      <Crush>0</Crush>
    1212      <MaxRange>24.0</MaxRange>
    13       <MinRange>0.0</MinRange>
     13      <MinRange>7.0</MinRange>
    1414      <ProjectileSpeed>56.0</ProjectileSpeed>
    1515      <PrepareTime>1250</PrepareTime>
    1616      <RepeatTime>1250</RepeatTime>
  • binaries/data/mods/public/simulation/templates/template_unit_infantry_ranged_slinger.xml

     
    1010      <Pierce>9.5</Pierce>
    1111      <Crush>2.0</Crush>
    1212      <MaxRange>48.0</MaxRange>
    13       <MinRange>0.0</MinRange>
     13      <MinRange>10.0</MinRange>
    1414      <ProjectileSpeed>60.0</ProjectileSpeed>
    1515      <PrepareTime>1000</PrepareTime>
    1616      <RepeatTime>1000</RepeatTime>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_unit_mechanical_ship">
    33  <Attack>
     4    <ChangeDistance>15</ChangeDistance>
     5    <Melee>
     6      <AttackOrder>secondary</AttackOrder>
     7      <Hack>0.0</Hack>
     8      <Pierce>0.0</Pierce>
     9      <Crush>100.0</Crush>
     10      <MaxRange>20</MaxRange>
     11      <RepeatTime>1500</RepeatTime>
     12      <PreferredClasses datatype="tokens">Ship Structure</PreferredClasses>
     13    </Melee>
    414    <Ranged>
     15      <AttackOrder>primary</AttackOrder>
    516      <Hack>0.0</Hack>
    6       <Pierce>35.0</Pierce>
     17      <Pierce>25.0</Pierce>
    718      <Crush>0.0</Crush>
    819      <MaxRange>55.0</MaxRange>
    920      <MinRange>0.0</MinRange>
  • binaries/data/mods/public/simulation/templates/units/pers_champion_infantry.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<Entity parent="template_unit_champion_infantry_spearman">
     3  <Attack>
     4    <ChangeDistance>25</ChangeDistance>
     5    <Melee>
     6      <AttackOrder>primary</AttackOrder>
     7    </Melee>
     8    <Ranged>
     9      <AttackOrder>secondary</AttackOrder>
     10      <Hack>0</Hack>
     11      <Pierce>6.0</Pierce>
     12      <Crush>0</Crush>
     13      <MaxRange>65.0</MaxRange>
     14      <MinRange>10.0</MinRange>
     15      <ProjectileSpeed>120.0</ProjectileSpeed>
     16      <PrepareTime>1000</PrepareTime>
     17      <RepeatTime>1000</RepeatTime>
     18      <Spread>3.0</Spread>
     19    </Ranged>
     20  </Attack>
    321  <Identity>
    422    <Civ>pers</Civ>
    523    <GenericName>Persian Immortal</GenericName>