Ticket #563: AnimalAIm-06-02-2010.patch
File AnimalAIm-06-02-2010.patch, 25.0 KB (added by , 13 years ago) |
---|
-
binaries/data/mods/public/simulation/components/UnitAI.js
5 5 "<a:example/>" + 6 6 "<element name='FormationController'>" + 7 7 "<data type='boolean'/>" + 8 "</element>" + 9 "<element name='IsAnimal'>" + 10 "<data type='boolean'/>" + 8 11 "</element>"; 9 12 10 13 // Very basic stance support (currently just for test maps where we don't want … … 44 47 // ignore attacker 45 48 }, 46 49 50 "HealthChanged": function(msg) { 51 // ignore 52 }, 47 53 48 54 // Formation handlers: 49 55 … … 788 794 }, 789 795 790 796 }, 797 798 "ANIMAL": { 799 "MoveCompleted": function() { 800 // ignore spurious movement messages 801 // (these can happen when stopping moving at the same time 802 // as switching states) 803 }, 804 805 "MoveStarted": function() { 806 // ignore spurious movement messages 807 }, 808 809 "HealthChanged": function(msg) { 810 // If we died (got reduced to 0 hitpoints), stop the AI and act like a corpse 811 if (msg.to == 0) 812 this.SetNextState("CORPSE"); 813 }, 814 815 "ResourceGather": function(msg) { 816 // If someone's carving chunks of meat off us, then run away 817 if(this.behavior == "SKITTISH" || this.behavior == "PASSIVE") 818 { 819 this.MoveAwayFrom(msg.gatherer, +this.FleeDistance); 820 this.SetNextState("FLEEING"); 821 this.PlaySound("panic"); 822 } 823 else if(this.behavior == "VIOLENT" || this.behavior == "AGGRESSIVE" 824 || this.behavior == "DEFENSIVE") 825 { 826 this.Riposte(msg.gatherer); 827 } 828 }, 829 830 "Attacked": function(msg) { 831 if(this.behavior == "SKITTISH" || this.behavior == "PASSIVE") 832 { 833 this.MoveAwayFrom(msg.data.attacker, +this.FleeDistance); 834 this.SetNextState("FLEEING"); 835 this.PlaySound("panic"); 836 } 837 else if(this.behavior == "VIOLENT" || this.behavior == "AGGRESSIVE" || this.behavior == "DEFENSIVE") 838 { 839 this.Riposte(msg.data.attacker); 840 } 841 }, 842 843 844 "LosRangeUpdate": function(msg) { 845 if(this.behavior == "SKITTISH") 846 { 847 if(msg.data.added.length>0) 848 { 849 this.MoveAwayFrom(msg.data.added[0], +this.FleeDistance); 850 this.SetNextState("FLEEING"); 851 this.PlaySound("panic"); 852 return; 853 } 854 } 855 // Start attacking one of the newly-seen enemy (if any) 856 else if(this.behavior == "VIOLENT") 857 this.AttackVisibleEntity(msg.data.added); 858 }, 859 860 "CORPSE": { 861 "enter": function() { 862 this.StopMoving(); 863 }, 864 865 "Attacked": function(msg) { 866 // Do nothing, because we're dead already 867 }, 868 }, 869 870 "ROAMING": { 871 "enter": function() { 872 // Walk in a random direction 873 this.SelectAnimation("walk", false, this.GetWalkSpeed()); 874 this.MoveRandomly(+this.RoamDistance); 875 // Set a random timer to switch to feeding state 876 this.StartTimer(RandomInt(+this.RoamTimeMin, +this.RoamTimeMax)); 877 }, 878 879 "leave": function() { 880 this.StopTimer(); 881 }, 882 883 "Timer": function(msg) { 884 this.SetNextState("FEEDING"); 885 }, 886 887 "MoveCompleted": function() { 888 this.MoveRandomly(+this.RoamDistance); 889 }, 890 }, 891 892 "FEEDING": { 893 "enter": function() { 894 // Stop and eat for a while 895 this.SelectAnimation("feeding"); 896 this.StopMoving(); 897 898 if (this.behavior == "AGGRESSIVE" && this.losRangeQuery) 899 { 900 var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 901 this.residEnts = rangeMan.ResetActiveQuery(this.losRangeQuery); 902 } 903 904 this.StartTimer(RandomInt(+this.FeedTimeMin, +this.FeedTimeMax)); 905 }, 906 907 "leave": function() { 908 this.StopTimer(); 909 }, 910 911 "MoveCompleted": function() { }, 912 913 "Timer": function(msg) { 914 if (this.behavior == "AGGRESSIVE" && this.losRangeQuery) 915 { 916 var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 917 var ents = rangeMan.ResetActiveQuery(this.losRangeQuery); 918 for each (var ent in this.residEnts) 919 { 920 for each (var tent in ents) 921 { 922 if (ent == tent) 923 { 924 this.Riposte(ent); 925 this.StopTimer(); 926 return; 927 } 928 } 929 } 930 } 931 this.SetNextState("ROAMING"); 932 }, 933 }, 934 935 "FLEEING": { 936 "enter": function() { 937 // Run quickly 938 var speed = this.GetRunSpeed(); 939 this.SelectAnimation("run", false, speed); 940 this.SetMoveSpeed(speed); 941 }, 942 943 "leave": function() { 944 // Reset normal speed 945 this.SetMoveSpeed(this.GetWalkSpeed()); 946 }, 947 948 "MoveCompleted": function() { 949 // When we've run far enough, go back to the roaming state 950 this.SetNextState("ROAMING"); 951 }, 952 953 "Timer": function(msg) { 954 } 955 }, 956 957 "Order.Attack": function(msg) { 958 // Work out how to attack the given target 959 var type = this.GetBestAttack(); 960 if (!type) 961 { 962 // Oops, we can't attack at all 963 return; 964 } 965 this.attackType = type; 966 967 // Try to move within attack range 968 if (this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType)) 969 { 970 // We've started walking to the given point 971 this.SetNextState("COMBAT.APPROACHING"); 972 } 973 else 974 { 975 // We are already at the target, or can't move at all, 976 // so try attacking it from here. 977 // TODO: need better handling of the can't-reach-target case 978 this.SetNextState("COMBAT.ATTACKING"); 979 } 980 }, 981 982 "COMBAT": { 983 "Attacked": function(msg) { 984 }, 985 986 "LosRangeUpdate": function(msg) { 987 }, 988 989 "APPROACHING": { 990 "enter": function() { 991 this.SelectAnimation("walk", false, this.GetWalkSpeed()); 992 }, 993 "MoveCompleted": function() { 994 this.SetNextState("ATTACKING"); 995 }, 996 }, 997 998 "ATTACKING": { 999 "enter": function() { 1000 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 1001 this.attackTimers = cmpAttack.GetTimers(this.attackType); 1002 this.SelectAnimation("melee", false, 1.0, "attack"); 1003 //this.SetAnimationSync(this.attackTimers.prepare, this.attackTimers.repeat); 1004 this.StartTimer(this.attackTimers.prepare, this.attackTimers.repeat); 1005 // TODO: we should probably only bother syncing projectile attacks, not melee 1006 }, 1007 "leave": function() { 1008 this.StopTimer(); 1009 }, 1010 "Timer": function(msg) { 1011 // Check we can still reach the target 1012 if (this.CheckTargetRange(this.order.data.target, IID_Attack, this.attackType)) 1013 { 1014 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 1015 cmpAttack.PerformAttack(this.attackType, this.order.data.target); 1016 } 1017 else 1018 { 1019 if (this.losRangeQuery) 1020 { 1021 // check if the raget is still in sight 1022 var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 1023 var ents = rangeMan.ResetActiveQuery(this.losRangeQuery); 1024 for each (var ent in ents) 1025 { 1026 if (ent == this.order.data.target) 1027 { 1028 // Try to chase after it 1029 if (this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType)) 1030 { 1031 this.SetNextState("CHASING"); 1032 this.StopTimer(); 1033 return; 1034 } 1035 } 1036 } 1037 } 1038 this.SetNextState("ANIMAL.ROAMING"); 1039 } 1040 }, 1041 }, //end ANIMAL.COMBAT.ATTACKING 1042 1043 "CHASING": { 1044 "enter": function() { 1045 this.SelectAnimation("walk", false, this.GetWalkSpeed()); 1046 }, 1047 "MoveCompleted": function() { 1048 this.SetNextState("ATTACKING"); 1049 }, 1050 }, 1051 1052 }, //end ANIMAL.COMBAT 1053 }, //end ANIMAL 791 1054 }; 792 1055 793 1056 var UnitFsm = new FSM(UnitFsmSpec); … … 814 1077 815 1078 UnitAI.prototype.OnCreate = function() 816 1079 { 817 if (this.IsFormationController()) 818 UnitFsm.Init(this, "FORMATIONCONTROLLER.IDLE"); 1080 if (this.template.IsAnimal == "true") 1081 { 1082 this.InitAnimalAI(); 1083 var startingState = this.NaturalBehaviour.toUpperCase(this.NaturalBehaviour); 1084 this.behavior = startingState; 1085 1086 startingState = "ANIMAL.FEEDING"; 1087 UnitFsm.Init(this, startingState); 1088 } 819 1089 else 820 UnitFsm.Init(this, "INDIVIDUAL.IDLE"); 1090 { 1091 if (this.IsFormationController()) 1092 UnitFsm.Init(this, "FORMATIONCONTROLLER.IDLE"); 1093 else 1094 UnitFsm.Init(this, "INDIVIDUAL.IDLE"); 1095 } 821 1096 }; 822 1097 823 1098 UnitAI.prototype.OnOwnershipChanged = function(msg) … … 854 1129 var range = cmpVision.GetRange(); 855 1130 856 1131 var players = []; 857 858 1132 1133 if (owner != -1) 859 1134 { 860 1135 // If unit not just killed, get enemy players via diplomacy 861 1136 var player = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player); … … 863 1138 // Get our diplomacy array 864 1139 var diplomacy = player.GetDiplomacy(); 865 1140 var numPlayers = playerMan.GetNumPlayers(); 866 1141 867 1142 for (var i = 1; i < numPlayers; ++i) 868 1143 { 869 1144 // Exclude gaia, allies, and self 870 1145 // TODO: How to handle neutral players - Special query to attack military only? 871 if (i != owner && diplomacy[i - 1] < 0)1146 if (i != owner && (diplomacy[i - 1] < 0 || owner == 0)) 872 1147 players.push(i); 873 1148 } 874 1149 } … … 1546 1821 return true; 1547 1822 }; 1548 1823 1824 //Animal specific functions 1549 1825 1826 UnitAI.prototype.OnHealthChanged = function(msg) 1827 { 1828 UnitFsm.ProcessMessage(this, {"type": "HealthChanged", "from": msg.from, "to": msg.to}); 1829 }; 1830 1831 UnitAI.prototype.MoveRandomly = function(distance) 1832 { 1833 // We want to walk in a random direction, but avoid getting stuck 1834 // in obstacles or narrow spaces. 1835 // So pick a circular range from approximately our current position, 1836 // and move outwards to the nearest point on that circle, which will 1837 // lead to us avoiding obstacles and moving towards free space. 1838 1839 // TODO: we probably ought to have a 'home' point, and drift towards 1840 // that, so we don't spread out all across the whole map 1841 1842 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 1843 if (!cmpPosition) 1844 return; 1845 1846 if (!cmpPosition.IsInWorld()) 1847 return; 1848 1849 var pos = cmpPosition.GetPosition(); 1850 1851 var jitter = 0.5; 1852 1853 // Randomly adjust the range's center a bit, so we tend to prefer 1854 // moving in random directions (if there's nothing in the way) 1855 var tx = pos.x + (2*Math.random()-1)*jitter; 1856 var tz = pos.z + (2*Math.random()-1)*jitter; 1857 1858 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 1859 cmpMotion.MoveToPointRange(tx, tz, distance, distance); 1860 }; 1861 1862 UnitAI.prototype.MoveAwayFrom = function(ent, distance) 1863 { 1864 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 1865 cmpMotion.MoveToTargetRange(ent, distance, distance); 1866 }; 1867 1868 UnitAI.prototype.SetMoveSpeed = function(speed) 1869 { 1870 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 1871 cmpMotion.SetSpeed(speed); 1872 }; 1873 1874 UnitAI.prototype.InitAnimalAI = function() 1875 { 1876 var cmpAnimalAI = Engine.QueryInterface(this.entity, IID_AnimalAI); 1877 if (!cmpAnimalAI) 1878 return; 1879 1880 this.NaturalBehaviour = cmpAnimalAI.GetNaturalBehaviour(); 1881 this.RoamDistance = cmpAnimalAI.GetRoamDistance(); 1882 this.FleeDistance = cmpAnimalAI.GetFleeDistance(); 1883 this.RoamTimeMin = cmpAnimalAI.GetRoamTimeMin(); 1884 this.RoamTimeMax = cmpAnimalAI.GetRoamTimeMax(); 1885 this.FeedTimeMin = cmpAnimalAI.GetFeedTimeMin(); 1886 this.FeedTimeMax = cmpAnimalAI.GetFeedTimeMax(); 1887 }; 1888 1889 UnitAI.prototype.Riposte = function(attacker) 1890 { 1891 // Default behaviour: attack back at our attacker 1892 if (this.CanAttack(attacker)) 1893 { 1894 this.order = { "type": "Attack", "data": { "target": attacker }}; 1895 UnitFsm.ProcessMessage(this, {"type": "Order.Attack", "data": this.order.data}); 1896 return true; 1897 } 1898 return false; 1899 }; 1900 1550 1901 Engine.RegisterComponentType(IID_UnitAI, "UnitAI", UnitAI); -
binaries/data/mods/public/simulation/components/AnimalAI.js
30 30 "<ref name='positiveDecimal'/>" + 31 31 "</element>"; 32 32 33 var AnimalFsmSpec = {34 35 "MoveCompleted": function() {36 // ignore spurious movement messages37 // (these can happen when stopping moving at the same time38 // as switching states)39 },40 41 "MoveStarted": function() {42 // ignore spurious movement messages43 },44 45 "HealthChanged": function(msg) {46 // If we died (got reduced to 0 hitpoints), stop the AI and act like a corpse47 if (msg.to == 0)48 this.SetNextState("CORPSE");49 },50 51 "CORPSE": {52 "enter": function() {53 this.StopMoving();54 },55 56 "Attacked": function(msg) {57 // Do nothing, because we're dead already58 },59 },60 61 "SKITTISH": {62 63 "Attacked": function(msg) {64 // If someone's attacking us, then run away65 this.MoveAwayFrom(msg.data.attacker, +this.template.FleeDistance);66 this.SetNextState("FLEEING");67 this.PlaySound("panic");68 },69 70 "ROAMING": {71 "enter": function() {72 // Walk in a random direction73 this.SelectAnimation("walk", false, this.GetWalkSpeed());74 this.MoveRandomly(+this.template.RoamDistance);75 // Set a random timer to switch to feeding state76 this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));77 },78 79 "leave": function() {80 this.StopTimer();81 },82 83 "Timer": function(msg) {84 this.SetNextState("FEEDING");85 },86 87 "MoveCompleted": function() {88 this.MoveRandomly(+this.template.RoamDistance);89 },90 },91 92 "FEEDING": {93 "enter": function() {94 // Stop and eat for a while95 this.SelectAnimation("feeding");96 this.StopMoving();97 this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));98 },99 100 "leave": function() {101 this.StopTimer();102 },103 104 "MoveCompleted": function() { },105 106 "Timer": function(msg) {107 this.SetNextState("ROAMING");108 },109 },110 111 "FLEEING": {112 "enter": function() {113 // Run quickly114 var speed = this.GetRunSpeed();115 this.SelectAnimation("run", false, speed);116 this.SetMoveSpeed(speed);117 },118 119 "leave": function() {120 // Reset normal speed121 this.SetMoveSpeed(this.GetWalkSpeed());122 },123 124 "MoveCompleted": function() {125 // When we've run far enough, go back to the roaming state126 this.SetNextState("ROAMING");127 },128 },129 },130 131 "PASSIVE": {132 133 "Attacked": function(msg) {134 // Do nothing, just let them kill us135 },136 137 "ROAMING": {138 "enter": function() {139 // Walk in a random direction140 this.SelectAnimation("walk", false, this.GetWalkSpeed());141 this.MoveRandomly(+this.template.RoamDistance);142 // Set a random timer to switch to feeding state143 this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));144 },145 146 "leave": function() {147 this.StopTimer();148 },149 150 "Timer": function(msg) {151 this.SetNextState("FEEDING");152 },153 154 "MoveCompleted": function() {155 this.MoveRandomly(+this.template.RoamDistance);156 },157 },158 159 "FEEDING": {160 "enter": function() {161 // Stop and eat for a while162 this.SelectAnimation("feeding");163 this.StopMoving();164 this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));165 },166 167 "leave": function() {168 this.StopTimer();169 },170 171 "MoveCompleted": function() { },172 173 "Timer": function(msg) {174 this.SetNextState("ROAMING");175 },176 },177 },178 179 };180 181 var AnimalFsm = new FSM(AnimalFsmSpec);182 183 33 AnimalAI.prototype.Init = function() 184 34 { 185 35 }; 186 36 187 // FSM linkage functions: 188 189 AnimalAI.prototype.OnCreate = function() 37 AnimalAI.prototype.GetNaturalBehaviour = function() 190 38 { 191 var startingState = this.template.NaturalBehaviour; 192 startingState = startingState.toUpperCase(startingState); 193 194 if (startingState == "SKITTISH") 195 startingState = startingState + ".FEEDING"; 196 else 197 startingState = "PASSIVE.FEEDING"; 198 199 AnimalFsm.Init(this, startingState); 39 return this.template.NaturalBehaviour; 200 40 }; 201 41 202 AnimalAI.prototype. SetNextState = function(state)42 AnimalAI.prototype.GetRoamDistance = function() 203 43 { 204 AnimalFsm.SetNextState(this, state);44 return this.template.RoamDistance; 205 45 }; 206 46 207 AnimalAI.prototype. DeferMessage = function(msg)47 AnimalAI.prototype.GetFleeDistance = function() 208 48 { 209 AnimalFsm.DeferMessage(this, msg);49 return this.template.FleeDistance; 210 50 }; 211 51 212 AnimalAI.prototype. OnMotionChanged = function(msg)52 AnimalAI.prototype.GetRoamTimeMin = function() 213 53 { 214 if (msg.starting && !msg.error) 215 { 216 AnimalFsm.ProcessMessage(this, {"type": "MoveStarted", "data": msg}); 217 } 218 else if (!msg.starting || msg.error) 219 { 220 AnimalFsm.ProcessMessage(this, {"type": "MoveCompleted", "data": msg}); 221 } 54 return this.template.RoamTimeMin; 222 55 }; 223 56 224 AnimalAI.prototype. OnAttacked = function(msg)57 AnimalAI.prototype.GetRoamTimeMax = function() 225 58 { 226 AnimalFsm.ProcessMessage(this, {"type": "Attacked", "data": msg});59 return this.template.RoamTimeMax; 227 60 }; 228 61 229 AnimalAI.prototype. OnHealthChanged = function(msg)62 AnimalAI.prototype.GetFeedTimeMin = function() 230 63 { 231 AnimalFsm.ProcessMessage(this, {"type": "HealthChanged", "from": msg.from, "to": msg.to});64 return this.template.FeedTimeMin; 232 65 }; 233 66 234 AnimalAI.prototype. TimerHandler = function(data, lateness)67 AnimalAI.prototype.GetFeedTimeMax = function() 235 68 { 236 AnimalFsm.ProcessMessage(this, {"type": "Timer", "data": data, "lateness": lateness});69 return this.template.FeedTimeMax; 237 70 }; 238 71 239 // Functions to be called by the FSM:240 241 AnimalAI.prototype.GetWalkSpeed = function()242 {243 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);244 return cmpMotion.GetWalkSpeed();245 };246 247 AnimalAI.prototype.GetRunSpeed = function()248 {249 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);250 return cmpMotion.GetRunSpeed();251 };252 253 AnimalAI.prototype.PlaySound = function(name)254 {255 PlaySound(name, this.entity);256 };257 258 AnimalAI.prototype.SelectAnimation = function(name, once, speed, sound)259 {260 var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);261 if (!cmpVisual)262 return;263 264 var soundgroup;265 if (sound)266 {267 var cmpSound = Engine.QueryInterface(this.entity, IID_Sound);268 if (cmpSound)269 soundgroup = cmpSound.GetSoundGroup(sound);270 }271 272 // Set default values if unspecified273 if (typeof once == "undefined")274 once = false;275 if (typeof speed == "undefined")276 speed = 1.0;277 if (typeof soundgroup == "undefined")278 soundgroup = "";279 280 cmpVisual.SelectAnimation(name, once, speed, soundgroup);281 };282 283 AnimalAI.prototype.MoveRandomly = function(distance)284 {285 // We want to walk in a random direction, but avoid getting stuck286 // in obstacles or narrow spaces.287 // So pick a circular range from approximately our current position,288 // and move outwards to the nearest point on that circle, which will289 // lead to us avoiding obstacles and moving towards free space.290 291 // TODO: we probably ought to have a 'home' point, and drift towards292 // that, so we don't spread out all across the whole map293 294 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);295 if (!cmpPosition)296 return;297 298 if (!cmpPosition.IsInWorld())299 return;300 301 var pos = cmpPosition.GetPosition();302 303 var jitter = 0.5;304 305 // Randomly adjust the range's center a bit, so we tend to prefer306 // moving in random directions (if there's nothing in the way)307 var tx = pos.x + (2*Math.random()-1)*jitter;308 var tz = pos.z + (2*Math.random()-1)*jitter;309 310 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);311 cmpMotion.MoveToPointRange(tx, tz, distance, distance);312 };313 314 AnimalAI.prototype.MoveAwayFrom = function(ent, distance)315 {316 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);317 cmpMotion.MoveToTargetRange(ent, distance, distance);318 };319 320 AnimalAI.prototype.StopMoving = function()321 {322 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);323 cmpMotion.StopMoving();324 };325 326 AnimalAI.prototype.SetMoveSpeed = function(speed)327 {328 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);329 cmpMotion.SetSpeed(speed);330 };331 332 AnimalAI.prototype.StartTimer = function(interval, data)333 {334 if (this.timer)335 error("Called StartTimer when there's already an active timer");336 337 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);338 this.timer = cmpTimer.SetTimeout(this.entity, IID_AnimalAI, "TimerHandler", interval, data);339 };340 341 AnimalAI.prototype.StopTimer = function()342 {343 if (!this.timer)344 return;345 346 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);347 cmpTimer.CancelTimer(this.timer);348 this.timer = undefined;349 };350 351 72 Engine.RegisterComponentType(IID_AnimalAI, "AnimalAI", AnimalAI); -
binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_aggressive.xml
5 5 <AnimalAI> 6 6 <NaturalBehaviour>aggressive</NaturalBehaviour> 7 7 </AnimalAI> 8 <Attack> 9 <Melee> 10 <Hack>1.0</Hack> 11 <Pierce>1.0</Pierce> 12 <Crush>0.0</Crush> 13 <MaxRange>4.0</MaxRange> 14 <RepeatTime>1000</RepeatTime> 15 </Melee> 16 </Attack> 8 17 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_wild_violent.xml
5 5 <AnimalAI> 6 6 <NaturalBehaviour>violent</NaturalBehaviour> 7 7 </AnimalAI> 8 <Attack> 9 <Melee> 10 <Hack>1.0</Hack> 11 <Pierce>1.0</Pierce> 12 <Crush>0.0</Crush> 13 <MaxRange>4.0</MaxRange> 14 <RepeatTime>1000</RepeatTime> 15 </Melee> 16 </Attack> 8 17 </Entity> -
binaries/data/mods/public/simulation/templates/special/formation.xml
8 8 <Formation/> 9 9 <UnitAI> 10 10 <FormationController>true</FormationController> 11 <IsAnimal>false</IsAnimal> 11 12 </UnitAI> 12 13 <UnitMotion> 13 14 <FormationController>true</FormationController> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_violent.xml
5 5 <AnimalAI> 6 6 <NaturalBehaviour>violent</NaturalBehaviour> 7 7 </AnimalAI> 8 <Attack> 9 <Melee> 10 <Hack>1.0</Hack> 11 <Pierce>1.0</Pierce> 12 <Crush>0.0</Crush> 13 <MaxRange>4.0</MaxRange> 14 <RepeatTime>1000</RepeatTime> 15 </Melee> 16 </Attack> 8 17 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_wild_aggressive.xml
3 3 <Identity> 4 4 </Identity> 5 5 <AnimalAI> 6 <NaturalBehaviour> violent</NaturalBehaviour>6 <NaturalBehaviour>aggressive</NaturalBehaviour> 7 7 </AnimalAI> 8 <Attack> 9 <Melee> 10 <Hack>1.0</Hack> 11 <Pierce>1.0</Pierce> 12 <Crush>0.0</Crush> 13 <MaxRange>4.0</MaxRange> 14 <RepeatTime>1000</RepeatTime> 15 </Melee> 16 </Attack> 8 17 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna.xml
25 25 <Speed>6.0</Speed> 26 26 </Run> 27 27 </UnitMotion> 28 <UnitAI disable=""/> 28 <UnitAI> 29 <FormationController>false</FormationController> 30 <IsAnimal>true</IsAnimal> 31 </UnitAI> 29 32 <AnimalAI> 30 33 <RoamDistance>8.0</RoamDistance> 31 34 <FleeDistance>32.0</FleeDistance> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_fish.xml
16 16 <Floating>true</Floating> 17 17 </Position> 18 18 <UnitMotion disable=""/> 19 <UnitAI disable=""/> 19 20 <AnimalAI disable=""/> 20 21 <ResourceSupply> 21 22 <KillBeforeGather>false</KillBeforeGather> -
binaries/data/mods/public/simulation/templates/template_unit.xml
9 9 </Minimap> 10 10 <UnitAI> 11 11 <FormationController>false</FormationController> 12 <IsAnimal>false</IsAnimal> 12 13 </UnitAI> 13 14 <Cost> 14 15 <Population>1</Population>