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.
 
 
 

292 lines
6.2 KiB

  1. let classes = require('../config/spirits');
  2. const eventEmitter = require('../misc/events');
  3. module.exports = {
  4. type: 'player',
  5. seen: [],
  6. cdSave: 1000,
  7. cdSaveMax: 1000,
  8. update: function () {
  9. if (this.cdSave > 0)
  10. this.cdSave--;
  11. else {
  12. this.cdSave = this.cdSaveMax;
  13. this.obj.auth.doSave();
  14. }
  15. },
  16. spawn: function (character, cb) {
  17. let obj = this.obj;
  18. if (character.dead)
  19. obj.dead = true;
  20. extend(obj, {
  21. layerName: 'mobs',
  22. cell: character.cell,
  23. sheetName: character.sheetName,
  24. skinId: character.skinId,
  25. name: character.name,
  26. class: character.class,
  27. x: character.x,
  28. y: character.y,
  29. hidden: character.dead || null,
  30. account: character.account,
  31. zoneName: character.zoneName || clientConfig.config.defaultZone,
  32. zoneId: character.zoneId || null
  33. });
  34. character.components = character.components || [];
  35. let blueprintStats = character.components.find(c => c.type === 'stats') || {};
  36. extend(blueprintStats, classes.stats[obj.class]);
  37. if (!blueprintStats.values.hp)
  38. blueprintStats.values.hp = blueprintStats.values.hpMax;
  39. let stats = obj.addComponent('stats');
  40. for (let s in blueprintStats.values)
  41. stats.values[s] = blueprintStats.values[s];
  42. for (let s in blueprintStats.stats)
  43. stats.stats[s] = blueprintStats.stats[s];
  44. obj.portrait = classes.portraits[character.class];
  45. obj.addComponent('spellbook');
  46. obj.addComponent('dialogue');
  47. obj.addComponent('trade', character.components.find(c => c.type === 'trade'));
  48. obj.addComponent('reputation', character.components.find(c => c.type === 'reputation'));
  49. let social = character.components.find(c => c.type === 'social');
  50. if (social)
  51. delete social.party;
  52. obj.addComponent('social', social);
  53. obj.social.init();
  54. obj.social.party = null;
  55. obj.addComponent('aggro', {
  56. faction: 'players'
  57. });
  58. obj.addComponent('gatherer');
  59. obj.addComponent('stash');
  60. let blueprintEffects = character.components.find(c => c.type === 'effects') || {};
  61. if (blueprintEffects.effects) {
  62. //Calculate ttl of effects
  63. let time = +new Date();
  64. blueprintEffects.effects = blueprintEffects.effects.filter(e => {
  65. let remaining = e.expire - time;
  66. if (remaining < 0)
  67. return false;
  68. e.ttl = Math.max(~~(remaining / consts.tickTime), 1);
  69. return true;
  70. });
  71. }
  72. obj.addComponent('effects', blueprintEffects);
  73. let prophecies = character.components.find(c => c.type === 'prophecies');
  74. if (prophecies)
  75. obj.addComponent('prophecies', prophecies);
  76. ['equipment', 'passives', 'inventory', 'quests', 'events'].forEach(c => {
  77. obj.addComponent(c, character.components.find(f => f.type === c));
  78. });
  79. eventEmitter.emit('onAfterBuildPlayerObject', {
  80. obj: this.obj,
  81. saveData: character
  82. });
  83. obj.xp = stats.values.xp;
  84. obj.level = stats.values.level;
  85. stats.stats.logins++;
  86. atlas.addObject(this.obj, true);
  87. cons.emit('events', {
  88. onGetMessages: [{
  89. messages: [{
  90. class: 'color-blueB',
  91. message: this.obj.name + ' has come online'
  92. }]
  93. }],
  94. onGetConnectedPlayer: [cons.getCharacterList()]
  95. });
  96. cb();
  97. },
  98. broadcastSelf: function () {
  99. let obj = this.obj;
  100. let self = {
  101. id: obj.id,
  102. zoneId: obj.zoneId,
  103. name: obj.name,
  104. level: obj.level,
  105. class: obj.class
  106. };
  107. cons.emit('events', {
  108. onGetConnectedPlayer: [self]
  109. });
  110. },
  111. hasSeen: function (id) {
  112. return (this.seen.indexOf(id) > -1);
  113. },
  114. see: function (id) {
  115. this.seen.push(id);
  116. },
  117. unsee: function (id) {
  118. this.seen.spliceWhere(s => s === id);
  119. },
  120. die: function (source, permadeath) {
  121. let obj = this.obj;
  122. obj.clearQueue();
  123. let physics = obj.instance.physics;
  124. physics.removeObject(obj, obj.x, obj.y);
  125. obj.dead = true;
  126. obj.aggro.die();
  127. if (!permadeath) {
  128. let level = obj.stats.values.level;
  129. let spawns = obj.spawn;
  130. let spawnPos = spawns.filter(s => ((s.maxLevel && s.maxLevel >= level) || !s.maxLevel));
  131. if (!spawnPos.length || !source.name)
  132. spawnPos = spawns[0];
  133. else if (source.name) {
  134. let sourceSpawnPos = spawnPos.find(s => ((s.source) && (s.source.toLowerCase() === source.name.toLowerCase())));
  135. if (sourceSpawnPos)
  136. spawnPos = sourceSpawnPos;
  137. else
  138. spawnPos = spawnPos[0];
  139. }
  140. obj.instance.eventEmitter.emit('onBeforePlayerRespawn', obj, spawnPos);
  141. obj.x = spawnPos.x;
  142. obj.y = spawnPos.y;
  143. obj.stats.die(source);
  144. process.send({
  145. method: 'object',
  146. serverId: obj.serverId,
  147. obj: {
  148. dead: true
  149. }
  150. });
  151. } else {
  152. process.send({
  153. method: 'object',
  154. serverId: obj.serverId,
  155. obj: {
  156. dead: true,
  157. permadead: true
  158. }
  159. });
  160. }
  161. obj.fireEvent('onAfterDeath', source);
  162. obj.auth.track('combat', 'death', source.name, 1);
  163. obj.spellbook.die();
  164. obj.effects.die();
  165. },
  166. respawn: function () {
  167. const obj = this.obj;
  168. const spawnPos = {
  169. x: obj.x,
  170. y: obj.y
  171. };
  172. obj.instance.eventEmitter.emit('onBeforePlayerRespawn', obj, spawnPos);
  173. if (!spawnPos.zoneName) {
  174. obj.x = spawnPos.x;
  175. obj.y = spawnPos.y;
  176. let syncer = obj.syncer;
  177. syncer.o.x = obj.x;
  178. syncer.o.y = obj.y;
  179. obj.effects.addEffect({
  180. type: 'invulnerability',
  181. force: true,
  182. ttl: 28
  183. });
  184. obj.aggro.move();
  185. obj.instance.physics.addObject(obj, obj.x, obj.y);
  186. obj.instance.syncer.queue('teleportToPosition', {
  187. x: obj.x,
  188. y: obj.y
  189. }, [obj.serverId]);
  190. } else {
  191. obj.fireEvent('beforeRezone');
  192. obj.destroyed = true;
  193. let simpleObj = obj.getSimple(true, false, true);
  194. simpleObj.x = spawnPos.x;
  195. simpleObj.y = spawnPos.y;
  196. process.send({
  197. method: 'rezone',
  198. id: obj.serverId,
  199. args: {
  200. obj: simpleObj,
  201. newZone: spawnPos.zoneName
  202. }
  203. });
  204. }
  205. },
  206. move: function (msg) {
  207. atlas.queueAction(this.obj, {
  208. action: 'move',
  209. data: msg.data
  210. });
  211. },
  212. castSpell: function (msg) {
  213. atlas.queueAction(this.obj, {
  214. action: 'spell',
  215. data: msg.data
  216. });
  217. },
  218. queueAction: function (msg) {
  219. atlas.queueAction(this.obj, msg.data);
  220. },
  221. performAction: function (msg) {
  222. if (msg.callback)
  223. msg.data.data.callbackId = atlas.registerCallback(msg.callback);
  224. atlas.performAction(this.obj, msg.data);
  225. },
  226. clearQueue: function (msg) {
  227. const spellbook = this.obj.spellbook;
  228. if (spellbook.isCasting())
  229. spellbook.stopCasting();
  230. else
  231. this.obj.clearQueue();
  232. }
  233. };