const AttackerInformationPacket = require("../Packets/AttackerInformation"); const HealthChangedPacket = require("../Packets/HealthChanged"); const ItemUsedPacket = require("../Packets/ItemUsed"); const itemTable = require("../Data/items"); const constants = require("../Data/constants"); const { CATEGORIES, AFFECTS, TYPES } = constants; const { CATEGORY_ITEM } = CATEGORIES; const { AFFECT_HITPOINT, AFFECT_SAILING_SPEED } = AFFECTS; const { ENTITY_TYPE_PLAYER } = TYPES; module.exports = function (ws, message, player) { const itemID = message.getUint8(6); const itemScheme = itemTable[itemID]; if (!itemScheme) return; if (!player.isAlive) return; const targetTypeID = message.getUint8(1); const targetID = message.getUint32(2); if (targetTypeID === player.typeID && targetID === player.id) return; // ??? const inventoryItem = player.inventory.getItem(itemID); const resolution = { statusID: itemScheme.statusID, itemID, amountToRemove: 0, isActive: !inventoryItem.isActive }; if (itemScheme.statusID && itemScheme.isDurable) { const index = player.activeStatusEffects.findIndex(id => id === itemScheme.statusID); if (index === -1) player.activeStatusEffects.push(itemScheme.statusID); else player.activeStatusEffects.splice(index, 1); }; const metadata = [player.hp.current / player.hp.maximum, player.isAttacking(), itemID, inventoryItem.isActive ? 0 : 1]; if (inventoryItem.isActive) { const packet = ItemUsedPacket(resolution); player.map.registerIndividualNetworkPacket(player.id, packet); player.inventory.disable(itemID); return metadata; }; const aliveTarget = itemScheme.isSelf ? player : player.map.getAliveEntityFromSubgroup(targetTypeID, targetID); const amount = 1; if (!itemScheme.isSelf && !aliveTarget) return; const targetMapMode = itemScheme.isSelf ? player.map.type : aliveTarget.map.type; if (itemScheme.allowedTargetTypes && !itemScheme.allowedTargetTypes[targetMapMode].includes(targetTypeID)) return; if (inventoryItem.nextUseAt > performance.now()) return; const isInRange = !itemScheme.isSelf && Math.pow(aliveTarget.position.x - player.position.x, 2) + Math.pow(aliveTarget.position.y - player.position.y, 2) < Math.pow(itemScheme.range, 2); if (itemScheme.range && !isInRange) return; if (inventoryItem.affects.includes(AFFECT_HITPOINT) && itemScheme.scale > 0 && aliveTarget.hp.maximum === aliveTarget.hp.current) return; const item = inventoryItem.activate(amount); if (!item) return; resolution.amountToRemove = item.removedAmount; const packet = ItemUsedPacket(resolution); player.map.registerIndividualNetworkPacket(player.id, packet); if (!itemScheme.isSelf) { const attackInitialized = { authorID: player.id, authorTypeID: player.typeID }; const attackInitializedPacket = AttackerInformationPacket(attackInitialized); player.map.registerIndividualNetworkPacket(aliveTarget.id, attackInitializedPacket); }; item.affects.forEach(affects => { switch (affects) { case AFFECT_HITPOINT: const healthUpdate = item.scale > 0 ? aliveTarget.increaseCurrentHitpoint(item.scale) : aliveTarget.decreaseCurrentHitpoint(item.scale, { authorSessionID: player.sessionID, authorGuildID: player.guild.id, authorID: player.id, authorTypeID: player.typeID }); if (aliveTarget.typeID === ENTITY_TYPE_PLAYER && aliveTarget.isAtMaximumHitpoints()) aliveTarget.cancelRepair(); const data = { authorTypeID: player.typeID, authorID: player.id, targetTypeID: aliveTarget.typeID, targetID: aliveTarget.id, amount: healthUpdate.normalizedAmount, isCritical: false, type: item.scale > 0 }; const packet = HealthChangedPacket(data); player.map.registerNetworkPacket(player.id, packet); break; case AFFECT_SAILING_SPEED: aliveTarget.changeSpeed(item.scale); aliveTarget.setReusableSingleEvent(itemScheme.iid, item.time, -item.scale); break; }; }); return metadata; };