No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

383 líneas
7.5 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({
  11. type: type
  12. }, blueprint || {});
  13. }
  14. cpn = extend({}, template);
  15. cpn.obj = this;
  16. this.components.push(cpn);
  17. this[cpn.type] = cpn;
  18. }
  19. if (cpn.init && this.has('instance'))
  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(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.has('serverId')) {
  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. return;
  166. let cpn = this[action.cpn];
  167. if (!cpn)
  168. return;
  169. cpn[action.method](action.data);
  170. },
  171. performQueue: function () {
  172. let q = this.dequeue();
  173. if (!q)
  174. return;
  175. if (q.action === 'move') {
  176. if ((this.actionQueue[0]) && (this.actionQueue[0].action === 'move')) {
  177. let sprintChance = this.stats.values.sprintChance || 0;
  178. let physics = this.instance.physics;
  179. if ((~~(Math.random() * 100) < sprintChance) && (!physics.isTileBlocking(q.data.x, q.data.y))) {
  180. q = this.dequeue();
  181. q.isDouble = true;
  182. }
  183. }
  184. let success = this.performMove(q);
  185. if (!success)
  186. this.clearQueue();
  187. } else if (q.action === 'clearQueue')
  188. this.clearQueue();
  189. else if (q.action === 'spell') {
  190. let success = this.spellbook.cast(q);
  191. if (!success)
  192. this.performQueue();
  193. }
  194. },
  195. performMove: function (action) {
  196. let data = action.data;
  197. let physics = this.instance.physics;
  198. if (!action.force) {
  199. if (physics.isTileBlocking(data.x, data.y))
  200. return false;
  201. data.success = true;
  202. this.fireEvent('beforeMove', data);
  203. if (data.success === false) {
  204. action.priority = true;
  205. this.queue(action);
  206. return true;
  207. }
  208. let maxDistance = action.isDouble ? 2 : 1;
  209. let deltaX = Math.abs(this.x - data.x);
  210. let deltaY = Math.abs(this.y - data.y);
  211. if (
  212. (
  213. (deltaX > maxDistance) ||
  214. (deltaY > maxDistance)
  215. ) ||
  216. (
  217. (deltaX === 0) &&
  218. (deltaY === 0)
  219. )
  220. )
  221. return false;
  222. }
  223. //Don't allow mob overlap during combat
  224. if ((this.mob) && (this.mob.target)) {
  225. if (physics.addObject(this, data.x, data.y)) {
  226. physics.removeObject(this, this.x, this.y);
  227. this.x = data.x;
  228. this.y = data.y;
  229. } else
  230. return false;
  231. } else {
  232. physics.removeObject(this, this.x, this.y, data.x, data.y);
  233. physics.addObject(this, data.x, data.y, this.x, this.y);
  234. this.x = data.x;
  235. this.y = data.y;
  236. }
  237. let syncer = this.syncer;
  238. syncer.o.x = this.x;
  239. syncer.o.y = this.y;
  240. if (this.aggro)
  241. this.aggro.move();
  242. this.fireEvent('afterMove');
  243. return true;
  244. },
  245. collisionEnter: function (obj) {
  246. let cpns = this.components;
  247. let cLen = cpns.length;
  248. for (let i = 0; i < cLen; i++) {
  249. let c = cpns[i];
  250. if (c.collisionEnter) {
  251. if (c.collisionEnter(obj))
  252. return true;
  253. }
  254. }
  255. },
  256. collisionExit: function (obj) {
  257. let cpns = this.components;
  258. let cLen = cpns.length;
  259. for (let i = 0; i < cLen; i++) {
  260. let c = cpns[i];
  261. if (c.collisionExit)
  262. c.collisionExit(obj);
  263. }
  264. },
  265. fireEvent: function (event) {
  266. let args = [].slice.call(arguments, 1);
  267. let cpns = this.components;
  268. let cLen = cpns.length;
  269. for (let i = 0; i < cLen; i++) {
  270. let cpn = cpns[i];
  271. let events = cpn.events;
  272. if (!events)
  273. continue;
  274. let callback = events[event];
  275. if (!callback)
  276. continue;
  277. callback.apply(cpn, args);
  278. }
  279. if (this.effects)
  280. this.effects.fireEvent(event, args);
  281. if (this.quests)
  282. this.quests.fireEvent(event, args);
  283. if (this.prophecies)
  284. this.prophecies.fireEvent(event, args);
  285. if (this.inventory)
  286. this.inventory.fireEvent(event, args);
  287. if (this.spellbook)
  288. this.spellbook.fireEvent(event, args);
  289. },
  290. destroy: function () {
  291. let cpns = this.components;
  292. let len = cpns.length;
  293. for (let i = 0; i < len; i++) {
  294. let c = cpns[i];
  295. if (c.destroy)
  296. c.destroy();
  297. }
  298. this.components = null;
  299. },
  300. toString: function () {
  301. let res = {};
  302. for (let p in this) {
  303. if (['components', 'syncer'].indexOf(p) > -1)
  304. continue;
  305. let val = this[p];
  306. let stringVal = (val && val.toString) ? val.toString() : val;
  307. const type = typeof(val);
  308. if (
  309. type !== 'function' &&
  310. (
  311. type !== 'object' ||
  312. val.type
  313. )
  314. )
  315. res[p] = stringVal;
  316. }
  317. return JSON.stringify(res, null, 4).split('"').join('') + '\r\n';
  318. }
  319. };