Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 

444 рядки
8.5 KiB

  1. let components = require('../components/components');
  2. module.exports = {
  3. components: [],
  4. actionQueue: [],
  5. eventListeners: [],
  6. addComponent: function (type, blueprint, isTransfer) {
  7. let cpn = this[type];
  8. if (!cpn) {
  9. let template = components.components[type];
  10. if (!template) {
  11. template = extend({
  12. type: type
  13. }, blueprint || {});
  14. }
  15. cpn = extend({}, template);
  16. cpn.obj = this;
  17. this.components.push(cpn);
  18. this[cpn.type] = cpn;
  19. }
  20. if (cpn.init && this.has('instance'))
  21. cpn.init(blueprint || {}, isTransfer);
  22. else {
  23. for (let p in blueprint)
  24. cpn[p] = blueprint[p];
  25. }
  26. return cpn;
  27. },
  28. addBuiltComponent: function (cpn) {
  29. this[cpn.type] = cpn;
  30. cpn.obj = this;
  31. this.components.push(cpn);
  32. return cpn;
  33. },
  34. removeComponent: function (type) {
  35. let cpn = this[type];
  36. if (!cpn)
  37. return;
  38. cpn.destroyed = true;
  39. },
  40. extendComponent: function (ext, type, blueprint) {
  41. let template = require('../components/extensions/' + type);
  42. let cpn = this[ext];
  43. extend(cpn, template);
  44. if (template.init)
  45. cpn.init(blueprint);
  46. return cpn;
  47. },
  48. update: function () {
  49. let usedTurn = false;
  50. let cpns = this.components;
  51. let len = cpns.length;
  52. for (let i = 0; i < len; i++) {
  53. let c = cpns[i];
  54. if (c.destroyed) {
  55. this.syncer.setSelfArray(false, 'removeComponents', c.type);
  56. cpns.spliceWhere(f => (f === c));
  57. delete this[c.type];
  58. len--;
  59. i--;
  60. } else if (c.update) {
  61. if (c.update())
  62. usedTurn = true;
  63. }
  64. }
  65. if (!usedTurn)
  66. this.performQueue();
  67. },
  68. getSimple: function (self, isSave, isTransfer) {
  69. let s = this.simplify(null, self, isSave, isTransfer);
  70. if (this.instance)
  71. s.zoneId = this.instance.zoneId;
  72. if (self && !isSave && this.syncer) {
  73. this.syncer.oSelf.components
  74. .forEach(c => {
  75. if (!this[c.type])
  76. s.components.push(c);
  77. });
  78. }
  79. return s;
  80. },
  81. simplify: function (o, self, isSave, isTransfer) {
  82. let result = {};
  83. if (!o) {
  84. result.components = [];
  85. o = this;
  86. }
  87. let syncTypes = ['portrait', 'area'];
  88. for (let p in o) {
  89. let value = o[p];
  90. if (value === null)
  91. continue;
  92. let type = typeof (value);
  93. if (type === 'function')
  94. continue;
  95. else if (type !== 'object')
  96. result[p] = value;
  97. else if (type === 'undefined')
  98. continue;
  99. else {
  100. if (value.type) {
  101. if (!value.simplify) {
  102. if (self) {
  103. result.components.push({
  104. type: value.type
  105. });
  106. }
  107. } else {
  108. let component = null;
  109. if (isSave && value.save)
  110. component = value.save();
  111. else if (isTransfer && value.simplifyTransfer)
  112. component = value.simplifyTransfer();
  113. else
  114. component = value.simplify(self);
  115. if (value.destroyed) {
  116. if (!component) {
  117. component = {
  118. type: value.type
  119. };
  120. }
  121. component.destroyed = true;
  122. }
  123. if (component)
  124. result.components.push(component);
  125. }
  126. } else if (syncTypes.includes(p))
  127. result[p] = value;
  128. continue;
  129. }
  130. }
  131. return result;
  132. },
  133. sendEvent: function (event, data) {
  134. process.send({
  135. method: 'event',
  136. id: this.serverId,
  137. data: {
  138. event: event,
  139. data: data
  140. }
  141. });
  142. },
  143. queue: function (action) {
  144. if (action.action === 'clearQueue') {
  145. let spellbook = this.spellbook;
  146. if (spellbook.isCasting())
  147. spellbook.stopCasting();
  148. else
  149. this.clearQueue();
  150. return;
  151. } else if (action.action === 'spell') {
  152. let spellbook = this.spellbook;
  153. const isCasting = spellbook.isCasting();
  154. if (isCasting && (!action.priority || !spellbook.canCast(action))) {
  155. if (action.auto)
  156. spellbook.queueAuto(action);
  157. return;
  158. }
  159. if (isCasting)
  160. spellbook.stopCasting();
  161. this.actionQueue.spliceWhere(a => a.priority);
  162. this.actionQueue.splice(0, 0, action);
  163. } else {
  164. if (action.priority) {
  165. this.spellbook.stopCasting();
  166. this.actionQueue.splice(0, 0, action);
  167. return;
  168. }
  169. this.actionQueue.push(action);
  170. }
  171. },
  172. dequeue: function () {
  173. if (this.actionQueue.length === 0)
  174. return null;
  175. return this.actionQueue.splice(0, 1)[0];
  176. },
  177. clearQueue: function () {
  178. if (this.has('serverId')) {
  179. this.instance.syncer.queue('onClearQueue', {
  180. id: this.id
  181. }, [this.serverId]);
  182. }
  183. this.actionQueue = [];
  184. this.fireEvent('clearQueue');
  185. },
  186. performAction: function (action) {
  187. if (action.instanceModule)
  188. return;
  189. let cpn = this[action.cpn];
  190. if (!cpn)
  191. return;
  192. cpn[action.method](action.data);
  193. },
  194. performQueue: function () {
  195. let q = this.dequeue();
  196. if (!q)
  197. return;
  198. if (q.action === 'move') {
  199. let maxDistance = 1;
  200. if ((this.actionQueue[0]) && (this.actionQueue[0].action === 'move')) {
  201. let moveEvent = {
  202. sprintChance: this.stats.values.sprintChance || 0
  203. };
  204. this.fireEvent('onBeforeTryMove', moveEvent);
  205. let physics = this.instance.physics;
  206. let sprintChance = moveEvent.sprintChance;
  207. do {
  208. if ((~~(Math.random() * 100) < sprintChance) && (!physics.isTileBlocking(q.data.x, q.data.y))) {
  209. q = this.dequeue();
  210. maxDistance++;
  211. }
  212. sprintChance -= 100;
  213. } while (sprintChance > 0 && this.actionQueue.length > 0);
  214. }
  215. q.maxDistance = maxDistance;
  216. let success = this.performMove(q);
  217. if (!success)
  218. this.clearQueue();
  219. } else if (q.action === 'spell') {
  220. let success = this.spellbook.cast(q);
  221. if (!success)
  222. this.performQueue();
  223. }
  224. },
  225. performMove: function (action) {
  226. let data = action.data;
  227. let physics = this.instance.physics;
  228. if (!action.force) {
  229. if (physics.isTileBlocking(data.x, data.y))
  230. return true;
  231. data.success = true;
  232. this.fireEvent('beforeMove', data);
  233. if (data.success === false) {
  234. action.priority = true;
  235. this.queue(action);
  236. return true;
  237. }
  238. let maxDistance = action.maxDistance || 1;
  239. let deltaX = Math.abs(this.x - data.x);
  240. let deltaY = Math.abs(this.y - data.y);
  241. if (
  242. (
  243. (deltaX > maxDistance) ||
  244. (deltaY > maxDistance)
  245. ) ||
  246. (
  247. (deltaX === 0) &&
  248. (deltaY === 0)
  249. )
  250. )
  251. return false;
  252. }
  253. //Don't allow mob overlap during combat
  254. if ((this.mob) && (this.mob.target)) {
  255. if (physics.addObject(this, data.x, data.y)) {
  256. physics.removeObject(this, this.x, this.y);
  257. this.x = data.x;
  258. this.y = data.y;
  259. } else
  260. return false;
  261. } else {
  262. const { x: xOld, y: yOld } = this;
  263. const { x: xNew, y: yNew } = data;
  264. physics.removeObject(this, xOld, yOld, xNew, yNew);
  265. this.x = xNew;
  266. this.y = yNew;
  267. physics.addObject(this, xNew, yNew, xOld, yOld);
  268. }
  269. let syncer = this.syncer;
  270. syncer.o.x = this.x;
  271. syncer.o.y = this.y;
  272. if (this.aggro)
  273. this.aggro.move();
  274. this.fireEvent('afterMove');
  275. return true;
  276. },
  277. collisionEnter: function (obj) {
  278. let cpns = this.components;
  279. let cLen = cpns.length;
  280. for (let i = 0; i < cLen; i++) {
  281. let c = cpns[i];
  282. if (c.collisionEnter) {
  283. if (c.collisionEnter(obj))
  284. return true;
  285. }
  286. }
  287. },
  288. collisionExit: function (obj) {
  289. let cpns = this.components;
  290. let cLen = cpns.length;
  291. for (let i = 0; i < cLen; i++) {
  292. let c = cpns[i];
  293. if (c.collisionExit)
  294. c.collisionExit(obj);
  295. }
  296. },
  297. onEvent: function (eventName, callback) {
  298. const entry = {
  299. eventName,
  300. callback
  301. };
  302. this.eventListeners.push(entry);
  303. return this.offEvent.bind(this, entry);
  304. },
  305. offEvent: function (entry) {
  306. this.eventListeners.spliceWhere(e => e === entry);
  307. },
  308. fireEvent: function (event) {
  309. let args = [].slice.call(arguments, 1);
  310. let cpns = this.components;
  311. let cLen = cpns.length;
  312. for (let i = 0; i < cLen; i++) {
  313. let cpn = cpns[i];
  314. if (cpn.fireEvent)
  315. cpn.fireEvent(event, args);
  316. let events = cpn.events;
  317. if (!events)
  318. continue;
  319. let callback = events[event];
  320. if (!callback)
  321. continue;
  322. callback.apply(cpn, args);
  323. }
  324. this.eventListeners.forEach(l => {
  325. const { eventName, callback } = l;
  326. if (eventName !== event)
  327. return;
  328. callback.apply(null, args);
  329. });
  330. },
  331. destroy: function () {
  332. let cpns = this.components;
  333. let len = cpns.length;
  334. for (let i = 0; i < len; i++) {
  335. let c = cpns[i];
  336. if (c.destroy)
  337. c.destroy();
  338. }
  339. },
  340. toString: function () {
  341. let res = {};
  342. for (let p in this) {
  343. if (['components', 'syncer'].includes(p))
  344. continue;
  345. let val = this[p];
  346. let stringVal = (val && val.toString) ? val.toString() : val;
  347. const type = typeof(val);
  348. if (
  349. type !== 'function' &&
  350. (
  351. type !== 'object' ||
  352. val.type
  353. )
  354. )
  355. res[p] = stringVal;
  356. }
  357. return JSON.stringify(res, null, 4).split('"').join('') + '\r\n';
  358. }
  359. };