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.

1030 lines
23 KiB

  1. define([
  2. 'items/generator',
  3. 'items/salvager',
  4. 'items/enchanter',
  5. 'objects/objects',
  6. 'config/classes',
  7. 'mtx/mtx',
  8. 'config/factions',
  9. 'misc/events',
  10. 'items/itemEffects'
  11. ], function (
  12. generator,
  13. salvager,
  14. enchanter,
  15. objects,
  16. classes,
  17. mtx,
  18. factions,
  19. events,
  20. itemEffects
  21. ) {
  22. return {
  23. type: 'inventory',
  24. inventorySize: 50,
  25. items: [],
  26. blueprint: null,
  27. init: function (blueprint, isTransfer) {
  28. var items = blueprint.items || [];
  29. var iLen = items.length;
  30. //Spells should be sorted so they're EQ'd in the right order
  31. items.sort(function (a, b) {
  32. var aId = (a.spellId != null) ? ~~a.spellId : 9999;
  33. var bId = (b.spellId != null) ? ~~b.spellId : 9999;
  34. return (aId - bId);
  35. });
  36. for (var i = 0; i < iLen; i++) {
  37. var item = items[i];
  38. if ((item.pos >= this.inventorySize) || (item.eq))
  39. delete item.pos;
  40. //Hacks for old items
  41. if (((item.spell) && (!item.spell.rolls)) || (!item.sprite)) {
  42. items.splice(i, 1);
  43. i--;
  44. iLen--;
  45. continue;
  46. } else if ((item.spell) && (item.type == 'Spear')) {
  47. item.spell.properties = item.spell.properties || {};
  48. item.spell.properties.range = item.range;
  49. } else if (item.quantity == NaN)
  50. item.quantity = 1;
  51. else if ((item.effects) && (Object.keys(item.effects[0]).length == 0)) {
  52. items.splice(i, 1);
  53. i--;
  54. iLen--;
  55. continue;
  56. } else if ((item.slot != 'twoHanded') && (item.spell) && (!item.ability))
  57. delete item.spell;
  58. while (item.name.indexOf(`''`) > -1) {
  59. item.name = item.name.replace(`''`, `'`);
  60. }
  61. }
  62. this.hookItemEvents(items);
  63. for (var i = 0; i < iLen; i++) {
  64. var item = items[i];
  65. var pos = item.pos;
  66. var newItem = this.getItem(item, true, true);
  67. newItem.pos = pos;
  68. }
  69. if ((this.obj.player) && (!isTransfer))
  70. this.getDefaultAbilities();
  71. delete blueprint.items;
  72. this.blueprint = blueprint;
  73. },
  74. transfer: function () {
  75. this.hookItemEvents();
  76. },
  77. hookItemEvents: function (items) {
  78. var items = items || this.items;
  79. var iLen = items.length;
  80. for (var i = 0; i < iLen; i++) {
  81. var item = items[i];
  82. if (item.effects) {
  83. item.effects.forEach(function (e) {
  84. if (e.mtx) {
  85. var mtxUrl = mtx.get(e.mtx);
  86. var mtxModule = require(mtxUrl);
  87. e.events = mtxModule.events;
  88. } else if (e.factionId) {
  89. var faction = factions.getFaction(e.factionId);
  90. var statGenerator = faction.uniqueStat;
  91. statGenerator.generate(item);
  92. } else {
  93. var effectUrl = itemEffects.get(e.type);
  94. var effectModule = require(effectUrl);
  95. e.events = effectModule.events;
  96. }
  97. });
  98. }
  99. if ((item.pos == null) && (!item.eq)) {
  100. var pos = i;
  101. for (var j = 0; j < iLen; j++) {
  102. if (!items.some(fj => (fj.pos == j))) {
  103. pos = j;
  104. break;
  105. }
  106. }
  107. item.pos = pos;
  108. } else if ((!item.eq) && (items.some(ii => ((ii != item) && (ii.pos == item.pos))))) {
  109. var pos = item.pos;
  110. for (var j = 0; j < iLen; j++) {
  111. if (!items.some(fi => ((fi != item) && (fi.pos == j)))) {
  112. pos = j;
  113. break;
  114. }
  115. }
  116. item.pos = pos;
  117. }
  118. }
  119. },
  120. //Client Actions
  121. enchantItem: function (msg) {
  122. var item = this.findItem(msg.itemId);
  123. if ((!item) || (!item.slot) || (item.eq) || (item.noAugment) || ((msg.action == 'scour') && (item.power == 0))) {
  124. this.resolveCallback(msg);
  125. return;
  126. }
  127. enchanter.enchant(this.obj, item, msg);
  128. },
  129. getEnchantMaterials: function (msg) {
  130. var result = [];
  131. var item = this.findItem(msg.itemId);
  132. if ((item) && (item.slot))
  133. result = enchanter.getEnchantMaterials(item, msg.action);
  134. this.resolveCallback(msg, result);
  135. },
  136. learnAbility: function (itemId, runeSlot) {
  137. if (itemId.itemId != null) {
  138. var msg = itemId;
  139. itemId = msg.itemId;
  140. runeSlot = msg.slot;
  141. }
  142. var item = this.findItem(itemId);
  143. if (!item)
  144. return;
  145. else if (!item.spell) {
  146. item.eq = false;
  147. return;
  148. }
  149. var spellbook = this.obj.spellbook;
  150. if (item.slot == 'twoHanded')
  151. runeSlot = 0;
  152. else if (runeSlot == null) {
  153. if (!this.items.some(i => (i.runeSlot == 2)))
  154. runeSlot = 2;
  155. else
  156. runeSlot = 1;
  157. }
  158. var currentEq = this.items.find(i => (i.runeSlot == runeSlot));
  159. if (currentEq) {
  160. spellbook.removeSpellById(runeSlot);
  161. delete currentEq.eq;
  162. delete currentEq.runeSlot;
  163. this.obj.syncer.setArray(true, 'inventory', 'getItems', currentEq);
  164. }
  165. item.eq = true;
  166. item.runeSlot = runeSlot;
  167. delete item.pos;
  168. spellbook.addSpellFromRune(item.spell, runeSlot);
  169. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  170. },
  171. activateMtx: function (itemId) {
  172. var item = this.findItem(itemId);
  173. if (!item)
  174. return;
  175. else if (item.type != 'mtx') {
  176. delete item.active;
  177. return;
  178. }
  179. item.active = !item.active;
  180. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  181. },
  182. splitStack: function (msg) {
  183. var item = this.findItem(msg.itemId);
  184. if (!item)
  185. return;
  186. else if ((!item.quantity) || (item.quantity < msg.stackSize) || (msg.stackSize < 1))
  187. return;
  188. var newItem = extend(true, {}, item);
  189. item.quantity -= msg.stackSize;
  190. newItem.quantity = msg.stackSize;
  191. this.getItem(newItem, true, true);
  192. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  193. },
  194. combineStacks: function (msg) {
  195. var fromItem = this.findItem(msg.fromId);
  196. var toItem = this.findItem(msg.toId);
  197. if ((!fromItem) || (!toItem))
  198. return;
  199. else if ((!fromItem.quantity) || (!toItem.quantity))
  200. return;
  201. toItem.quantity += fromItem.quantity;
  202. this.obj.syncer.setArray(true, 'inventory', 'getItems', toItem);
  203. this.destroyItem(fromItem.id);
  204. },
  205. useItem: function (itemId) {
  206. var item = this.findItem(itemId);
  207. if (!item)
  208. return;
  209. if (item.cdMax) {
  210. if (item.cd) {
  211. process.send({
  212. method: 'events',
  213. data: {
  214. 'onGetAnnouncement': [{
  215. obj: {
  216. msg: 'That item is on cooldown'
  217. },
  218. to: [this.obj.serverId]
  219. }]
  220. }
  221. });
  222. return;
  223. }
  224. item.cd = item.cdMax;
  225. //Find similar items and put them on cooldown too
  226. this.items.forEach(function (i) {
  227. if ((i.name == item.name) && (i.cdMax == item.cdMax))
  228. i.cd = i.cdMax;
  229. });
  230. }
  231. var result = {};
  232. events.emit('onBeforeUseItem', this.obj, item, result);
  233. if (item.type == 'consumable') {
  234. if (item.uses) {
  235. item.uses--;
  236. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  237. return;
  238. }
  239. this.destroyItem(itemId, 1);
  240. }
  241. },
  242. unlearnAbility: function (itemId) {
  243. if (itemId.itemId != null)
  244. itemId = itemId.itemId;
  245. var item = this.findItem(itemId);
  246. if (!item)
  247. return;
  248. else if (!item.spell) {
  249. item.eq = false;
  250. return;
  251. }
  252. var spellbook = this.obj.spellbook;
  253. spellbook.removeSpellById(item.runeSlot);
  254. delete item.eq;
  255. delete item.runeSlot;
  256. this.setItemPosition(itemId);
  257. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  258. },
  259. stashItem: function (id) {
  260. var item = this.findItem(id);
  261. if ((!item) || (item.quest) || (item.noStash))
  262. return;
  263. delete item.pos;
  264. var stash = this.obj.stash;
  265. if (!stash.active)
  266. return;
  267. var clonedItem = extend(true, {}, item);
  268. this.destroyItem(id, null, true);
  269. stash.deposit(clonedItem);
  270. },
  271. salvageItem: function (id) {
  272. var item = this.findItem(id);
  273. if ((!item) || (item.material) || (item.quest) || (item.noSalvage) || (item.eq))
  274. return;
  275. var messages = [];
  276. var items = salvager.salvage(item);
  277. var iLen = items.length;
  278. if (!iLen)
  279. return;
  280. for (var i = 0; i < iLen; i++) {
  281. var material = items[i];
  282. this.getItem(material, true);
  283. messages.push({
  284. class: 'q' + material.quality,
  285. message: 'salvage (' + material.name + ' x' + material.quantity + ')'
  286. });
  287. }
  288. this.obj.instance.syncer.queue('onGetMessages', {
  289. id: this.obj.id,
  290. messages: messages
  291. }, [this.obj.serverId]);
  292. this.destroyItem(id);
  293. },
  294. destroyItem: function (id, amount, force) {
  295. var item = this.findItem(id);
  296. if ((!item) || ((item.noDestroy) && (!force)))
  297. return;
  298. amount = amount || item.quantity;
  299. if (item.eq)
  300. this.obj.equipment.unequip(id);
  301. if ((item.quantity) && (amount)) {
  302. item.quantity -= amount;
  303. if (item.quantity <= 0) {
  304. this.items.spliceWhere(i => i.id == id);
  305. this.obj.syncer.setArray(true, 'inventory', 'destroyItems', id);
  306. } else
  307. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  308. } else {
  309. this.items.spliceWhere(i => i.id == id);
  310. this.obj.syncer.setArray(true, 'inventory', 'destroyItems', id);
  311. }
  312. if (this.obj.player)
  313. this.getDefaultAbilities();
  314. this.obj.fireEvent('afterDestroyItem', item, amount);
  315. return item;
  316. },
  317. dropItem: function (id) {
  318. var item = this.findItem(id);
  319. if ((!item) || (item.noDrop))
  320. return;
  321. delete item.pos;
  322. //Find close open position
  323. var x = this.obj.x;
  324. var y = this.obj.y;
  325. var dropCell = this.obj.instance.physics.getOpenCellInArea(x - 1, y - 1, x + 1, y + 1);
  326. if (!dropCell)
  327. return;
  328. if (item.eq)
  329. this.obj.equipment.unequip(id);
  330. this.items.spliceWhere(i => i.id == id);
  331. this.obj.syncer.setArray(true, 'inventory', 'destroyItems', id);
  332. this.createBag(dropCell.x, dropCell.y, [item]);
  333. },
  334. moveItem: function (msgs) {
  335. msgs.forEach(function (m) {
  336. var item = this.findItem(m.id);
  337. if (!item)
  338. return;
  339. item.pos = m.pos;
  340. }, this);
  341. },
  342. mailItem: function (msg) {
  343. var item = this.findItem(msg.itemId);
  344. if (!item) {
  345. this.resolveCallback(msg);
  346. return;
  347. }
  348. delete item.pos;
  349. var io = require('security/io');
  350. io.get({
  351. ent: msg.recipient,
  352. field: 'character',
  353. callback: this.onCheckCharExists.bind(this, msg, item)
  354. });
  355. },
  356. onCheckCharExists: function (msg, item, res) {
  357. if (!res) {
  358. this.resolveCallback(msg, 'Recipient does not exist');
  359. return;
  360. }
  361. this.obj.instance.mail.sendMail(msg.recipient, [extend(true, {}, item)]);
  362. this.destroyItem(item.id);
  363. this.resolveCallback(msg);
  364. },
  365. //Helpers
  366. setItemPosition: function (id) {
  367. var item = this.findItem(id);
  368. if (!item)
  369. return;
  370. var iSize = this.inventorySize;
  371. for (var i = 0; i < iSize; i++) {
  372. if (!this.items.some(j => (j.pos == i))) {
  373. item.pos = i;
  374. break;
  375. }
  376. }
  377. },
  378. resolveCallback: function (msg, result) {
  379. var callbackId = (msg.callbackId != null) ? msg.callbackId : msg;
  380. result = result || [];
  381. if (callbackId == null)
  382. return;
  383. this.obj.instance.syncer.queue('serverModule', {
  384. module: 'atlas',
  385. method: 'resolveCallback',
  386. msg: {
  387. id: callbackId,
  388. result: result
  389. }
  390. });
  391. },
  392. findItem: function (id) {
  393. if (id == null)
  394. return null;
  395. return this.items.find(i => i.id == id);
  396. },
  397. getDefaultAbilities: function () {
  398. var hasWeapon = this.items.some(function (i) {
  399. return (
  400. (i.spell) &&
  401. (i.spell.rolls) &&
  402. (i.spell.rolls.damage != null) &&
  403. (i.slot == 'twoHanded')
  404. );
  405. });
  406. if (!hasWeapon) {
  407. var item = generator.generate({
  408. slot: 'twoHanded',
  409. type: classes.weapons[this.obj.class],
  410. quality: 0,
  411. spellQuality: 'mid'
  412. });
  413. item.eq = true;
  414. item.noSalvage = true;
  415. this.getItem(item);
  416. }
  417. classes.spells[this.obj.class].forEach(function (spellName) {
  418. var hasSpell = this.items.some(function (i) {
  419. return (
  420. (i.spell) &&
  421. (i.spell.name.toLowerCase() == spellName)
  422. );
  423. });
  424. if (!hasSpell) {
  425. var item = generator.generate({
  426. spell: true,
  427. spellQuality: 'basic',
  428. spellName: spellName
  429. });
  430. item.eq = true;
  431. item.noSalvage = true;
  432. this.getItem(item);
  433. }
  434. }, this);
  435. },
  436. createBag: function (x, y, items, ownerId) {
  437. if (ownerId == null)
  438. ownerId = -1;
  439. var bagCell = 50;
  440. var topQuality = 0;
  441. var iLen = items.length;
  442. for (var i = 0; i < iLen; i++) {
  443. var quality = items[i].quality;
  444. items[i].fromMob = !!this.obj.mob;
  445. if (quality > topQuality)
  446. topQuality = quality;
  447. }
  448. if (topQuality == 0)
  449. bagCell = 50;
  450. else if (topQuality == 1)
  451. bagCell = 51;
  452. else if (topQuality == 2)
  453. bagCell = 128;
  454. else if (topQuality == 3)
  455. bagCell = 52;
  456. else
  457. bagCell = 53;
  458. var obj = this.obj.instance.objects.buildObjects([{
  459. sheetName: 'objects',
  460. cell: bagCell,
  461. x: x,
  462. y: y,
  463. properties: {
  464. cpnChest: {
  465. ownerId: ownerId
  466. },
  467. cpnInventory: {
  468. items: extend(true, [], items)
  469. }
  470. }
  471. }]);
  472. return obj;
  473. },
  474. hasSpace: function () {
  475. if (this.inventorySize != -1) {
  476. var nonEqItems = this.items.filter(f => !f.eq).length;
  477. return (nonEqItems < this.inventorySize);
  478. } else
  479. return true;
  480. },
  481. getItem: function (item, hideMessage, noStack) {
  482. events.emit('onBeforeGetItem', item, this.obj);
  483. //We need to know if a mob dropped it for quest purposes
  484. var fromMob = item.fromMob;
  485. if (item.quality == null)
  486. item.quality = 0;
  487. //Players can't have fromMob items in their inventory but bags can (dropped by a mob)
  488. if (this.obj.player)
  489. delete item.fromMob;
  490. //Store the quantity to send to the player
  491. var quantity = item.quantity;
  492. var exists = false;
  493. if (((item.material) || (item.quest) || (item.quantity)) && (!item.noStack) && (!item.uses) && (!noStack)) {
  494. var existItem = this.items.find(i => (i.name == item.name));
  495. if (existItem) {
  496. exists = true;
  497. if (!existItem.quantity)
  498. existItem.quantity = 1;
  499. existItem.quantity += (item.quantity || 1);
  500. item = existItem;
  501. }
  502. }
  503. if (!exists)
  504. delete item.pos;
  505. //Get next id
  506. if (!exists) {
  507. var id = 0;
  508. var items = this.items;
  509. var iLen = items.length;
  510. if (!this.hasSpace()) {
  511. if (!hideMessage) {
  512. this.obj.instance.syncer.queue('onGetMessages', {
  513. id: this.obj.id,
  514. messages: [{
  515. class: 'q0',
  516. message: 'you bags are too full to loot any more items',
  517. type: 'info'
  518. }]
  519. }, [this.obj.serverId]);
  520. }
  521. return false;
  522. }
  523. for (var i = 0; i < iLen; i++) {
  524. var fItem = items[i];
  525. if (fItem.id >= id) {
  526. id = fItem.id + 1;
  527. }
  528. }
  529. item.id = id;
  530. if (item.eq)
  531. delete item.pos;
  532. if ((item.pos == null) && (!item.eq)) {
  533. var pos = iLen;
  534. for (var i = 0; i < iLen; i++) {
  535. if (!items.some(fi => (fi.pos == i))) {
  536. pos = i;
  537. break;
  538. }
  539. }
  540. item.pos = pos;
  541. }
  542. }
  543. if ((this.obj.player) && (!hideMessage)) {
  544. var messages = [];
  545. var msg = item.name;
  546. if (quantity)
  547. msg += ' x' + quantity;
  548. else if ((item.stats) && (item.stats.weight))
  549. msg += ` ${item.stats.weight}lb`;
  550. messages.push({
  551. class: 'q' + item.quality,
  552. message: 'loot: {' + msg + '}',
  553. item: item,
  554. type: 'loot'
  555. });
  556. this.obj.instance.syncer.queue('onGetDamage', {
  557. id: this.obj.id,
  558. event: true,
  559. text: 'loot'
  560. });
  561. this.obj.instance.syncer.queue('onGetMessages', {
  562. id: this.obj.id,
  563. messages: messages
  564. }, [this.obj.serverId]);
  565. }
  566. //TODO: Remove later, just for test
  567. if (item.stats) {
  568. var stats = Object.keys(item.stats);
  569. var sLen = stats.length
  570. for (var i = 0; i < sLen; i++) {
  571. var s = stats[i];
  572. var val = item.stats[s];
  573. if (s == 'maxHp') {
  574. delete item.stats[s];
  575. item.stats.hpMax = val;
  576. } else if (s == 'maxMana') {
  577. delete item.stats[s];
  578. item.stats.manaMax = val;
  579. }
  580. }
  581. }
  582. if (item.effects) {
  583. item.effects.forEach(function (e) {
  584. if (e.mtx) {
  585. var mtxUrl = mtx.get(e.mtx);
  586. var mtxModule = require(mtxUrl);
  587. e.events = mtxModule.events;
  588. } else if (e.type) {
  589. var effectUrl = itemEffects.get(e.type);
  590. var effectModule = require(effectUrl);
  591. e.text = effectModule.events.onGetText(item);
  592. e.events = effectModule.events;
  593. }
  594. });
  595. }
  596. if (!exists)
  597. this.items.push(item);
  598. if (item.eq) {
  599. if (item.ability)
  600. this.learnAbility(item.id, item.runeSlot);
  601. else
  602. this.obj.equipment.equip(item.id);
  603. } else {
  604. if (!item.effects)
  605. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  606. else {
  607. var result = extend(true, {}, item);
  608. result.effects = result.effects.map(e => ({
  609. factionId: e.factionId,
  610. text: e.text,
  611. properties: e.properties
  612. }));
  613. var reputation = this.obj.reputation;
  614. //Don't do this check if we don't have a reputation cpn. That means this is most likely a bag
  615. if ((reputation) && (result.factions)) {
  616. result.factions = result.factions.map(function (f) {
  617. var faction = reputation.getBlueprint(f.id);
  618. var factionTier = reputation.getTier(f.id);
  619. var noEquip = null;
  620. if (factionTier < f.tier)
  621. noEquip = true;
  622. return {
  623. name: faction.name,
  624. tier: f.tier,
  625. tierName: ['Hated', 'Hostile', 'Unfriendly', 'Neutral', 'Friendly', 'Honored', 'Revered', 'Exalted'][f.tier],
  626. noEquip: noEquip
  627. };
  628. }, this);
  629. }
  630. this.obj.syncer.setArray(true, 'inventory', 'getItems', result);
  631. }
  632. }
  633. if (!hideMessage) {
  634. if (fromMob)
  635. this.obj.fireEvent('afterLootMobItem', item);
  636. }
  637. return item;
  638. },
  639. dropBag: function (ownerId, killSource) {
  640. if (!this.blueprint)
  641. return;
  642. //Only drop loot if this player is in the zone
  643. var playerObject = this.obj.instance.objects.find(o => o.serverId == ownerId);
  644. if (!playerObject)
  645. return;
  646. //Get player's spells' statTypes
  647. var stats = [];
  648. playerObject.spellbook.spells.forEach(function (s) {
  649. var spellStatType = s.statType;
  650. if (!(spellStatType instanceof Array))
  651. spellStatType = [spellStatType];
  652. spellStatType.forEach(function (ss) {
  653. if (stats.indexOf(ss) == -1)
  654. stats.push(ss);
  655. });
  656. });
  657. var items = this.items;
  658. var iLen = items.length;
  659. for (var i = 0; i < iLen; i++) {
  660. delete items[i].eq;
  661. delete items[i].pos;
  662. }
  663. var blueprint = this.blueprint;
  664. var savedItems = extend(true, [], this.items);
  665. var instancedItems = extend(true, [], this.items);
  666. this.items = [];
  667. if ((!blueprint.noRandom) || (blueprint.alsoRandom)) {
  668. var magicFind = (blueprint.magicFind || 0);
  669. var bonusMagicFind = killSource.stats.values.magicFind;
  670. for (var i = 0; i < blueprint.rolls; i++) {
  671. if (Math.random() * 100 >= (blueprint.chance || 35))
  672. continue;
  673. /*var useItem = null;
  674. if (Math.random() < generator.spellChance) {
  675. useItem = instancedItems
  676. .filter(item => item.ability);
  677. if (useItem.length > 0)
  678. useItem = useItem[~~(Math.random() * useItem.length)];
  679. }
  680. if (!useItem) {
  681. var slot = generator.pickRandomSlot();
  682. var useItem = instancedItems.find(item => item.slot == slot);
  683. }
  684. if (!useItem)
  685. useItem = instancedItems[~~(Math.random() * iLen)];
  686. iLen--;
  687. instancedItems.spliceWhere(item => item == useItem);
  688. //Spells don't have stats
  689. if (useItem.stats)
  690. delete useItem.stats.armor;*/
  691. var itemBlueprint = {
  692. level: this.obj.stats.values.level,
  693. magicFind: magicFind,
  694. bonusMagicFind: bonusMagicFind
  695. };
  696. useItem = generator.generate(itemBlueprint);
  697. this.getItem(useItem);
  698. }
  699. }
  700. if (blueprint.noRandom) {
  701. var blueprints = blueprint.blueprints;
  702. for (var i = 0; i < blueprints.length; i++) {
  703. var drop = blueprints[i];
  704. if ((blueprint.chance) && (~~(Math.random() * 100) >= blueprint.chance))
  705. continue;
  706. else if ((drop.maxLevel) && (drop.maxLevel < killSource.stats.values.level))
  707. continue;
  708. else if ((drop.chance) && (~~(Math.random() * 100) >= drop.chance)) {
  709. continue;
  710. }
  711. drop.level = drop.level || this.obj.stats.values.level;
  712. drop.magicFind = magicFind;
  713. var item = drop;
  714. if (!item.quest)
  715. item = generator.generate(drop);
  716. if (!item.slot)
  717. delete item.level;
  718. this.getItem(item, true);
  719. }
  720. }
  721. killSource.fireEvent('beforeTargetDeath', this.obj, this.items);
  722. events.emit('onBeforeDropBag', this.obj, this.items, killSource);
  723. if (this.items.length > 0)
  724. this.createBag(this.obj.x, this.obj.y, this.items, ownerId);
  725. this.items = savedItems;
  726. },
  727. giveItems: function (obj, hideMessage) {
  728. var objInventory = obj.inventory;
  729. var messages = [];
  730. var items = this.items;
  731. var iLen = items.length;
  732. for (var i = 0; i < iLen; i++) {
  733. var item = items[i];
  734. if (objInventory.getItem(item, hideMessage)) {
  735. items.splice(i, 1);
  736. i--;
  737. iLen--;
  738. } else
  739. return false;
  740. }
  741. return true;
  742. },
  743. rollItems: function (party) {
  744. var items = this.items;
  745. var iLen = items.length;
  746. for (var i = 0; i < iLen; i++) {
  747. var item = items[i];
  748. this.obj.instance.syncer.queue('serverModule', {
  749. module: 'lootRoller',
  750. method: 'enqueue',
  751. msg: {
  752. party: party,
  753. item: item
  754. }
  755. });
  756. }
  757. this.items = [];
  758. },
  759. fireEvent: function (event, args) {
  760. var items = this.items;
  761. var iLen = items.length;
  762. for (var i = 0; i < iLen; i++) {
  763. var item = items[i];
  764. if ((!item.eq) && (!item.active))
  765. continue;
  766. var effects = item.effects;
  767. if (!effects)
  768. continue;
  769. var eLen = effects.length;
  770. for (var j = 0; j < eLen; j++) {
  771. var effect = effects[j];
  772. var effectEvent = effect.events[event];
  773. if (!effectEvent)
  774. continue;
  775. effectEvent.apply(this.obj, [item, ...args]);
  776. }
  777. }
  778. },
  779. clear: function () {
  780. delete this.items;
  781. this.items = [];
  782. },
  783. save: function () {
  784. return {
  785. type: 'inventory',
  786. items: this.items
  787. };
  788. },
  789. simplify: function (self) {
  790. if (!self)
  791. return null;
  792. var reputation = this.obj.reputation;
  793. return {
  794. type: 'inventory',
  795. items: this.items
  796. .map(function (i) {
  797. var item = extend(true, {}, i);
  798. if (item.effects) {
  799. item.effects = item.effects.map(e => ({
  800. factionId: e.factionId,
  801. text: e.text,
  802. properties: e.properties,
  803. mtx: e.mtx,
  804. type: e.type,
  805. rolls: e.rolls
  806. }));
  807. }
  808. if (item.factions) {
  809. item.factions = item.factions.map(function (f) {
  810. var faction = reputation.getBlueprint(f.id);
  811. var factionTier = reputation.getTier(f.id);
  812. var noEquip = null;
  813. if (factionTier < f.tier)
  814. noEquip = true;
  815. if (!faction)
  816. console.log(f);
  817. return {
  818. id: f.id,
  819. name: faction.name,
  820. tier: f.tier,
  821. tierName: ['Hated', 'Hostile', 'Unfriendly', 'Neutral', 'Friendly', 'Honored', 'Revered', 'Exalted'][f.tier],
  822. noEquip: noEquip
  823. };
  824. }, this);
  825. }
  826. return item;
  827. })
  828. };
  829. },
  830. update: function () {
  831. var items = this.items;
  832. var iLen = items.length;
  833. for (var i = 0; i < iLen; i++) {
  834. var item = items[i];
  835. if (!item.cd)
  836. continue;
  837. item.cd--;
  838. this.obj.syncer.setArray(true, 'inventory', 'getItems', item);
  839. }
  840. }
  841. };
  842. });