Master See merge request Isleward/isleward!584tags/v0.10.6.10
@@ -36,7 +36,8 @@ define([ | |||
method: 'performAction', | |||
data: { | |||
cpn: 'stats', | |||
method: 'respawn' | |||
method: 'respawn', | |||
data: {} | |||
} | |||
}); | |||
}, | |||
@@ -172,7 +172,7 @@ define([ | |||
unequipItem: function (item) { | |||
const isQuickslot = item.has('quickSlot'); | |||
const method = isQuickslot ? 'setQuickSlot' : 'unequip'; | |||
const data = isQuickslot ? { slot: item.quickSlot } : item.id; | |||
const data = isQuickslot ? { slot: item.quickSlot } : { itemId: item.id }; | |||
client.request({ | |||
cpn: 'player', | |||
@@ -290,7 +290,7 @@ define([ | |||
let cpn = 'equipment'; | |||
let method = 'equip'; | |||
let data = item.id; | |||
let data = { itemId: item.id }; | |||
if (item.empty) | |||
method = 'unequip'; | |||
@@ -174,6 +174,8 @@ define([ | |||
let method = 'moveItem'; | |||
if ((this.hoverCell) && (this.hoverCell[0] !== this.dragItem[0])) { | |||
const data = {}; | |||
let placeholder = $('<div></div>') | |||
.insertAfter(this.dragItem); | |||
@@ -182,10 +184,12 @@ define([ | |||
placeholder.remove(); | |||
let msgs = [{ | |||
id: this.dragItem.data('item').id, | |||
pos: this.dragItem.index() | |||
itemId: this.dragItem.data('item').id, | |||
targetPos: this.dragItem.index() | |||
}]; | |||
data.moveMsgs = msgs; | |||
this.items.find(function (i) { | |||
return (i.id === this.dragItem.data('item').id); | |||
}, this).pos = this.dragItem.index(); | |||
@@ -194,19 +198,19 @@ define([ | |||
if (hoverCellItem) { | |||
if ((hoverCellItem.name !== this.dragItem.data('item').name) || (!hoverCellItem.quantity)) { | |||
msgs.push({ | |||
id: hoverCellItem.id, | |||
pos: this.hoverCell.index() | |||
itemId: hoverCellItem.id, | |||
targetPos: this.hoverCell.index() | |||
}); | |||
this.items.find(function (i) { | |||
return (i.id === hoverCellItem.id); | |||
}, this).pos = this.hoverCell.index(); | |||
} else { | |||
delete data.moveMsgs; | |||
data.fromId = this.dragItem.data('item').id; | |||
data.toId = hoverCellItem.id; | |||
method = 'combineStacks'; | |||
msgs = { | |||
fromId: this.dragItem.data('item').id, | |||
toId: hoverCellItem.id | |||
}; | |||
} | |||
} | |||
@@ -216,7 +220,7 @@ define([ | |||
data: { | |||
cpn: 'inventory', | |||
method: method, | |||
data: msgs | |||
data | |||
} | |||
}); | |||
@@ -516,7 +520,9 @@ define([ | |||
else if ((action === 'learnAbility') && (!window.player.inventory.canEquipItem(item))) | |||
return; | |||
let data = item.id; | |||
let data = { | |||
itemId: item.id | |||
}; | |||
let cpn = 'inventory'; | |||
if (['equip', 'setQuickSlot'].includes(action)) { | |||
@@ -537,9 +543,9 @@ define([ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
cpn: cpn, | |||
cpn, | |||
method: action, | |||
data: data | |||
data | |||
} | |||
}); | |||
}, | |||
@@ -216,7 +216,9 @@ define([ | |||
client.request({ | |||
cpn: 'social', | |||
method: 'removeFromParty', | |||
data: id | |||
data: { | |||
id | |||
} | |||
}); | |||
}, | |||
@@ -86,7 +86,9 @@ define([ | |||
data: { | |||
cpn: 'quests', | |||
method: 'complete', | |||
data: quest.id | |||
data: { | |||
questId: quest.id | |||
} | |||
} | |||
}); | |||
}, | |||
@@ -196,7 +196,9 @@ define([ | |||
data: { | |||
cpn: 'stash', | |||
method: 'withdraw', | |||
data: item.id | |||
data: { | |||
itemId: item.id | |||
} | |||
} | |||
}); | |||
}, | |||
@@ -74,11 +74,11 @@ define([ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
targetId: this.wardrobeId, | |||
cpn: 'wardrobe', | |||
method: 'apply', | |||
data: { | |||
skinId: this.skin.id | |||
skinId: this.skin.id, | |||
targetId: this.wardrobeId | |||
} | |||
} | |||
}); | |||
@@ -86,10 +86,10 @@ define([ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
targetId: this.workbenchId, | |||
cpn: 'workbench', | |||
method: 'getRecipe', | |||
data: { | |||
targetId: this.workbenchId, | |||
name: recipeName | |||
} | |||
}, | |||
@@ -215,10 +215,10 @@ define([ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
targetId: this.workbenchId, | |||
cpn: 'workbench', | |||
method: 'getRecipe', | |||
data: { | |||
targetId: this.workbenchId, | |||
name: this.currentRecipe.name, | |||
pickedItemIds | |||
} | |||
@@ -271,10 +271,10 @@ define([ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
targetId: this.workbenchId, | |||
cpn: 'workbench', | |||
method: 'craft', | |||
data: { | |||
targetId: this.workbenchId, | |||
name: selectedRecipe, | |||
pickedItemIds | |||
} | |||
@@ -61,7 +61,8 @@ define([ | |||
method: 'performAction', | |||
data: { | |||
cpn: 'gatherer', | |||
method: 'gather' | |||
method: 'gather', | |||
data: {} | |||
} | |||
}); | |||
}, | |||
@@ -44,10 +44,11 @@ define([ | |||
if (keyEvent.key === 'esc') { | |||
client.request({ | |||
cpn: 'player', | |||
method: 'queueAction', | |||
method: 'performAction', | |||
data: { | |||
action: 'clearQueue', | |||
priority: true | |||
cpn: 'player', | |||
method: 'clearQueue', | |||
data: {} | |||
} | |||
}); | |||
} | |||
@@ -77,10 +77,10 @@ define([ | |||
client.request({ | |||
cpn: 'player', | |||
method: 'move', | |||
priority: !this.path.length, | |||
data: { | |||
x: x, | |||
y: y | |||
y: y, | |||
priority: !this.path.length | |||
} | |||
}); | |||
}, | |||
@@ -102,9 +102,8 @@ define([ | |||
if (!target && this.target && (!this.hoverTarget || this.hoverTarget.id !== this.target.id)) { | |||
client.request({ | |||
cpn: 'player', | |||
method: 'queueAction', | |||
method: 'castSpell', | |||
data: { | |||
action: 'spell', | |||
priority: true, | |||
target: null | |||
} | |||
@@ -193,9 +192,8 @@ define([ | |||
client.request({ | |||
cpn: 'player', | |||
method: 'queueAction', | |||
method: 'castSpell', | |||
data: { | |||
action: 'spell', | |||
priority: input.isKeyDown('ctrl'), | |||
spell: spell.id, | |||
target: target, | |||
@@ -87,10 +87,11 @@ define([ | |||
client.request({ | |||
cpn: 'player', | |||
method: 'queueAction', | |||
method: 'performAction', | |||
data: { | |||
action: 'clearQueue', | |||
priority: true | |||
cpn: 'player', | |||
method: 'clearQueue', | |||
data: {} | |||
} | |||
}); | |||
@@ -80,9 +80,11 @@ module.exports = { | |||
obj.syncer.setArray(true, 'serverActions', 'removeActions', { | |||
key: 'u', | |||
action: { | |||
targetId: this.obj.id, | |||
cpn: 'door', | |||
method: 'unlock' | |||
method: 'unlock', | |||
data: { | |||
targetId: this.obj.id | |||
} | |||
} | |||
}); | |||
}, | |||
@@ -107,9 +109,11 @@ module.exports = { | |||
key: 'u', | |||
name: this.closed ? 'open door' : 'close door', | |||
action: { | |||
targetId: this.obj.id, | |||
cpn: 'door', | |||
method: 'unlock' | |||
method: 'unlock', | |||
data: { | |||
targetId: this.obj.id | |||
} | |||
} | |||
}); | |||
} | |||
@@ -148,7 +152,7 @@ module.exports = { | |||
const key = obj.inventory.items.find(i => i.keyId === this.key); | |||
if (key && (key.singleUse || this.destroyKey)) { | |||
obj.inventory.destroyItem(key.id, 1); | |||
obj.inventory.destroyItem({ itemId: key.id }, 1); | |||
const message = `The ${key.name} disintegrates on use`; | |||
obj.social.notifySelf({ message }); | |||
@@ -45,7 +45,7 @@ module.exports = { | |||
} | |||
if (!this.eq.has(item.slot)) { | |||
this.equip(itemId); | |||
this.equip({ itemId }); | |||
return true; | |||
} | |||
}, | |||
@@ -72,14 +72,14 @@ module.exports = { | |||
slot = item.equipSlot || item.slot; | |||
if (slot === 'twoHanded') { | |||
if (this.eq.has('offHand')) | |||
this.unequip(this.eq.offHand, true); | |||
this.unequip({ itemId: this.eq.offHand }, true); | |||
slot = 'oneHanded'; | |||
} else if (slot === 'offHand') { | |||
if (this.eq.has('oneHanded')) { | |||
let oneHandedEq = inventory.findItem(this.eq.oneHanded); | |||
if (oneHandedEq.slot === 'twoHanded') | |||
this.unequip(this.eq.oneHanded, true); | |||
this.unequip({ itemId: this.eq.oneHanded }, true); | |||
} | |||
} | |||
@@ -113,7 +113,7 @@ module.exports = { | |||
if (this.eq[slot] === item.id) | |||
return; | |||
this.unequip(this.eq[slot], true); | |||
this.unequip({ itemId: this.eq[slot] }, true); | |||
} | |||
applyItemStats(obj, item, true); | |||
@@ -126,7 +126,7 @@ module.exports = { | |||
if ((!obj.mob) || (item.ability)) { | |||
if (item.spell) | |||
inventory.learnAbility(itemId, item.runeSlot); | |||
inventory.learnAbility({ itemId }, item.runeSlot); | |||
else | |||
obj.syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item)); | |||
} | |||
@@ -164,7 +164,7 @@ module.exports = { | |||
if (item.spell) { | |||
item.eq = true; | |||
inventory.unlearnAbility(itemId, item.runeSlot); | |||
inventory.unlearnAbility({ itemId }, item.runeSlot); | |||
} else | |||
obj.syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item)); | |||
@@ -178,7 +178,7 @@ module.exports = { | |||
unequipAll: function () { | |||
let eq = this.eq; | |||
Object.keys(this.eq).forEach(function (slot) { | |||
this.unequip(eq[slot]); | |||
this.unequip({ itemId: eq[slot] }); | |||
}, this); | |||
}, | |||
@@ -228,7 +228,7 @@ module.exports = { | |||
if (!item) | |||
return; | |||
inventory.useItem(this.quickSlots[0]); | |||
inventory.useItem({ itemId: this.quickSlots[0] }); | |||
if (item.uses <= 0 && !item.quantity) | |||
this.replaceQuickSlot(item); | |||
@@ -256,7 +256,7 @@ module.exports = { | |||
let errors = inventory.equipItemErrors(item); | |||
if (errors.length > 0) { | |||
this.unequip(itemId); | |||
this.unequip({ itemId: itemId }); | |||
let message = ({ | |||
int: `You suddenly feel too stupid to wear your ${item.name}`, | |||
@@ -290,7 +290,7 @@ module.exports = { | |||
return; | |||
if (findFaction.tier > tier) { | |||
this.unequip(itemId); | |||
this.unequip({ itemId }); | |||
const message = `You unequip your ${item.name} as it zaps you.`; | |||
this.obj.social.notifySelf({ | |||
@@ -352,7 +352,7 @@ module.exports = { | |||
unEq: function () { | |||
let eq = this.obj.equipment; | |||
Object.keys(eq.eq).forEach(function (slot) { | |||
eq.unequip(eq.eq[slot]); | |||
eq.unequip({ itemId: eq.eq[slot] }); | |||
}); | |||
}, | |||
@@ -362,7 +362,7 @@ module.exports = { | |||
inventory.items | |||
.filter(i => !i.eq) | |||
.map(i => i.id) | |||
.forEach(i => inventory.destroyItem(i, null, true)); | |||
.forEach(i => inventory.destroyItem({ itemId: i }, null, true)); | |||
}, | |||
getItem: function (config) { | |||
@@ -442,7 +442,7 @@ module.exports = { | |||
let newItem = this.obj.inventory.getItem(item); | |||
if (eq) | |||
this.obj.equipment.equip(newItem.id); | |||
this.obj.equipment.equip({ itemId: newItem.id }); | |||
}, | |||
getGold: function (amount) { | |||
@@ -271,9 +271,11 @@ module.exports = { | |||
obj.syncer.setArray(true, 'serverActions', action, { | |||
key: 'u', | |||
action: { | |||
targetId: obj.id, | |||
cpn: 'gatherer', | |||
method: 'gather' | |||
method: 'gather', | |||
data: { | |||
targetId: obj.id | |||
} | |||
} | |||
}); | |||
}, | |||
@@ -247,10 +247,10 @@ module.exports = { | |||
toItem.quantity += fromItem.quantity; | |||
this.obj.syncer.setArray(true, 'inventory', 'getItems', toItem); | |||
this.destroyItem(fromItem.id, null, true); | |||
this.destroyItem({ itemId: fromItem.id }, null, true); | |||
}, | |||
useItem: function (itemId) { | |||
useItem: function ({ itemId }) { | |||
useItem(this, itemId); | |||
}, | |||
@@ -275,8 +275,8 @@ module.exports = { | |||
this.obj.syncer.setArray(true, 'inventory', 'getItems', item); | |||
}, | |||
stashItem: async function (id) { | |||
const item = this.findItem(id); | |||
stashItem: async function ({ itemId }) { | |||
const item = this.findItem(itemId); | |||
if (!item || item.quest || item.noStash) | |||
return; | |||
@@ -288,11 +288,11 @@ module.exports = { | |||
if (!success) | |||
return; | |||
this.destroyItem(id, null, true); | |||
this.destroyItem({ itemId: itemId }, null, true); | |||
}, | |||
salvageItem: function (id) { | |||
let item = this.findItem(id); | |||
salvageItem: function ({ itemId }) { | |||
let item = this.findItem(itemId); | |||
if ((!item) || (item.material) || (item.quest) || (item.noSalvage) || (item.eq)) | |||
return; | |||
@@ -300,7 +300,7 @@ module.exports = { | |||
let items = salvager.salvage(item); | |||
this.destroyItem(id); | |||
this.destroyItem({ itemId: itemId }); | |||
for (const material of items) { | |||
this.getItem(material, true, false, false, true); | |||
@@ -314,27 +314,27 @@ module.exports = { | |||
this.obj.social.notifySelfArray(messages); | |||
}, | |||
destroyItem: function (id, amount, force) { | |||
let item = this.findItem(id); | |||
destroyItem: function ({ itemId }, amount, force) { | |||
let item = this.findItem(itemId); | |||
if (!item || (item.noDestroy && !force)) | |||
return; | |||
amount = amount || item.quantity; | |||
if (item.eq) | |||
this.obj.equipment.unequip(id); | |||
this.obj.equipment.unequip({ itemId }); | |||
if ((item.quantity) && (amount)) { | |||
item.quantity -= amount; | |||
if (item.quantity <= 0) { | |||
this.items.spliceWhere(i => i.id === id); | |||
this.obj.syncer.setArray(true, 'inventory', 'destroyItems', id); | |||
this.items.spliceWhere(i => i.id === itemId); | |||
this.obj.syncer.setArray(true, 'inventory', 'destroyItems', itemId); | |||
} else | |||
this.obj.syncer.setArray(true, 'inventory', 'getItems', item); | |||
} else { | |||
this.items.spliceWhere(i => i.id === id); | |||
this.obj.syncer.setArray(true, 'inventory', 'destroyItems', id); | |||
this.obj.syncer.deleteFromArray(true, 'inventory', 'getItems', i => i.id === id); | |||
this.items.spliceWhere(i => i.id === itemId); | |||
this.obj.syncer.setArray(true, 'inventory', 'destroyItems', itemId); | |||
this.obj.syncer.deleteFromArray(true, 'inventory', 'getItems', i => i.id === itemId); | |||
} | |||
this.obj.fireEvent('afterDestroyItem', item, amount); | |||
@@ -343,8 +343,8 @@ module.exports = { | |||
return item; | |||
}, | |||
dropItem: function (id) { | |||
let item = this.findItem(id); | |||
dropItem: function ({ itemId }) { | |||
let item = this.findItem(itemId); | |||
if ((!item) || (item.noDrop) || (item.quest)) | |||
return; | |||
@@ -367,25 +367,25 @@ module.exports = { | |||
return; | |||
if (item.eq) | |||
this.obj.equipment.unequip(id); | |||
this.obj.equipment.unequip(itemId); | |||
this.items.spliceWhere(i => i.id === id); | |||
this.items.spliceWhere(i => i.id === itemId); | |||
this.obj.syncer.setArray(true, 'inventory', 'destroyItems', id); | |||
this.obj.syncer.setArray(true, 'inventory', 'destroyItems', itemId); | |||
this.createBag(dropCell.x, dropCell.y, [item]); | |||
events.emit('afterPlayerDropItem', this.obj, item); | |||
}, | |||
moveItem: function (msgs) { | |||
msgs.forEach(function (m) { | |||
let item = this.findItem(m.id); | |||
moveItem: function ({ moveMsgs }) { | |||
moveMsgs.forEach(({ itemId, targetPos }) => { | |||
let item = this.findItem(itemId); | |||
if (!item) | |||
return; | |||
item.pos = m.pos; | |||
}, this); | |||
item.pos = targetPos; | |||
}); | |||
}, | |||
hookItemEvents: function (items) { | |||
@@ -124,10 +124,10 @@ module.exports = (cpnInv, item, hideMessage, noStack, hideAlert, createBagIfFull | |||
if (item.eq) { | |||
if (item.ability) | |||
cpnInv.learnAbility(item.id, item.runeSlot); | |||
cpnInv.learnAbility({ itemId: item.id }, item.runeSlot); | |||
else { | |||
delete item.eq; | |||
obj.equipment.equip(item.id); | |||
obj.equipment.equip({ itemId: item.id }); | |||
} | |||
} else if (item.has('quickSlot')) { | |||
obj.equipment.setQuickSlot({ | |||
@@ -67,7 +67,7 @@ module.exports = async (cpnInv, itemId) => { | |||
if (item.recipe) { | |||
const didLearn = await learnRecipe(obj, item); | |||
if (didLearn) | |||
cpnInv.destroyItem(itemId, 1); | |||
cpnInv.destroyItem({ itemId }, 1); | |||
return; | |||
} | |||
@@ -107,7 +107,7 @@ module.exports = async (cpnInv, itemId) => { | |||
} | |||
} | |||
cpnInv.destroyItem(itemId, 1); | |||
cpnInv.destroyItem({ itemId }, 1); | |||
if (item.has('quickSlot')) | |||
cpnInv.obj.equipment.replaceQuickSlot(item); | |||
} | |||
@@ -260,7 +260,13 @@ module.exports = { | |||
move: function (msg) { | |||
atlas.queueAction(this.obj, { | |||
action: 'move', | |||
priority: msg.priority, | |||
data: msg.data | |||
}); | |||
}, | |||
castSpell: function (msg) { | |||
atlas.queueAction(this.obj, { | |||
action: 'spell', | |||
data: msg.data | |||
}); | |||
}, | |||
@@ -274,5 +280,13 @@ module.exports = { | |||
msg.data.data.callbackId = atlas.registerCallback(msg.callback); | |||
atlas.performAction(this.obj, msg.data); | |||
}, | |||
clearQueue: function (msg) { | |||
const spellbook = this.obj.spellbook; | |||
if (spellbook.isCasting()) | |||
spellbook.stopCasting(); | |||
else | |||
this.obj.clearQueue(); | |||
} | |||
}; |
@@ -35,8 +35,8 @@ module.exports = { | |||
return true; | |||
}, | |||
complete: function (id) { | |||
let quest = this.quests.find(q => q.id === id); | |||
complete: function ({ questId }) { | |||
let quest = this.quests.find(q => q.id === questId); | |||
if ((!quest) || (!quest.isReady)) | |||
return; | |||
@@ -222,7 +222,7 @@ module.exports = { | |||
return; | |||
} | |||
let target = cons.players.find(c => c.id === msg.data); | |||
let target = cons.players.find(c => c.id === msg.data.id); | |||
if (!target) | |||
return; | |||
@@ -101,13 +101,13 @@ module.exports = { | |||
return true; | |||
}, | |||
withdraw: function (id) { | |||
withdraw: function ({ itemId }) { | |||
const { active, items, obj } = this; | |||
if (!active) | |||
return; | |||
let item = items.find(i => i.id === id); | |||
let item = items.find(i => i.id === itemId); | |||
if (!item) | |||
return; | |||
else if (!obj.inventory.hasSpace(item)) { | |||
@@ -122,7 +122,7 @@ module.exports = { | |||
obj.inventory.getItem(item); | |||
items.spliceWhere(i => i === item); | |||
obj.instance.syncer.queue('onRemoveStashItems', [id], [obj.serverId]); | |||
obj.instance.syncer.queue('onRemoveStashItems', [itemId], [obj.serverId]); | |||
}, | |||
setActive: function (active) { | |||
@@ -135,9 +135,11 @@ module.exports = { | |||
id: 'openStash', | |||
key: 'u', | |||
action: { | |||
targetId: obj.id, | |||
cpn: 'stash', | |||
method: 'open' | |||
method: 'open', | |||
data: { | |||
targetId: obj.id | |||
} | |||
} | |||
}); | |||
@@ -240,7 +240,7 @@ module.exports = { | |||
if (item.worth.currency) { | |||
let currencyItem = this.obj.inventory.items.find(i => (i.name === item.worth.currency)); | |||
this.obj.inventory.destroyItem(currencyItem.id, item.worth.amount, true); | |||
this.obj.inventory.destroyItem({ itemId: currencyItem.id }, item.worth.amount, true); | |||
} else { | |||
targetTrade.gold += ~~(item.worth * markup); | |||
this.gold -= ~~(item.worth * markup); | |||
@@ -270,7 +270,7 @@ module.exports = { | |||
return; | |||
const oldQuantity = item.quantity; | |||
this.obj.inventory.destroyItem(msg.itemId); | |||
this.obj.inventory.destroyItem({ itemId: msg.itemId }); | |||
if (oldQuantity) | |||
item.quantity = oldQuantity; | |||
@@ -42,9 +42,11 @@ module.exports = { | |||
obj.syncer.setArray(true, 'serverActions', 'removeActions', { | |||
key: 'u', | |||
action: { | |||
targetId: this.obj.id, | |||
cpn: 'wardrobe', | |||
method: 'access' | |||
method: 'access', | |||
data: { | |||
targetId: this.obj.id | |||
} | |||
} | |||
}); | |||
@@ -64,9 +66,11 @@ module.exports = { | |||
key: 'u', | |||
name: 'open wardrobe', | |||
action: { | |||
targetId: this.obj.id, | |||
cpn: 'wardrobe', | |||
method: 'open' | |||
method: 'open', | |||
data: { | |||
targetId: this.obj.id | |||
} | |||
} | |||
}); | |||
@@ -47,9 +47,11 @@ module.exports = { | |||
obj.syncer.setArray(true, 'serverActions', 'removeActions', { | |||
key: 'u', | |||
action: { | |||
targetId: this.obj.id, | |||
cpn: 'workbench', | |||
method: 'access' | |||
method: 'open', | |||
data: { | |||
targetId: this.obj.id | |||
} | |||
} | |||
}); | |||
@@ -66,9 +68,11 @@ module.exports = { | |||
key: 'u', | |||
name: 'access workbench', | |||
action: { | |||
targetId: this.obj.id, | |||
cpn: 'workbench', | |||
method: 'open' | |||
method: 'open', | |||
data: { | |||
targetId: this.obj.id | |||
} | |||
} | |||
}); | |||
@@ -33,7 +33,7 @@ module.exports = (cpnWorkbench, msg) => { | |||
if (!canCraft) | |||
return null; | |||
materials.forEach(m => inventory.destroyItem(m.id, m.needQuantity)); | |||
materials.forEach(m => inventory.destroyItem({ itemId: m.id }, m.needQuantity)); | |||
let resultMsg = null; | |||
@@ -56,7 +56,7 @@ module.exports = (cpnWorkbench, msg) => { | |||
applyItemStats(crafter, p, true); | |||
if (p.slot !== oldSlots[i]) | |||
equipment.unequip(p.id); | |||
equipment.unequip({ itemId: p.id }); | |||
spellbook.calcDps(); | |||
@@ -231,7 +231,7 @@ module.exports = { | |||
return; | |||
obj.reputation.getReputation('akarei', (crystals.quantity || 1) * 15); | |||
inventory.destroyItem(crystals.id); | |||
inventory.destroyItem({ itemId: crystals.id }); | |||
} | |||
} | |||
} | |||
@@ -76,7 +76,7 @@ module.exports = { | |||
let inventory = this.obj.inventory; | |||
let item = inventory.items.find((i => i.name === this.item.name).bind(this)); | |||
if (item) | |||
this.obj.inventory.destroyItem(item.id, this.need); | |||
this.obj.inventory.destroyItem({ itemId: item.id }, this.need); | |||
}, | |||
events: { | |||
@@ -176,22 +176,16 @@ module.exports = { | |||
}); | |||
}, | |||
queue: function (action) { | |||
if (action.action === 'clearQueue') { | |||
let spellbook = this.spellbook; | |||
if (spellbook.isCasting()) | |||
spellbook.stopCasting(); | |||
else | |||
this.clearQueue(); | |||
return; | |||
} else if (action.action === 'spell') { | |||
queue: function (msg) { | |||
const { action, auto, data: { priority } } = msg; | |||
if (action === 'spell') { | |||
let spellbook = this.spellbook; | |||
const isCasting = spellbook.isCasting(); | |||
if (isCasting && (!action.priority || !spellbook.canCast(action))) { | |||
if (action.auto) | |||
spellbook.queueAuto(action); | |||
if (isCasting && (!priority || !spellbook.canCast(msg))) { | |||
if (auto) | |||
spellbook.queueAuto(msg); | |||
return; | |||
} | |||
@@ -200,15 +194,15 @@ module.exports = { | |||
spellbook.stopCasting(); | |||
this.actionQueue.spliceWhere(a => a.priority); | |||
this.actionQueue.splice(0, 0, action); | |||
this.actionQueue.splice(0, 0, msg); | |||
} else { | |||
if (action.priority) { | |||
if (priority) { | |||
this.spellbook.stopCasting(); | |||
this.actionQueue.splice(0, 0, action); | |||
this.actionQueue.splice(0, 0, msg); | |||
return; | |||
} | |||
this.actionQueue.push(action); | |||
this.actionQueue.push(msg); | |||
} | |||
}, | |||
@@ -270,7 +264,7 @@ module.exports = { | |||
if (!success) | |||
this.clearQueue(); | |||
} else if (q.action === 'spell') { | |||
let success = this.spellbook.cast(q); | |||
let success = this.spellbook.cast(q.data); | |||
if (!success) | |||
this.performQueue(); | |||
} | |||
@@ -1,4 +1,4 @@ | |||
const { routerConfig: { allowed, allowTargetId, secondaryAllowed, globalAllowed, secondaryAllowTargetId } } = require('./routerConfig'); | |||
const { routerConfig: { signatures, allowed, allowTargetId, secondaryAllowed, globalAllowed, secondaryAllowTargetId } } = require('./routerConfig'); | |||
module.exports = { | |||
allowedCpn: function (msg) { | |||
@@ -41,5 +41,120 @@ module.exports = { | |||
const result = globalAllowed[threadModule] && globalAllowed[threadModule].includes(method); | |||
return result; | |||
}, | |||
keysCorrect: function (obj, keys) { | |||
const foundIncorrect = keys.some(({ key, dataType, optional, spec }) => { | |||
if (!obj.hasOwnProperty(key)) { | |||
if (optional) | |||
return false; | |||
return true; | |||
} | |||
const value = obj[key]; | |||
if (dataType === 'string' || dataType === 'boolean') | |||
return dataType !== typeof(value); | |||
else if (dataType === 'numberOrString') | |||
return (typeof(value) !== 'string' && !Number.isFinite(value)); | |||
else if (dataType === 'integerOrString') | |||
return (typeof(value) !== 'string' && !Number.isInteger(value)); | |||
else if (dataType === 'integer') | |||
return !Number.isInteger(value); | |||
else if (dataType === 'integerNullOrPosition') | |||
return !Number.isInteger(value) && value !== null && (typeof(value) !== 'object' && value.hasOwnProperty('x') && value.hasOwnProperty('y')); | |||
else if (dataType === 'arrayOfStrings') | |||
return (!Array.isArray(value) || value.some(v => typeof(v) !== 'string')); | |||
else if (dataType === 'arrayOfIntegers') | |||
return (!Array.isArray(value) || value.some(v => !Number.isInteger(v))); | |||
else if (dataType === 'arrayOfObjects') { | |||
if (!Array.isArray(value) || value.some(v => v === null || typeof(v) !== 'object')) | |||
return true; | |||
const foundIncorrectObject = value.some(v => !this.keysCorrect(v, spec)); | |||
if (foundIncorrectObject) | |||
return true; | |||
return foundIncorrectObject; | |||
} else if (dataType === 'object') { | |||
if (typeof(value) !== 'object' || value === null) | |||
return true; | |||
if (!spec) | |||
return false; | |||
const foundIncorrectObject = !this.keysCorrect(value, spec); | |||
if (foundIncorrectObject) | |||
return true; | |||
return foundIncorrectObject; | |||
} else if (dataType === 'stringOrNull') | |||
return (typeof(value) !== 'string' && value !== null); | |||
else if (dataType === 'mixed') | |||
return false; | |||
return true; | |||
}); | |||
if (foundIncorrect) | |||
return false; | |||
const foundInvalid = Object.keys(obj).some(o => !keys.some(k => k.key === o)); | |||
return !foundInvalid; | |||
}, | |||
signatureCorrect: function (msg, config) { | |||
if (config.callback !== 'deferred') { | |||
if (config.callback === true && !msg.callback) | |||
return false; | |||
else if (config.callback === false && !!msg.callback) | |||
return false; | |||
} | |||
const expectKeys = config.data; | |||
const keysCorrect = this.keysCorrect(msg.data, expectKeys); | |||
return keysCorrect; | |||
}, | |||
isMsgValid: function (msg) { | |||
let signature; | |||
if (msg.module) { | |||
if (msg.threadModule !== undefined || msg.cpn !== undefined || msg.data.cpn !== undefined) | |||
return false; | |||
signature = signatures.global[msg.module]?.[msg.method]; | |||
} else if (msg.threadModule) { | |||
if (msg.module !== undefined || msg.cpn !== undefined || msg.data.cpn !== undefined) | |||
return false; | |||
signature = signatures.threadGlobal[msg.threadModule]?.[msg.method]; | |||
} else if (msg.cpn) { | |||
if (msg.module !== undefined || msg.threadModule !== undefined) | |||
return false; | |||
signature = signatures.cpnMethods[msg.cpn]?.[msg.method]; | |||
} | |||
if (!signature) | |||
return false; | |||
const result = this.signatureCorrect(msg, signature); | |||
if (!result || msg.cpn !== 'player' || msg.method !== 'performAction') | |||
return result; | |||
const signatureThreadMsg = signatures.threadCpnMethods[msg.data.cpn]?.[msg.data.method]; | |||
if (!signatureThreadMsg) | |||
return false; | |||
const resultSub = this.signatureCorrect(msg.data, signatureThreadMsg); | |||
return resultSub; | |||
} | |||
}; |
@@ -1,50 +1,636 @@ | |||
let events = require('../misc/events'); | |||
const routerConfig = { | |||
//Component methods that can be called on the main thread | |||
allowed: { | |||
player: ['performAction', 'queueAction', 'move'], | |||
auth: ['login', 'register', 'play', 'getCharacterList', 'getCharacter', 'deleteCharacter', 'getSkinList', 'createCharacter', 'getCustomChannels'], | |||
social: ['chat', 'getInvite', 'acceptInvite', 'declineInvite', 'removeFromParty', 'leaveParty'] | |||
}, | |||
//Component methods that can be called with a targetId | |||
// which means that we're not calling our own component method but instead, another object's component method | |||
allowTargetId: { | |||
social: ['getInvite', 'acceptInvite', 'declineInvite'] | |||
}, | |||
//Component methods that can be called on map threads through `performAction` or `queueAction` methods | |||
secondaryAllowed: { | |||
dialogue: ['talk'], | |||
gatherer: ['gather'], | |||
quests: ['complete'], | |||
inventory: ['combineStacks', 'splitStack', 'useItem', 'moveItem', 'learnAbility', 'unlearnAbility', 'dropItem', 'destroyItem', 'salvageItem', 'stashItem', 'sortInventory'], | |||
equipment: ['equip', 'unequip', 'setQuickSlot', 'useQuickSlot', 'inspect'], | |||
stash: ['withdraw', 'open'], | |||
trade: ['buySell'], | |||
door: ['lock', 'unlock'], | |||
wardrobe: ['open', 'apply'], | |||
stats: ['respawn'], | |||
passives: ['tickNode', 'untickNode'], | |||
workbench: ['open', 'craft', 'getRecipe'] | |||
}, | |||
//Component methods that can be called on map threads with a targetId | |||
// which means that we're not calling our own component method but instead, another object's component method | |||
// These are called through `performAction` or `queueAction` methods | |||
secondaryAllowTargetId: { | |||
door: ['lock', 'unlock'], | |||
gatherer: ['gather'], | |||
equipment: ['inspect'], | |||
stash: ['open'], | |||
wardrobe: ['open', 'apply'], | |||
workbench: ['open', 'craft', 'getRecipe'] | |||
}, | |||
//Global module methods that can be called on the main thread or map threads | |||
globalAllowed: { | |||
clientConfig: ['getClientConfig'], | |||
leaderboard: ['requestList'], | |||
cons: ['unzone'], | |||
rezoneManager: ['clientAck'], | |||
instancer: ['clientAck'] | |||
signatures: { | |||
global: { | |||
clientConfig: { | |||
getClientConfig: { | |||
callback: true, | |||
data: [] | |||
} | |||
}, | |||
leaderboard: { | |||
requestList: { | |||
callback: true, | |||
data: [ | |||
{ | |||
key: 'offset', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'prophecies', | |||
dataType: 'arrayOfStrings' | |||
} | |||
] | |||
} | |||
}, | |||
cons: { | |||
unzone: { | |||
callback: true, | |||
data: [] | |||
} | |||
} | |||
}, | |||
threadGlobal: { | |||
instancer: { | |||
clientAck: { | |||
callback: false, | |||
data: [] | |||
} | |||
}, | |||
rezoneManager: { | |||
clientAck: { | |||
callback: false, | |||
data: [] | |||
} | |||
} | |||
}, | |||
cpnMethods: { | |||
auth: { | |||
login: { | |||
callback: true, | |||
data: [ | |||
{ | |||
key: 'username', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'password', | |||
dataType: 'string' | |||
} | |||
] | |||
}, | |||
register: { | |||
callback: true, | |||
data: [ | |||
{ | |||
key: 'username', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'password', | |||
dataType: 'string' | |||
} | |||
] | |||
}, | |||
deleteCharacter: { | |||
callback: true, | |||
data: [ | |||
{ | |||
key: 'name', | |||
dataType: 'string' | |||
} | |||
] | |||
}, | |||
getSkinList: { | |||
callback: true, | |||
data: [] | |||
}, | |||
createCharacter: { | |||
callback: true, | |||
data: [ | |||
{ | |||
key: 'name', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'class', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'skinId', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'prophecies', | |||
dataType: 'arrayOfStrings' | |||
} | |||
] | |||
}, | |||
getCharacterList: { | |||
callback: true, | |||
data: [] | |||
}, | |||
getCharacter: { | |||
callback: true, | |||
data: [ | |||
{ | |||
key: 'name', | |||
dataType: 'string' | |||
} | |||
] | |||
}, | |||
play: { | |||
callback: true, | |||
data: [ | |||
{ | |||
key: 'name', | |||
dataType: 'string' | |||
} | |||
] | |||
} | |||
}, | |||
player: { | |||
move: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'x', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'y', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'priority', | |||
dataType: 'boolean', | |||
optional: true | |||
} | |||
] | |||
}, | |||
castSpell: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'priority', | |||
dataType: 'boolean' | |||
}, | |||
{ | |||
key: 'target', | |||
dataType: 'integerNullOrPosition' | |||
}, | |||
{ | |||
key: 'spell', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'self', | |||
dataType: 'boolean', | |||
optional: true | |||
} | |||
] | |||
}, | |||
performAction: { | |||
callback: 'deferred', | |||
data: [ | |||
{ | |||
key: 'cpn', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'method', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'data', | |||
dataType: 'object' | |||
} | |||
] | |||
} | |||
}, | |||
social: { | |||
chat: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'message', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'type', | |||
dataType: 'string', | |||
optional: true | |||
}, | |||
{ | |||
key: 'subType', | |||
dataType: 'stringOrNull', | |||
optional: true | |||
}, | |||
{ | |||
key: 'item', | |||
dataType: 'object', | |||
optional: true | |||
} | |||
] | |||
}, | |||
getInvite: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
acceptInvite: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
declineInvite: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
removeFromParty: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'id', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
leaveParty: { | |||
callback: false, | |||
data: [] | |||
} | |||
} | |||
}, | |||
threadCpnMethods: { | |||
dialogue: { | |||
talk: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'target', | |||
dataType: 'integerOrString' | |||
}, | |||
{ | |||
key: 'state', | |||
dataType: 'numberOrString' | |||
} | |||
] | |||
} | |||
}, | |||
gatherer: { | |||
gather: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
} | |||
}, | |||
quests: { | |||
complete: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'questId', | |||
dataType: 'integer' | |||
} | |||
] | |||
} | |||
}, | |||
player: { | |||
clearQueue: { | |||
callback: false, | |||
data: [] | |||
} | |||
}, | |||
inventory: { | |||
combineStacks: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'fromId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'toId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
splitStack: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'stackSize', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
useItem: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
moveItem: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'moveMsgs', | |||
dataType: 'arrayOfObjects', | |||
spec: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'targetPos', | |||
dataType: 'integer' | |||
} | |||
] | |||
} | |||
] | |||
}, | |||
learnAbility: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'slot', | |||
dataType: 'integer', | |||
optional: true | |||
} | |||
] | |||
}, | |||
unlearnAbility: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
dropItem: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
destroyItem: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
salvageItem: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
stashItem: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
sortInventory: { | |||
callback: false, | |||
data: [] | |||
} | |||
}, | |||
equipment: { | |||
equip: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'slot', | |||
dataType: 'string', | |||
optional: true | |||
} | |||
] | |||
}, | |||
unequip: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'slot', | |||
dataType: 'string', | |||
optional: true | |||
} | |||
] | |||
}, | |||
setQuickSlot: { | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'slot', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
useQuickSlot: { | |||
data: [ | |||
{ | |||
key: 'slot', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
inspect: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'playerId', | |||
dataType: 'integer' | |||
} | |||
] | |||
} | |||
}, | |||
stash: { | |||
withdraw: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
open: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
} | |||
}, | |||
trade: { | |||
buySell: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'itemId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'action', | |||
dataType: 'string' | |||
} | |||
] | |||
} | |||
}, | |||
door: { | |||
lock: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
unlock: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
} | |||
}, | |||
wardrobe: { | |||
open: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
apply: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'skinId', | |||
dataType: 'string' | |||
} | |||
] | |||
} | |||
}, | |||
stats: { | |||
respawn: { | |||
callback: false, | |||
data: [] | |||
} | |||
}, | |||
passives: { | |||
tickNode: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'nodeId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
untickNode: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'nodeId', | |||
dataType: 'integer', | |||
optional: true | |||
} | |||
] | |||
} | |||
}, | |||
workbench: { | |||
open: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
} | |||
] | |||
}, | |||
craft: { | |||
callback: false, | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'name', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'pickedItemIds', | |||
dataType: 'arrayOfIntegers' | |||
} | |||
] | |||
}, | |||
getRecipe: { | |||
data: [ | |||
{ | |||
key: 'targetId', | |||
dataType: 'integer' | |||
}, | |||
{ | |||
key: 'name', | |||
dataType: 'string' | |||
}, | |||
{ | |||
key: 'pickedItemIds', | |||
dataType: 'arrayOfIntegers', | |||
optional: true | |||
} | |||
] | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
@@ -52,6 +638,12 @@ module.exports = { | |||
routerConfig, | |||
init: function () { | |||
events.emit('onBeforeGetRouterConfig', routerConfig); | |||
routerConfig.allowed = {}; | |||
routerConfig.allowTargetId = {}; | |||
routerConfig.secondaryAllowed = {}; | |||
routerConfig.secondaryAllowTargetId = {}; | |||
routerConfig.globalAllowed = {}; | |||
events.emit('onBeforeGetRouterSignatureConfig', routerConfig); | |||
} | |||
}; |
@@ -16,26 +16,14 @@ const onRequest = (socket, msg, callback) => { | |||
if (!msg.data) | |||
msg.data = {}; | |||
if (msg.cpn) { | |||
if (!router.allowedCpn(msg)) | |||
return; | |||
delete msg.threadModule; | |||
delete msg.module; | |||
if (!router.isMsgValid(msg)) | |||
return; | |||
if (msg.cpn) | |||
cons.route(socket, msg); | |||
} else if (msg.threadModule) { | |||
if (!router.allowedGlobalCall(msg.threadModule, msg.method)) | |||
return; | |||
delete msg.cpn; | |||
delete msg.module; | |||
else if (msg.threadModule) | |||
cons.route(socket, msg); | |||
} else { | |||
if (!router.allowedGlobal(msg)) | |||
return; | |||
else { | |||
const source = cons.players.find(p => p.socket.id === socket.id); | |||
msg.socket = socket; | |||
@@ -285,7 +285,7 @@ module.exports = { | |||
performAction: function (msg) { | |||
let obj = null; | |||
let targetId = msg.action.targetId; | |||
let targetId = msg.action.data.targetId; | |||
if (!targetId) | |||
obj = objects.find(o => o.serverId === msg.id); | |||
else { | |||