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.
 
 
 

362 lines
7.3 KiB

  1. let components = require('../components/components');
  2. module.exports = {
  3. components: [],
  4. actionQueue: [],
  5. addComponent: function (type, blueprint, isTransfer) {
  6. let cpn = this[type];
  7. if (!cpn) {
  8. let template = components.components[type];
  9. if (!template) {
  10. template = extend(true, {
  11. type: type
  12. }, blueprint || {});
  13. }
  14. cpn = extend(true, {}, template);
  15. cpn.obj = this;
  16. this.components.push(cpn);
  17. this[cpn.type] = cpn;
  18. }
  19. if ((cpn.init) && (this.instance !== null))
  20. cpn.init(blueprint || {}, isTransfer);
  21. else {
  22. for (let p in blueprint)
  23. cpn[p] = blueprint[p];
  24. }
  25. return cpn;
  26. },
  27. removeComponent: function (type) {
  28. let cpn = this[type];
  29. if (!cpn)
  30. return;
  31. cpn.destroyed = true;
  32. },
  33. extendComponent: function (ext, type, blueprint) {
  34. let template = require('../components/extensions/' + type);
  35. let cpn = this[ext];
  36. extend(true, cpn, template);
  37. if (template.init)
  38. cpn.init(blueprint);
  39. return cpn;
  40. },
  41. update: function () {
  42. let usedTurn = false;
  43. let cpns = this.components;
  44. let len = cpns.length;
  45. for (let i = 0; i < len; i++) {
  46. let c = cpns[i];
  47. if (c.destroyed) {
  48. this.syncer.setSelfArray(false, 'removeComponents', c.type);
  49. cpns.spliceWhere(f => (f === c));
  50. delete this[c.type];
  51. len--;
  52. i--;
  53. } else if (c.update) {
  54. if (c.update())
  55. usedTurn = true;
  56. }
  57. }
  58. if (!usedTurn)
  59. this.performQueue();
  60. },
  61. getSimple: function (self, isSave) {
  62. let s = this.simplify(null, self, isSave);
  63. if (this.instance)
  64. s.zoneId = this.instance.zoneId;
  65. if ((self) && (!isSave)) {
  66. let syncer = this.syncer;
  67. if (syncer) {
  68. //Add things that have been queued by the syncer (that aren't tied to server-side components)
  69. syncer.oSelf.components
  70. .filter((c => !this[c.type]), this)
  71. .forEach(c => s.components.push(c));
  72. }
  73. }
  74. return s;
  75. },
  76. simplify: function (o, self, isSave) {
  77. let result = {};
  78. if (!o) {
  79. result.components = [];
  80. o = this;
  81. }
  82. let syncTypes = ['portrait'];
  83. for (let p in o) {
  84. let value = o[p];
  85. if (value === null)
  86. continue;
  87. let type = typeof (value);
  88. //build component
  89. if (type === 'object') {
  90. if (value.type) {
  91. if (!value.simplify) {
  92. if (self) {
  93. result.components.push({
  94. type: value.type
  95. });
  96. }
  97. } else {
  98. let component = null;
  99. if (isSave)
  100. component = value.save ? value.save() : value.simplify(self);
  101. else
  102. component = value.simplify(self);
  103. if (value.destroyed) {
  104. if (!component) {
  105. component = {
  106. type: value.type
  107. };
  108. }
  109. component.destroyed = true;
  110. }
  111. if (component)
  112. result.components.push(component);
  113. }
  114. } else if (syncTypes.indexOf(p) > -1)
  115. result[p] = value;
  116. } else if (type !== 'function')
  117. result[p] = value;
  118. }
  119. return result;
  120. },
  121. sendEvent: function (event, data) {
  122. process.send({
  123. method: 'event',
  124. id: this.serverId,
  125. data: {
  126. event: event,
  127. data: data
  128. }
  129. });
  130. },
  131. queue: function (action) {
  132. if (action.list) {
  133. let type = action.action;
  134. let data = action.data;
  135. let dLen = data.length;
  136. for (let i = 0; i < dLen; i++) {
  137. let d = data[i];
  138. this.actionQueue.push({
  139. action: type,
  140. data: d
  141. });
  142. }
  143. return;
  144. }
  145. if (action.priority)
  146. this.actionQueue.splice(this.actionQueue.firstIndex(a => !a.priority), 0, action);
  147. else
  148. this.actionQueue.push(action);
  149. },
  150. dequeue: function () {
  151. if (this.actionQueue.length === 0)
  152. return null;
  153. return this.actionQueue.splice(0, 1)[0];
  154. },
  155. clearQueue: function () {
  156. if (this.serverId !== null) {
  157. this.instance.syncer.queue('onClearQueue', {
  158. id: this.id
  159. }, [this.serverId]);
  160. }
  161. this.actionQueue = [];
  162. },
  163. performAction: function (action) {
  164. if (action.instanceModule) {
  165. /*action.data.obj = this;
  166. this.instance[action.instanceModule][action.method](action.data);
  167. this.inventory.resolveCallback(action.data, action.data.result);*/
  168. return;
  169. }
  170. let cpn = this[action.cpn];
  171. if (!cpn)
  172. return;
  173. cpn[action.method](action.data);
  174. },
  175. performQueue: function () {
  176. let q = this.dequeue();
  177. if (!q)
  178. return;
  179. if (q.action === 'move') {
  180. if ((this.actionQueue[0]) && (this.actionQueue[0].action === 'move')) {
  181. let sprintChance = this.stats.values.sprintChance || 0;
  182. let physics = this.instance.physics;
  183. if ((~~(Math.random() * 100) < sprintChance) && (!physics.isTileBlocking(q.data.x, q.data.y))) {
  184. q = this.dequeue();
  185. q.isDouble = true;
  186. }
  187. }
  188. let success = this.performMove(q);
  189. if (!success)
  190. this.clearQueue();
  191. } else if (q.action === 'clearQueue')
  192. this.clearQueue();
  193. else if (q.action === 'spell') {
  194. let success = this.spellbook.cast(q);
  195. if (!success)
  196. this.performQueue();
  197. }
  198. },
  199. performMove: function (action) {
  200. let data = action.data;
  201. let physics = this.instance.physics;
  202. if (!action.force) {
  203. if (physics.isTileBlocking(data.x, data.y))
  204. return false;
  205. data.success = true;
  206. this.fireEvent('beforeMove', data);
  207. if (data.success === false) {
  208. action.priority = true;
  209. this.queue(action);
  210. return true;
  211. }
  212. let maxDistance = action.isDouble ? 2 : 1;
  213. let deltaX = Math.abs(this.x - data.x);
  214. let deltaY = Math.abs(this.y - data.y);
  215. if (
  216. (
  217. (deltaX > maxDistance) ||
  218. (deltaY > maxDistance)
  219. ) ||
  220. (
  221. (deltaX === 0) &&
  222. (deltaY === 0)
  223. )
  224. )
  225. return false;
  226. }
  227. //Don't allow mob overlap during combat
  228. if ((this.mob) && (this.mob.target)) {
  229. if (physics.addObject(this, data.x, data.y)) {
  230. physics.removeObject(this, this.x, this.y);
  231. this.x = data.x;
  232. this.y = data.y;
  233. } else
  234. return false;
  235. } else {
  236. physics.removeObject(this, this.x, this.y, data.x, data.y);
  237. physics.addObject(this, data.x, data.y, this.x, this.y);
  238. this.x = data.x;
  239. this.y = data.y;
  240. }
  241. let syncer = this.syncer;
  242. syncer.o.x = this.x;
  243. syncer.o.y = this.y;
  244. if (this.aggro)
  245. this.aggro.move();
  246. this.fireEvent('afterMove');
  247. return true;
  248. },
  249. collisionEnter: function (obj) {
  250. let cpns = this.components;
  251. let cLen = cpns.length;
  252. for (let i = 0; i < cLen; i++) {
  253. let c = cpns[i];
  254. if (c.collisionEnter) {
  255. if (c.collisionEnter(obj))
  256. return true;
  257. }
  258. }
  259. },
  260. collisionExit: function (obj) {
  261. let cpns = this.components;
  262. let cLen = cpns.length;
  263. for (let i = 0; i < cLen; i++) {
  264. let c = cpns[i];
  265. if (c.collisionExit)
  266. c.collisionExit(obj);
  267. }
  268. },
  269. fireEvent: function (event) {
  270. let args = [].slice.call(arguments, 1);
  271. let cpns = this.components;
  272. let cLen = cpns.length;
  273. for (let i = 0; i < cLen; i++) {
  274. let cpn = cpns[i];
  275. let events = cpn.events;
  276. if (!events)
  277. continue;
  278. let callback = events[event];
  279. if (!callback)
  280. continue;
  281. callback.apply(cpn, args);
  282. }
  283. if (this.effects)
  284. this.effects.fireEvent(event, args);
  285. if (this.quests)
  286. this.quests.fireEvent(event, args);
  287. if (this.prophecies)
  288. this.prophecies.fireEvent(event, args);
  289. if (this.inventory)
  290. this.inventory.fireEvent(event, args);
  291. if (this.spellbook)
  292. this.spellbook.fireEvent(event, args);
  293. },
  294. destroy: function () {
  295. let cpns = this.components;
  296. let len = cpns.length;
  297. for (let i = 0; i < len; i++) {
  298. let c = cpns[i];
  299. if (c.destroy)
  300. c.destroy();
  301. }
  302. this.components = null;
  303. }
  304. };