You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

303 lines
5.9 KiB

  1. define([
  2. ], function(
  3. ) {
  4. return {
  5. type: 'aggro',
  6. range: 7,
  7. faction: null,
  8. physics: null,
  9. list: [],
  10. ignoreList: [],
  11. init: function(blueprint) {
  12. this.physics = this.obj.instance.physics;
  13. blueprint = blueprint || {};
  14. if (blueprint.faction) {
  15. this.faction = blueprint.faction;
  16. }
  17. //TODO: Why don't we move if faction is null?
  18. if (this.faction == null)
  19. return;
  20. if (this.physics.width > 0)
  21. this.move();
  22. else {
  23. //HACK: Don't fire on main thread (no physics set up)
  24. console.log('HACK: cpn/aggro');
  25. }
  26. },
  27. events: {
  28. beforeRezone: function() {
  29. this.die();
  30. }
  31. },
  32. simplify: function(self) {
  33. return {
  34. type: 'aggro',
  35. faction: this.faction
  36. };
  37. },
  38. move: function() {
  39. var result = {
  40. success: true
  41. };
  42. this.obj.fireEvent('beforeAggro', result);
  43. if (!result.success)
  44. return;
  45. var obj = this.obj;
  46. //If we're attacking something, don't try and look for more trouble. SAVE THE CPU!
  47. // this only counts for mobs, players can have multiple attackers
  48. var list = this.list;
  49. if (obj.isMob) {
  50. var lLen = list.length;
  51. for (var i = 0; i < lLen; i++) {
  52. var l = list[i];
  53. var lThreat = l.obj.aggro.getHighest();
  54. if (lThreat) {
  55. l.obj.aggro.list.forEach(function(a) {
  56. a.obj.aggro.unIgnore(lThreat);
  57. });
  58. }
  59. l.obj.aggro.unIgnore(obj);
  60. if (l.threat > 0)
  61. return;
  62. }
  63. } else {
  64. var lLen = list.length;
  65. for (var i = 0; i < lLen; i++) {
  66. list[i].obj.aggro.unIgnore(obj);
  67. }
  68. }
  69. var x = obj.x;
  70. var y = obj.y;
  71. //find mobs in range
  72. var range = this.range;
  73. var faction = this.faction;
  74. var inRange = this.physics.getArea(x - range, y - range, x + range, y + range, (c => (((!c.player) || (!obj.player)) && (c.aggro) && (c.aggro.willAttack(obj)))));
  75. if (inRange.length == 0)
  76. return;
  77. var iLen = inRange.length;
  78. for (var i = 0; i < iLen; i++) {
  79. var enemy = inRange[i];
  80. //The length could change
  81. lLen = list.length;
  82. for (var j = 0; j < lLen; j++) {
  83. //Set the enemy to null so we need we need to continue
  84. if (list[j].obj == enemy)
  85. enemy = null;
  86. }
  87. if (!enemy)
  88. continue;
  89. //Do we have LoS?
  90. if (!this.physics.hasLos(x, y, enemy.x, enemy.y))
  91. continue;
  92. if (enemy.aggro.tryEngage(obj))
  93. this.tryEngage(enemy, 0);
  94. }
  95. },
  96. willAttack: function(target) {
  97. if (this.obj == target)
  98. return false;
  99. var faction = target.aggro.faction;
  100. if (faction == null)
  101. return false;
  102. if ((target.player) && (this.obj.player))
  103. return ((this.obj.prophecies.hasProphecy('butcher')) && (target.prophecies.hasProphecy('butcher')));
  104. var rep = this.obj.reputation;
  105. if (!rep) {
  106. var targetRep = target.reputation;
  107. if (!targetRep)
  108. return false;
  109. else
  110. return (targetRep.getTier(this.faction) < 3);
  111. }
  112. return (rep.getTier(faction) < 3);
  113. },
  114. ignore: function(obj) {
  115. this.ignoreList.spliceWhere(o => o == obj);
  116. this.ignoreList.push(obj);
  117. },
  118. unIgnore: function(obj) {
  119. this.ignoreList.spliceWhere(o => o == obj);
  120. },
  121. tryEngage: function(obj, amount, threatMult) {
  122. var result = {
  123. success: true
  124. };
  125. this.obj.fireEvent('beforeAggro', result);
  126. if (!result.success)
  127. return false;
  128. var oId = obj.id;
  129. var list = this.list;
  130. amount = amount || 0;
  131. threatMult = threatMult || 1;
  132. var exists = list.find(l => l.obj.id == oId);
  133. if (exists) {
  134. exists.damage += amount;
  135. exists.threat += amount * threatMult;
  136. } else {
  137. var l = {
  138. obj: obj,
  139. damage: amount,
  140. threat: amount * threatMult
  141. };
  142. list.push(l);
  143. }
  144. //this.sortThreat();
  145. return true;
  146. },
  147. getFirstAttacker: function() {
  148. var first = this.list.find(l => ((l.obj.player) && (l.damage > 0)));
  149. if (first)
  150. return first.obj;
  151. else
  152. return null;
  153. },
  154. die: function() {
  155. var list = this.list;
  156. var lLen = list.length;
  157. for (var i = 0; i < lLen; i++) {
  158. var l = list[i];
  159. if (!l) {
  160. console.log('aggro obj empty???');
  161. continue;
  162. }
  163. l.obj.aggro.unAggro(this.obj);
  164. }
  165. this.list = [];
  166. },
  167. unAggro: function(obj, amount) {
  168. var oId = obj.id;
  169. var list = this.list;
  170. var lLen = list.length;
  171. for (var i = 0; i < lLen; i++) {
  172. var l = list[i];
  173. if (l.obj != obj)
  174. continue;
  175. if (amount == null) {
  176. list.splice(i, 1);
  177. break;
  178. } else {
  179. l.threat -= amount;
  180. if (l.threat <= 0) {
  181. list.splice(i, 1);
  182. break;
  183. }
  184. }
  185. }
  186. this.ignoreList.spliceWhere(o => o == obj);
  187. //Stuff like cocoons don't have spellbooks
  188. if (this.obj.spellbook)
  189. this.obj.spellbook.unregisterCallback(obj.id, true);
  190. if ((this.list.length == 0) && (this.obj.mob))
  191. this.obj.stats.resetHp();
  192. },
  193. sortThreat: function() {
  194. this.list.sort(function(a, b) {
  195. return (b.threat - a.threat);
  196. });
  197. },
  198. getHighest: function() {
  199. if (this.list.length == 0)
  200. return null;
  201. var list = this.list;
  202. var lLen = list.length;
  203. var highest = null;
  204. var closest = 99999;
  205. var thisObj = this.obj;
  206. var x = thisObj.x;
  207. var y = thisObj.y;
  208. for (var i = 0; i < lLen; i++) {
  209. var l = list[i];
  210. var obj = l.obj;
  211. if (this.ignoreList.some(o => o == obj))
  212. continue;
  213. if ((highest == null) || (l.threat > highest.threat)) {
  214. highest = l;
  215. closest = Math.max(Math.abs(x - obj.x), Math.abs(y - obj.y));
  216. } else if (l.threat == highest.threat) {
  217. var distance = Math.max(Math.abs(x - obj.x), Math.abs(y - obj.y));
  218. if (distance < closest) {
  219. highest = l;
  220. closest = distance;
  221. }
  222. }
  223. }
  224. if (highest)
  225. return highest.obj;
  226. else {
  227. //We have aggro but can't reach our target. Don't let the mob run away as if not in combat!
  228. return true;
  229. }
  230. },
  231. update: function() {
  232. var list = this.list;
  233. var lLen = list.length;
  234. for (var i = 0; i < lLen; i++) {
  235. var l = list[i];
  236. if (l.obj.destroyed) {
  237. list.splice(i, 1);
  238. i--;
  239. lLen--;
  240. }
  241. }
  242. }
  243. };
  244. });