Ticket #563: AnimalAImm-16-02-2011.patch
File AnimalAImm-16-02-2011.patch, 33.0 KB (added by , 13 years ago) |
---|
-
binaries/data/mods/public/simulation/components/Foundation.js
90 90 if (cmpUnitAI) 91 91 cmpUnitAI.LeaveFoundation(this.entity); 92 92 93 var cmpAnimalAI = Engine.QueryInterface(ent, IID_AnimalAI); 94 if (cmpAnimalAI) 95 cmpAnimalAI.LeaveFoundation(this.entity); 96 97 // TODO: What if an obstruction has no UnitAI/AnimalAI? 93 // TODO: What if an obstruction has no UnitAI? 98 94 } 99 95 100 96 // TODO: maybe we should tell the builder to use a special -
binaries/data/mods/public/simulation/components/interfaces/AnimalAI.js
1 Engine.RegisterInterface("AnimalAI"); -
binaries/data/mods/public/simulation/components/UnitAI.js
2 2 3 3 UnitAI.prototype.Schema = 4 4 "<a:help>Controls the unit's movement, attacks, etc, in response to commands from the player.</a:help>" + 5 "<a:example/>" + 5 "<a:example/>" + 6 6 "<element name='FormationController'>" + 7 7 "<data type='boolean'/>" + 8 "</element>"; 8 "</element>" + 9 "<optional>" + 10 "<interleave>" + 11 "<element name='NaturalBehaviour' a:help='Behaviour of the unit in the absence of player commands (intended for animals)'>" + 12 "<choice>" + 13 "<value a:help='Will actively attack any unit it encounters, even if not threatened'>violent</value>" + 14 "<value a:help='Will attack nearby units if it feels threatened (if they linger within LOS for too long)'>aggressive</value>" + 15 "<value a:help='Will attack nearby units if attacked'>defensive</value>" + 16 "<value a:help='Will never attack units'>passive</value>" + 17 "<value a:help='Will never attack units. Will typically attempt to flee for short distances when units approach'>skittish</value>" + 18 "</choice>" + 19 "</element>" + 20 "<element name='RoamDistance'>" + 21 "<ref name='positiveDecimal'/>" + 22 "</element>" + 23 "<element name='FleeDistance'>" + 24 "<ref name='positiveDecimal'/>" + 25 "</element>" + 26 "<element name='RoamTimeMin'>" + 27 "<ref name='positiveDecimal'/>" + 28 "</element>" + 29 "<element name='RoamTimeMax'>" + 30 "<ref name='positiveDecimal'/>" + 31 "</element>" + 32 "<element name='FeedTimeMin'>" + 33 "<ref name='positiveDecimal'/>" + 34 "</element>" + 35 "<element name='FeedTimeMax'>" + 36 "<ref name='positiveDecimal'/>" + 37 "</element>"+ 38 "</interleave>" + 39 "</optional>"; 9 40 10 41 // Very basic stance support (currently just for test maps where we don't want 11 42 // everyone killing each other immediately after loading) … … 42 73 43 74 "Attacked": function(msg) { 44 75 // ignore attacker 76 }, 77 78 "HealthChanged": function(msg) { 79 // ignore 45 80 }, 46 81 47 48 82 // Formation handlers: 49 83 50 84 "FormationLeave": function(msg) { … … 111 145 if (this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType)) 112 146 { 113 147 // We've started walking to the given point 114 this.SetNextState("INDIVIDUAL.COMBAT.APPROACHING"); 148 if (this.template.NaturalBehaviour) 149 this.SetNextState("ANIMAL.COMBAT.APPROACHING"); 150 else 151 this.SetNextState("INDIVIDUAL.COMBAT.APPROACHING"); 115 152 } 116 153 else 117 154 { 118 155 // We are already at the target, or can't move at all, 119 156 // so try attacking it from here. 120 157 // TODO: need better handling of the can't-reach-target case 121 this.SetNextState("INDIVIDUAL.COMBAT.ATTACKING"); 158 if (this.template.NaturalBehaviour) 159 this.SetNextState("ANIMAL.COMBAT.ATTACKING"); 160 else 161 this.SetNextState("INDIVIDUAL.COMBAT.ATTACKING"); 122 162 } 123 163 }, 124 164 … … 454 494 455 495 // Can't reach it, or it doesn't exist any more - give up 456 496 this.FinishOrder(); 457 497 458 498 // TODO: see if we can switch to a new nearby enemy 459 499 }, 460 461 // TODO: respond to target deaths immediately, rather than waiting462 // until the next Timer event463 500 }, 464 501 465 502 "CHASING": { … … 841 878 }, 842 879 843 880 }, 881 882 "ANIMAL": { 883 884 "HealthChanged": function(msg) { 885 // If we died (got reduced to 0 hitpoints), stop the AI and act like a corpse 886 if (msg.to == 0) 887 this.SetNextState("CORPSE"); 888 }, 889 890 "Attacked": function(msg) { 891 if (this.template.NaturalBehaviour == "skittish" || this.template.NaturalBehaviour == "passive") 892 { 893 this.MoveAwayFrom(msg.data.attacker, +this.template.FleeDistance); 894 this.SetNextState("FLEEING"); 895 this.PlaySound("panic"); 896 } 897 else if(this.template.NaturalBehaviour == "violent" || this.template.NaturalBehaviour == "aggressive" || this.template.NaturalBehaviour == "defensive") 898 { 899 print("violent attack\n"); 900 if(this.CanAttack(msg.data.attacker)) 901 this.PushOrderFront("Attack", { "target": msg.data.attacker }); 902 } 903 }, 904 905 "LeaveFoundation": function(msg) { 906 // Run away from the foundation 907 this.MoveAwayFrom(msg.target, +this.template.FleeDistance); 908 this.SetNextState("FLEEING"); 909 this.PlaySound("panic"); 910 }, 911 912 "CORPSE": { 913 "enter": function() { 914 this.StopMoving(); 915 }, 916 917 "Attacked": function(msg) { 918 // Do nothing, because we're dead already 919 }, 920 921 "LeaveFoundation": function(msg) { 922 // We can't walk away from the foundation (since we're dead), 923 // but we mustn't block its construction (since the builders would get stuck), 924 // and we don't want to trick gatherers into trying to reach us when 925 // we're stuck in the middle of a building, so just delete our corpse. 926 Engine.DestroyEntity(this.entity); 927 }, 928 }, 929 930 "ROAMING": { 931 "enter": function() { 932 // Walk in a random direction 933 this.SelectAnimation("walk", false, this.GetWalkSpeed()); 934 this.MoveRandomly(+this.template.RoamDistance); 935 // Set a random timer to switch to feeding state 936 this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax)); 937 }, 938 939 "leave": function() { 940 this.StopTimer(); 941 }, 942 943 "LosRangeUpdate": function(msg) { 944 if (this.template.NaturalBehaviour == "skittish") 945 { 946 if (msg.data.added.length > 0) 947 { 948 this.MoveAwayFrom(msg.data.added[0], +this.template.FleeDistance); 949 this.SetNextState("FLEEING"); 950 this.PlaySound("panic"); 951 return; 952 } 953 } 954 // Start attacking one of the newly-seen enemy (if any) 955 else if (this.template.NaturalBehaviour == "violent" || this.template.NaturalBehaviour == "aggressive") 956 this.AttackVisibleEntity(msg.data.added); 957 }, 958 959 "Timer": function(msg) { 960 this.SetNextState("FEEDING"); 961 }, 962 963 "MoveCompleted": function() { 964 this.MoveRandomly(+this.template.RoamDistance); 965 }, 966 }, 967 968 "FEEDING": { 969 "enter": function() { 970 // Stop and eat for a while 971 this.SelectAnimation("feeding"); 972 this.StopMoving(); 973 this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax)); 974 }, 975 976 "leave": function() { 977 this.StopTimer(); 978 }, 979 980 "LosRangeUpdate": function(msg) { 981 if (this.template.NaturalBehaviour == "skittish") 982 { 983 if (msg.data.added.length > 0) 984 { 985 this.MoveAwayFrom(msg.data.added[0], +this.template.FleeDistance); 986 this.SetNextState("FLEEING"); 987 this.PlaySound("panic"); 988 return; 989 } 990 } 991 // Start attacking one of the newly-seen enemy (if any) 992 else if (this.template.NaturalBehaviour == "violent") 993 this.AttackVisibleEntity(msg.data.added); 994 }, 995 996 "MoveCompleted": function() { }, 997 998 "Timer": function(msg) { 999 this.SetNextState("ROAMING"); 1000 }, 1001 }, 1002 1003 "FLEEING": { 1004 "enter": function() { 1005 // Run quickly 1006 var speed = this.GetRunSpeed(); 1007 this.SelectAnimation("run", false, speed); 1008 this.SetMoveSpeed(speed); 1009 }, 1010 1011 "leave": function() { 1012 // Reset normal speed 1013 this.SetMoveSpeed(this.GetWalkSpeed()); 1014 }, 1015 1016 "MoveCompleted": function() { 1017 // When we've run far enough, go back to the roaming state 1018 this.SetNextState("ROAMING"); 1019 }, 1020 }, 1021 1022 "COMBAT": { 1023 "Attacked": function(msg) { 1024 // If we're already in combat mode, ignore anyone else 1025 // who's attacking us 1026 }, 1027 1028 "APPROACHING": { 1029 "enter": function () { 1030 this.SelectAnimation("move"); 1031 }, 1032 1033 "MoveCompleted": function() { 1034 this.SetNextState("ATTACKING"); 1035 }, 1036 }, 1037 1038 "ATTACKING": { 1039 "enter": function() { 1040 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 1041 this.attackTimers = cmpAttack.GetTimers(this.attackType); 1042 1043 this.SelectAnimation("melee", false, 1.0, "attack"); 1044 this.SetAnimationSync(this.attackTimers.prepare, this.attackTimers.repeat); 1045 this.StartTimer(this.attackTimers.prepare, this.attackTimers.repeat); 1046 }, 1047 1048 "leave": function() { 1049 this.StopTimer(); 1050 }, 1051 1052 "Timer": function(msg) { 1053 // Check the target is still alive 1054 if (this.TargetIsAlive(this.order.data.target)) 1055 { 1056 // Check we can still reach the target 1057 if (this.CheckTargetRange(this.order.data.target, IID_Attack, this.attackType)) 1058 { 1059 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); 1060 cmpAttack.PerformAttack(this.attackType, this.order.data.target); 1061 return; 1062 } 1063 1064 // Can't reach it - try to chase after it 1065 if (this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType)) 1066 { 1067 this.SetNextState("COMBAT.CHASING"); 1068 return; 1069 } 1070 } 1071 1072 // Can't reach it, or it doesn't exist any more - give up 1073 this.SetNextState("ANIMAL.ROAMING"); 1074 }, 1075 1076 // TODO: respond to target deaths immediately, rather than waiting 1077 // until the next Timer event 1078 }, 1079 1080 "CHASING": { 1081 "enter": function () { 1082 this.SelectAnimation("move"); 1083 }, 1084 1085 "MoveCompleted": function() { 1086 this.SetNextState("ATTACKING"); 1087 }, 1088 }, 1089 }, 1090 1091 1092 }, 844 1093 }; 845 1094 846 1095 var UnitFsm = new FSM(UnitFsmSpec); … … 860 1109 return (this.template.FormationController == "true"); 861 1110 }; 862 1111 1112 UnitAI.prototype.IsAnAnimal = function() 1113 { 1114 return (this.template.NaturalBehaviour ? true : false); 1115 }; 1116 863 1117 UnitAI.prototype.IsIdle = function() 864 1118 { 865 1119 return this.isIdle; … … 867 1121 868 1122 UnitAI.prototype.OnCreate = function() 869 1123 { 870 if (this.IsFormationController()) 1124 if(this.IsAnAnimal()) 1125 UnitFsm.Init(this, "ANIMAL.FEEDING"); 1126 else if (this.IsFormationController()) 871 1127 UnitFsm.Init(this, "FORMATIONCONTROLLER.IDLE"); 872 1128 else 873 1129 UnitFsm.Init(this, "INDIVIDUAL.IDLE"); … … 921 1177 { 922 1178 // Exclude gaia, allies, and self 923 1179 // TODO: How to handle neutral players - Special query to attack military only? 924 if (i != owner && diplomacy[i - 1] < 0)1180 if (i != owner && (diplomacy[i - 1] < 0 || owner == 0)) 925 1181 players.push(i); 926 1182 } 927 1183 } … … 1614 1870 return true; 1615 1871 }; 1616 1872 1873 //Animal specific functions 1874 UnitAI.prototype.OnHealthChanged = function(msg) 1875 { 1876 UnitFsm.ProcessMessage(this, {"type": "HealthChanged", "from": msg.from, "to": msg.to}); 1877 }; 1617 1878 1879 UnitAI.prototype.MoveRandomly = function(distance) 1880 { 1881 // We want to walk in a random direction, but avoid getting stuck 1882 // in obstacles or narrow spaces. 1883 // So pick a circular range from approximately our current position, 1884 // and move outwards to the nearest point on that circle, which will 1885 // lead to us avoiding obstacles and moving towards free space. 1886 1887 // TODO: we probably ought to have a 'home' point, and drift towards 1888 // that, so we don't spread out all across the whole map 1889 1890 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 1891 if (!cmpPosition) 1892 return; 1893 1894 if (!cmpPosition.IsInWorld()) 1895 return; 1896 1897 var pos = cmpPosition.GetPosition(); 1898 1899 var jitter = 0.5; 1900 1901 // Randomly adjust the range's center a bit, so we tend to prefer 1902 // moving in random directions (if there's nothing in the way) 1903 var tx = pos.x + (2*Math.random()-1)*jitter; 1904 var tz = pos.z + (2*Math.random()-1)*jitter; 1905 1906 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 1907 cmpMotion.MoveToPointRange(tx, tz, distance, distance); 1908 }; 1909 1910 UnitAI.prototype.MoveAwayFrom = function(ent, distance) 1911 { 1912 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 1913 cmpMotion.MoveToTargetRange(ent, distance, distance); 1914 }; 1915 1916 UnitAI.prototype.SetMoveSpeed = function(speed) 1917 { 1918 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 1919 cmpMotion.SetSpeed(speed); 1920 }; 1921 1922 1923 1924 1618 1925 Engine.RegisterComponentType(IID_UnitAI, "UnitAI", UnitAI); -
binaries/data/mods/public/simulation/components/AnimalAI.js
1 function AnimalAI() {}2 3 AnimalAI.prototype.Schema =4 "<a:example/>" +5 "<element name='NaturalBehaviour' a:help='Behaviour of the unit in the absence of player commands (intended for animals)'>" +6 "<choice>" +7 "<value a:help='Will actively attack any unit it encounters, even if not threatened'>violent</value>" +8 "<value a:help='Will attack nearby units if it feels threatened (if they linger within LOS for too long)'>aggressive</value>" +9 "<value a:help='Will attack nearby units if attacked'>defensive</value>" +10 "<value a:help='Will never attack units'>passive</value>" +11 "<value a:help='Will never attack units. Will typically attempt to flee for short distances when units approach'>skittish</value>" +12 "</choice>" +13 "</element>" +14 "<element name='RoamDistance'>" +15 "<ref name='positiveDecimal'/>" +16 "</element>" +17 "<element name='FleeDistance'>" +18 "<ref name='positiveDecimal'/>" +19 "</element>" +20 "<element name='RoamTimeMin'>" +21 "<ref name='positiveDecimal'/>" +22 "</element>" +23 "<element name='RoamTimeMax'>" +24 "<ref name='positiveDecimal'/>" +25 "</element>" +26 "<element name='FeedTimeMin'>" +27 "<ref name='positiveDecimal'/>" +28 "</element>" +29 "<element name='FeedTimeMax'>" +30 "<ref name='positiveDecimal'/>" +31 "</element>";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 "LeaveFoundation": function(msg) {61 // We can't walk away from the foundation (since we're dead),62 // but we mustn't block its construction (since the builders would get stuck),63 // and we don't want to trick gatherers into trying to reach us when64 // we're stuck in the middle of a building, so just delete our corpse.65 Engine.DestroyEntity(this.entity);66 },67 },68 69 "SKITTISH": {70 71 "Attacked": function(msg) {72 // If someone's attacking us, then run away73 this.MoveAwayFrom(msg.data.attacker, +this.template.FleeDistance);74 this.SetNextState("FLEEING");75 this.PlaySound("panic");76 },77 78 "LeaveFoundation": function(msg) {79 // Run away from the foundation80 this.MoveAwayFrom(msg.target, +this.template.FleeDistance);81 this.SetNextState("FLEEING");82 this.PlaySound("panic");83 },84 85 "ROAMING": {86 "enter": function() {87 // Walk in a random direction88 this.SelectAnimation("walk", false, this.GetWalkSpeed());89 this.MoveRandomly(+this.template.RoamDistance);90 // Set a random timer to switch to feeding state91 this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));92 },93 94 "leave": function() {95 this.StopTimer();96 },97 98 "Timer": function(msg) {99 this.SetNextState("FEEDING");100 },101 102 "MoveCompleted": function() {103 this.MoveRandomly(+this.template.RoamDistance);104 },105 },106 107 "FEEDING": {108 "enter": function() {109 // Stop and eat for a while110 this.SelectAnimation("feeding");111 this.StopMoving();112 this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));113 },114 115 "leave": function() {116 this.StopTimer();117 },118 119 "MoveCompleted": function() { },120 121 "Timer": function(msg) {122 this.SetNextState("ROAMING");123 },124 },125 126 "FLEEING": {127 "enter": function() {128 // Run quickly129 var speed = this.GetRunSpeed();130 this.SelectAnimation("run", false, speed);131 this.SetMoveSpeed(speed);132 },133 134 "leave": function() {135 // Reset normal speed136 this.SetMoveSpeed(this.GetWalkSpeed());137 },138 139 "MoveCompleted": function() {140 // When we've run far enough, go back to the roaming state141 this.SetNextState("ROAMING");142 },143 },144 },145 146 "PASSIVE": {147 148 "Attacked": function(msg) {149 // Do nothing, just let them kill us150 },151 152 "LeaveFoundation": function(msg) {153 // Walk away from the foundation154 this.MoveAwayFrom(msg.target, 4);155 this.SetNextState("FLEEING");156 },157 158 "ROAMING": {159 "enter": function() {160 // Walk in a random direction161 this.SelectAnimation("walk", false, this.GetWalkSpeed());162 this.MoveRandomly(+this.template.RoamDistance);163 // Set a random timer to switch to feeding state164 this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));165 },166 167 "leave": function() {168 this.StopTimer();169 },170 171 "Timer": function(msg) {172 this.SetNextState("FEEDING");173 },174 175 "MoveCompleted": function() {176 this.MoveRandomly(+this.template.RoamDistance);177 },178 },179 180 "FEEDING": {181 "enter": function() {182 // Stop and eat for a while183 this.SelectAnimation("feeding");184 this.StopMoving();185 this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));186 },187 188 "leave": function() {189 this.StopTimer();190 },191 192 "MoveCompleted": function() { },193 194 "Timer": function(msg) {195 this.SetNextState("ROAMING");196 },197 },198 199 "FLEEING": {200 "enter": function() {201 this.SelectAnimation("walk", false, this.GetWalkSpeed());202 },203 204 "MoveCompleted": function() {205 this.SetNextState("ROAMING");206 },207 },208 },209 210 };211 212 var AnimalFsm = new FSM(AnimalFsmSpec);213 214 AnimalAI.prototype.Init = function()215 {216 };217 218 // FSM linkage functions:219 220 AnimalAI.prototype.OnCreate = function()221 {222 var startingState = this.template.NaturalBehaviour;223 startingState = startingState.toUpperCase(startingState);224 225 if (startingState == "SKITTISH")226 startingState = startingState + ".FEEDING";227 else228 startingState = "PASSIVE.FEEDING";229 230 AnimalFsm.Init(this, startingState);231 };232 233 AnimalAI.prototype.SetNextState = function(state)234 {235 AnimalFsm.SetNextState(this, state);236 };237 238 AnimalAI.prototype.DeferMessage = function(msg)239 {240 AnimalFsm.DeferMessage(this, msg);241 };242 243 AnimalAI.prototype.OnMotionChanged = function(msg)244 {245 if (msg.starting && !msg.error)246 {247 AnimalFsm.ProcessMessage(this, {"type": "MoveStarted", "data": msg});248 }249 else if (!msg.starting || msg.error)250 {251 AnimalFsm.ProcessMessage(this, {"type": "MoveCompleted", "data": msg});252 }253 };254 255 AnimalAI.prototype.OnAttacked = function(msg)256 {257 AnimalFsm.ProcessMessage(this, {"type": "Attacked", "data": msg});258 };259 260 AnimalAI.prototype.OnHealthChanged = function(msg)261 {262 AnimalFsm.ProcessMessage(this, {"type": "HealthChanged", "from": msg.from, "to": msg.to});263 };264 265 AnimalAI.prototype.TimerHandler = function(data, lateness)266 {267 AnimalFsm.ProcessMessage(this, {"type": "Timer", "data": data, "lateness": lateness});268 };269 270 AnimalAI.prototype.LeaveFoundation = function(target)271 {272 AnimalFsm.ProcessMessage(this, {"type": "LeaveFoundation", "target": target});273 };274 275 // Functions to be called by the FSM:276 277 AnimalAI.prototype.GetWalkSpeed = function()278 {279 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);280 return cmpMotion.GetWalkSpeed();281 };282 283 AnimalAI.prototype.GetRunSpeed = function()284 {285 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);286 return cmpMotion.GetRunSpeed();287 };288 289 AnimalAI.prototype.PlaySound = function(name)290 {291 PlaySound(name, this.entity);292 };293 294 AnimalAI.prototype.SelectAnimation = function(name, once, speed, sound)295 {296 var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);297 if (!cmpVisual)298 return;299 300 var soundgroup;301 if (sound)302 {303 var cmpSound = Engine.QueryInterface(this.entity, IID_Sound);304 if (cmpSound)305 soundgroup = cmpSound.GetSoundGroup(sound);306 }307 308 // Set default values if unspecified309 if (typeof once == "undefined")310 once = false;311 if (typeof speed == "undefined")312 speed = 1.0;313 if (typeof soundgroup == "undefined")314 soundgroup = "";315 316 cmpVisual.SelectAnimation(name, once, speed, soundgroup);317 };318 319 AnimalAI.prototype.MoveRandomly = function(distance)320 {321 // We want to walk in a random direction, but avoid getting stuck322 // in obstacles or narrow spaces.323 // So pick a circular range from approximately our current position,324 // and move outwards to the nearest point on that circle, which will325 // lead to us avoiding obstacles and moving towards free space.326 327 // TODO: we probably ought to have a 'home' point, and drift towards328 // that, so we don't spread out all across the whole map329 330 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);331 if (!cmpPosition)332 return;333 334 if (!cmpPosition.IsInWorld())335 return;336 337 var pos = cmpPosition.GetPosition();338 339 var jitter = 0.5;340 341 // Randomly adjust the range's center a bit, so we tend to prefer342 // moving in random directions (if there's nothing in the way)343 var tx = pos.x + (2*Math.random()-1)*jitter;344 var tz = pos.z + (2*Math.random()-1)*jitter;345 346 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);347 cmpMotion.MoveToPointRange(tx, tz, distance, distance);348 };349 350 AnimalAI.prototype.MoveAwayFrom = function(ent, distance)351 {352 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);353 cmpMotion.MoveToTargetRange(ent, distance, distance);354 };355 356 AnimalAI.prototype.StopMoving = function()357 {358 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);359 cmpMotion.StopMoving();360 };361 362 AnimalAI.prototype.SetMoveSpeed = function(speed)363 {364 var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion);365 cmpMotion.SetSpeed(speed);366 };367 368 AnimalAI.prototype.StartTimer = function(interval, data)369 {370 if (this.timer)371 error("Called StartTimer when there's already an active timer");372 373 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);374 this.timer = cmpTimer.SetTimeout(this.entity, IID_AnimalAI, "TimerHandler", interval, data);375 };376 377 AnimalAI.prototype.StopTimer = function()378 {379 if (!this.timer)380 return;381 382 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);383 cmpTimer.CancelTimer(this.timer);384 this.timer = undefined;385 };386 387 Engine.RegisterComponentType(IID_AnimalAI, "AnimalAI", AnimalAI); -
binaries/data/mods/public/simulation/templates/template_unit_fauna_wild_defensive.xml
2 2 <Entity parent="template_unit_fauna_wild"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>defensive</NaturalBehaviour> 7 </ AnimalAI>7 </UnitAI> 8 8 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_aggressive.xml
2 2 <Entity parent="template_unit_fauna_hunt"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>aggressive</NaturalBehaviour> 7 </AnimalAI> 7 </UnitAI> 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/gaia/fauna_chicken.xml
22 22 <Circle radius="0.75"/> 23 23 <Height>1.5</Height> 24 24 </Footprint> 25 < AnimalAI>25 <UnitAI> 26 26 <RoamDistance>4.0</RoamDistance> 27 27 <FleeDistance>12.0</FleeDistance> 28 28 <RoamTimeMin>2000</RoamTimeMin> 29 29 <RoamTimeMax>8000</RoamTimeMax> 30 30 <FeedTimeMin>10000</FeedTimeMin> 31 31 <FeedTimeMax>40000</FeedTimeMax> 32 </ AnimalAI>32 </UnitAI> 33 33 <UnitMotion> 34 34 <WalkSpeed>1.0</WalkSpeed> 35 35 <Run> -
binaries/data/mods/public/simulation/templates/gaia/fauna_whale_humpback.xml
35 35 <Altitude>-4.0</Altitude> 36 36 <Floating>true</Floating> 37 37 </Position> 38 < AnimalAI>38 <UnitAI> 39 39 <NaturalBehaviour>skittish</NaturalBehaviour> 40 40 <RoamDistance>20.0</RoamDistance> 41 41 <FleeDistance>40.0</FleeDistance> … … 43 43 <RoamTimeMax>30000</RoamTimeMax> 44 44 <FeedTimeMin>1000</FeedTimeMin> 45 45 <FeedTimeMax>2000</FeedTimeMax> 46 </ AnimalAI>46 </UnitAI> 47 47 <ResourceSupply> 48 48 <KillBeforeGather>true</KillBeforeGather> 49 49 <Amount>2000</Amount> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_wild_violent.xml
2 2 <Entity parent="template_unit_fauna_wild"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>violent</NaturalBehaviour> 7 </AnimalAI> 7 </UnitAI> 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_passive.xml
2 2 <Entity parent="template_unit_fauna_wild"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>passive</NaturalBehaviour> 7 </ AnimalAI>7 </UnitAI> 8 8 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_breed_passive.xml
2 2 <Entity parent="template_unit_fauna_breed"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>passive</NaturalBehaviour> 7 </ AnimalAI>7 </UnitAI> 8 8 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_herd_passive.xml
2 2 <Entity parent="template_unit_fauna_herd"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>passive</NaturalBehaviour> 7 </ AnimalAI>7 </UnitAI> 8 8 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_wild_aggressive.xml
2 2 <Entity parent="template_unit_fauna_wild"> 3 3 <Identity> 4 4 </Identity> 5 <AnimalAI> 6 <NaturalBehaviour>violent</NaturalBehaviour> 7 </AnimalAI> 5 <UnitAI> 6 <NaturalBehaviour>aggressive</NaturalBehaviour> 7 </UnitAI> 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_hunt_violent.xml
2 2 <Entity parent="template_unit_fauna_hunt"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>violent</NaturalBehaviour> 7 </AnimalAI> 7 </UnitAI> 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_hunt_passive.xml
2 2 <Entity parent="template_unit_fauna_hunt"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>passive</NaturalBehaviour> 7 </ AnimalAI>7 </UnitAI> 8 8 </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=""/> 29 <AnimalAI> 28 <UnitAI> 30 29 <RoamDistance>8.0</RoamDistance> 31 30 <FleeDistance>32.0</FleeDistance> 32 31 <RoamTimeMin>2000</RoamTimeMin> 33 32 <RoamTimeMax>8000</RoamTimeMax> 34 33 <FeedTimeMin>15000</FeedTimeMin> 35 34 <FeedTimeMax>60000</FeedTimeMax> 36 </ AnimalAI>35 </UnitAI> 37 36 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_fish.xml
18 18 <Floating>true</Floating> 19 19 </Position> 20 20 <UnitMotion disable=""/> 21 < AnimalAI disable=""/>21 <UnitAI disable=""/> 22 22 <ResourceSupply> 23 23 <KillBeforeGather>false</KillBeforeGather> 24 24 <Amount>1000</Amount> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_skittish.xml
2 2 <Entity parent="template_unit_fauna_hunt"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>skittish</NaturalBehaviour> 7 </ AnimalAI>7 </UnitAI> 8 8 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_defensive.xml
2 2 <Entity parent="template_unit_fauna_hunt"> 3 3 <Identity> 4 4 </Identity> 5 < AnimalAI>5 <UnitAI> 6 6 <NaturalBehaviour>defensive</NaturalBehaviour> 7 </ AnimalAI>7 </UnitAI> 8 8 </Entity>