Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

439 wiersze
8.4 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.isDefined('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. const syncTypes = ['portrait', 'area'];
  88. const ignoreKeysWhenNotSelf = ['account'];
  89. for (let p in o) {
  90. let value = o[p];
  91. if (value === null)
  92. continue;
  93. let type = typeof (value);
  94. if (type === 'function')
  95. continue;
  96. else if (type !== 'object') {
  97. if (self || !ignoreKeysWhenNotSelf.includes(p))
  98. result[p] = value;
  99. } else if (type === 'undefined')
  100. continue;
  101. else {
  102. if (value.type) {
  103. if (!value.simplify) {
  104. if (self) {
  105. result.components.push({
  106. type: value.type
  107. });
  108. }
  109. } else {
  110. let component = null;
  111. if (isSave && value.save)
  112. component = value.save();
  113. else if (isTransfer && value.simplifyTransfer)
  114. component = value.simplifyTransfer();
  115. else
  116. component = value.simplify(self);
  117. if (value.destroyed) {
  118. if (!component) {
  119. component = {
  120. type: value.type
  121. };
  122. }
  123. component.destroyed = true;
  124. }
  125. if (component)
  126. result.components.push(component);
  127. }
  128. } else if (syncTypes.includes(p))
  129. result[p] = value;
  130. continue;
  131. }
  132. }
  133. return result;
  134. },
  135. sendEvent: function (event, data) {
  136. process.send({
  137. method: 'event',
  138. id: this.serverId,
  139. data: {
  140. event: event,
  141. data: data
  142. }
  143. });
  144. },
  145. queue: function (action) {
  146. if (action.action === 'clearQueue') {
  147. let spellbook = this.spellbook;
  148. if (spellbook.isCasting())
  149. spellbook.stopCasting();
  150. else
  151. this.clearQueue();
  152. return;
  153. } else if (action.action === 'spell') {
  154. let spellbook = this.spellbook;
  155. const isCasting = spellbook.isCasting();
  156. if (isCasting && (!action.priority || !spellbook.canCast(action))) {
  157. if (action.auto)
  158. spellbook.queueAuto(action);
  159. return;
  160. }
  161. if (isCasting)
  162. spellbook.stopCasting();
  163. this.actionQueue.spliceWhere(a => a.priority);
  164. this.actionQueue.splice(0, 0, action);
  165. } else {
  166. if (action.priority) {
  167. this.spellbook.stopCasting();
  168. this.actionQueue.splice(0, 0, action);
  169. return;
  170. }
  171. this.actionQueue.push(action);
  172. }
  173. },
  174. dequeue: function () {
  175. if (this.actionQueue.length === 0)
  176. return null;
  177. return this.actionQueue.splice(0, 1)[0];
  178. },
  179. clearQueue: function () {
  180. if (this.isDefined('serverId')) {
  181. this.instance.syncer.queue('onClearQueue', {
  182. id: this.id
  183. }, [this.serverId]);
  184. }
  185. this.actionQueue = [];
  186. this.fireEvent('clearQueue');
  187. },
  188. performAction: function (action) {
  189. if (action.instanceModule)
  190. return;
  191. let cpn = this[action.cpn];
  192. if (!cpn)
  193. return;
  194. cpn[action.method](action.data);
  195. },
  196. performQueue: function () {
  197. let q = this.dequeue();
  198. if (!q)
  199. return;
  200. if (q.action === 'move') {
  201. let maxDistance = 1;
  202. if ((this.actionQueue[0]) && (this.actionQueue[0].action === 'move')) {
  203. let moveEvent = {
  204. sprintChance: this.stats.values.sprintChance || 0
  205. };
  206. this.fireEvent('onBeforeTryMove', moveEvent);
  207. let physics = this.instance.physics;
  208. let sprintChance = moveEvent.sprintChance;
  209. do {
  210. if ((~~(Math.random() * 100) < sprintChance) && (!physics.isTileBlocking(q.data.x, q.data.y))) {
  211. q = this.dequeue();
  212. maxDistance++;
  213. }
  214. sprintChance -= 100;
  215. } while (sprintChance > 0 && this.actionQueue.length > 0);
  216. }
  217. q.maxDistance = maxDistance;
  218. let success = this.performMove(q);
  219. if (!success)
  220. this.clearQueue();
  221. } else if (q.action === 'spell') {
  222. let success = this.spellbook.cast(q);
  223. if (!success)
  224. this.performQueue();
  225. }
  226. },
  227. performMove: function (action) {
  228. const { x: xOld, y: yOld, syncer, aggro, instance: { physics } } = this;
  229. const { maxDistance = 1, force, data } = action;
  230. const { x: xNew, y: yNew } = data;
  231. if (!force) {
  232. if (physics.isTileBlocking(data.x, data.y))
  233. return true;
  234. data.success = true;
  235. this.fireEvent('beforeMove', data);
  236. if (data.success === false) {
  237. action.priority = true;
  238. this.queue(action);
  239. return true;
  240. }
  241. let deltaX = Math.abs(xOld - xNew);
  242. let deltaY = Math.abs(yOld - yNew);
  243. if (
  244. (
  245. (deltaX > maxDistance) ||
  246. (deltaY > maxDistance)
  247. ) ||
  248. (
  249. (deltaX === 0) &&
  250. (deltaY === 0)
  251. )
  252. )
  253. return false;
  254. }
  255. this.x = xNew;
  256. this.y = yNew;
  257. if (physics.addObject(this, xNew, yNew))
  258. physics.removeObject(this, xOld, yOld);
  259. else {
  260. this.x = xOld;
  261. this.y = yOld;
  262. return false;
  263. }
  264. //We can't use xNew and yNew because addObject could have changed the position (like entering a building interior with stairs)
  265. syncer.o.x = this.x;
  266. syncer.o.y = this.y;
  267. if (aggro)
  268. aggro.move();
  269. this.fireEvent('afterMove');
  270. return true;
  271. },
  272. collisionEnter: function (obj) {
  273. let cpns = this.components;
  274. let cLen = cpns.length;
  275. for (let i = 0; i < cLen; i++) {
  276. let c = cpns[i];
  277. if (c.collisionEnter) {
  278. if (c.collisionEnter(obj))
  279. return true;
  280. }
  281. }
  282. },
  283. collisionExit: function (obj) {
  284. let cpns = this.components;
  285. let cLen = cpns.length;
  286. for (let i = 0; i < cLen; i++) {
  287. let c = cpns[i];
  288. if (c.collisionExit)
  289. c.collisionExit(obj);
  290. }
  291. },
  292. onEvent: function (eventName, callback) {
  293. const entry = {
  294. eventName,
  295. callback
  296. };
  297. this.eventListeners.push(entry);
  298. return this.offEvent.bind(this, entry);
  299. },
  300. offEvent: function (entry) {
  301. this.eventListeners.spliceWhere(e => e === entry);
  302. },
  303. fireEvent: function (event) {
  304. let args = [].slice.call(arguments, 1);
  305. let cpns = this.components;
  306. let cLen = cpns.length;
  307. for (let i = 0; i < cLen; i++) {
  308. let cpn = cpns[i];
  309. if (cpn.fireEvent)
  310. cpn.fireEvent(event, args);
  311. let events = cpn.events;
  312. if (!events)
  313. continue;
  314. let callback = events[event];
  315. if (!callback)
  316. continue;
  317. callback.apply(cpn, args);
  318. }
  319. this.eventListeners.forEach(l => {
  320. const { eventName, callback } = l;
  321. if (eventName !== event)
  322. return;
  323. callback.apply(null, args);
  324. });
  325. },
  326. destroy: function () {
  327. let cpns = this.components;
  328. let len = cpns.length;
  329. for (let i = 0; i < len; i++) {
  330. let c = cpns[i];
  331. if (c.destroy)
  332. c.destroy();
  333. }
  334. },
  335. toString: function () {
  336. let res = {};
  337. for (let p in this) {
  338. if (['components', 'syncer'].includes(p))
  339. continue;
  340. let val = this[p];
  341. let stringVal = (val && val.toString) ? val.toString() : val;
  342. const type = typeof(val);
  343. if (
  344. type !== 'function' &&
  345. (
  346. type !== 'object' ||
  347. val.type
  348. )
  349. )
  350. res[p] = stringVal;
  351. }
  352. return JSON.stringify(res, null, 4).split('"').join('') + '\r\n';
  353. }
  354. };