@@ -16,6 +16,7 @@ define([ | |||||
if (blueprint.destroyItems) { | if (blueprint.destroyItems) { | ||||
rerender = true; | rerender = true; | ||||
this.items.spliceWhere(i => blueprint.destroyItems.includes(i.id)); | |||||
events.emit('onDestroyItems', blueprint.destroyItems, this.items); | events.emit('onDestroyItems', blueprint.destroyItems, this.items); | ||||
} | } | ||||
@@ -22,8 +22,6 @@ define([ | |||||
centered: true, | centered: true, | ||||
items: [], | |||||
dragItem: null, | dragItem: null, | ||||
dragEl: null, | dragEl: null, | ||||
hoverCell: null, | hoverCell: null, | ||||
@@ -65,7 +63,7 @@ define([ | |||||
let container = this.el.find('.grid') | let container = this.el.find('.grid') | ||||
.empty(); | .empty(); | ||||
let items = this.items | |||||
let items = window.player.inventory.items | |||||
.filter(function (item) { | .filter(function (item) { | ||||
return !item.eq; | return !item.eq; | ||||
}); | }); | ||||
@@ -184,7 +182,7 @@ define([ | |||||
pos: this.dragItem.index() | pos: this.dragItem.index() | ||||
}]; | }]; | ||||
this.items.find(function (i) { | |||||
window.player.inventory.items.find(function (i) { | |||||
return (i.id === this.dragItem.data('item').id); | return (i.id === this.dragItem.data('item').id); | ||||
}, this).pos = this.dragItem.index(); | }, this).pos = this.dragItem.index(); | ||||
@@ -196,7 +194,7 @@ define([ | |||||
pos: this.hoverCell.index() | pos: this.hoverCell.index() | ||||
}); | }); | ||||
this.items.find(function (i) { | |||||
window.player.inventory.items.find(function (i) { | |||||
return (i.id === hoverCellItem.id); | return (i.id === hoverCellItem.id); | ||||
}, this).pos = this.hoverCell.index(); | }, this).pos = this.hoverCell.index(); | ||||
} else { | } else { | ||||
@@ -264,11 +262,6 @@ define([ | |||||
text: 'destroy', | text: 'destroy', | ||||
callback: this.performItemAction.bind(this, item, 'destroyItem') | callback: this.performItemAction.bind(this, item, 'destroyItem') | ||||
}, | }, | ||||
salvage: { | |||||
text: 'salvage', | |||||
callback: this.performItemAction.bind(this, item, 'salvageItem'), | |||||
hotkey: 'f' | |||||
}, | |||||
stash: { | stash: { | ||||
text: 'stash', | text: 'stash', | ||||
callback: this.performItemAction.bind(this, item, 'stashItem') | callback: this.performItemAction.bind(this, item, 'stashItem') | ||||
@@ -341,9 +334,6 @@ define([ | |||||
if (!item.noDrop) | if (!item.noDrop) | ||||
ctxConfig.push(menuItems.drop); | ctxConfig.push(menuItems.drop); | ||||
if ((!item.material) && (!item.noSalvage)) | |||||
ctxConfig.push(menuItems.salvage); | |||||
} | } | ||||
} | } | ||||
@@ -477,19 +467,15 @@ define([ | |||||
}, | }, | ||||
onGetItems: function (items, rerender) { | onGetItems: function (items, rerender) { | ||||
this.items = items; | |||||
if ((this.shown) && (rerender)) | |||||
if (this.shown && rerender) | |||||
this.build(); | this.build(); | ||||
}, | }, | ||||
onDestroyItems: function (itemIds) { | onDestroyItems: function (itemIds) { | ||||
itemIds.forEach(function (id) { | |||||
let item = this.items.find(i => i.id === id); | |||||
itemIds.forEach(id => { | |||||
const item = window.player.inventory.items.find(i => i.id === id); | |||||
if (item === this.hoverItem) | if (item === this.hoverItem) | ||||
this.hideTooltip(); | this.hideTooltip(); | ||||
this.items.spliceWhere(i => i.id === id); | |||||
}, this); | |||||
}); | |||||
if (this.shown) | if (this.shown) | ||||
this.build(); | this.build(); | ||||
@@ -1,6 +1,7 @@ | |||||
const scheduler = require('../../misc/scheduler'); | const scheduler = require('../../misc/scheduler'); | ||||
const rewardGenerator = require('../../misc/rewardGenerator'); | const rewardGenerator = require('../../misc/rewardGenerator'); | ||||
const mail = require('../../mail/mail'); | const mail = require('../../mail/mail'); | ||||
const events = require('../../misc/events'); | |||||
const calculateDaysSkipped = (oldTime, newTime) => { | const calculateDaysSkipped = (oldTime, newTime) => { | ||||
let daysSkipped = 1; | let daysSkipped = 1; | ||||
@@ -63,8 +64,11 @@ module.exports = async (cpnAuth, data, character, cbDone) => { | |||||
accountInfo.loginStreak = loginStreak; | accountInfo.loginStreak = loginStreak; | ||||
const itemCount = 1 + ~~(loginStreak / 2); | const itemCount = 1 + ~~(loginStreak / 2); | ||||
const rewards = rewardGenerator(itemCount); | |||||
if (!rewards) { | |||||
const rewardConfig = []; | |||||
events.emit('onBeforeGenerateLoginRewards', rewardConfig); | |||||
const rewards = rewardGenerator(itemCount, rewardConfig); | |||||
if (!rewards.length) { | |||||
cbDone(); | cbDone(); | ||||
return; | return; | ||||
} | } | ||||
@@ -1,9 +1,9 @@ | |||||
let roles = require('../../config/roles'); | let roles = require('../../config/roles'); | ||||
let generator = require('../../items/generator'); | let generator = require('../../items/generator'); | ||||
let configSlots = require('../../items/config/slots'); | let configSlots = require('../../items/config/slots'); | ||||
let configMaterials = require('../../items/config/materials'); | |||||
let factions = require('../../config/factions'); | let factions = require('../../config/factions'); | ||||
let connections = require('../../security/connections'); | let connections = require('../../security/connections'); | ||||
const events = require('../../misc/events'); | |||||
const ban = require('../social/ban'); | const ban = require('../social/ban'); | ||||
const rezone = require('../social/rezone'); | const rezone = require('../social/rezone'); | ||||
@@ -45,7 +45,6 @@ let commandRoles = { | |||||
getXp: 10, | getXp: 10, | ||||
setPassword: 10, | setPassword: 10, | ||||
giveSkin: 10, | giveSkin: 10, | ||||
getMaterials: 10, | |||||
rezone: 10, | rezone: 10, | ||||
startEvent: 10, | startEvent: 10, | ||||
stopEvent: 10, | stopEvent: 10, | ||||
@@ -86,6 +85,8 @@ const contextActions = [ | |||||
} | } | ||||
]; | ]; | ||||
const commandActions = {}; | |||||
module.exports = { | module.exports = { | ||||
customChannels: [], | customChannels: [], | ||||
roleLevel: null, | roleLevel: null, | ||||
@@ -96,6 +97,13 @@ module.exports = { | |||||
.filter((c, i) => (this.customChannels.indexOf(c) === i)); | .filter((c, i) => (this.customChannels.indexOf(c) === i)); | ||||
} | } | ||||
events.emit('onBeforeGetCommandRoles', commandRoles, commandActions); | |||||
Object.entries(commandActions).forEach(a => { | |||||
const [ actionName, actionHandler ] = a; | |||||
this[actionName] = actionHandler.bind(this); | |||||
}); | |||||
this.roleLevel = roles.getRoleLevel(this.obj); | this.roleLevel = roles.getRoleLevel(this.obj); | ||||
this.calculateActions(); | this.calculateActions(); | ||||
}, | }, | ||||
@@ -694,22 +702,6 @@ module.exports = { | |||||
}); | }); | ||||
}, | }, | ||||
getMaterials: function (config) { | |||||
if (typeof(config) === 'object') | |||||
config = 100; | |||||
let inventory = this.obj.inventory; | |||||
Object.entries(configMaterials).forEach(([material, blueprint]) => { | |||||
inventory.getItem({ | |||||
name: material, | |||||
quantity: config, | |||||
material: true, | |||||
...blueprint | |||||
}); | |||||
}); | |||||
}, | |||||
broadcast: function (config, msg) { | broadcast: function (config, msg) { | ||||
if (typeof(msg) === 'object') | if (typeof(msg) === 'object') | ||||
msg = Object.keys(msg).join(' '); | msg = Object.keys(msg).join(' '); | ||||
@@ -1,334 +0,0 @@ | |||||
let qualityGenerator = require('../items/generators/quality'); | |||||
module.exports = { | |||||
type: 'gatherer', | |||||
nodes: [], | |||||
gathering: null, | |||||
gatheringTtl: 0, | |||||
gatheringTtlMax: 7, | |||||
defaultTtlMax: 7, | |||||
simplify: function () { | |||||
return { | |||||
type: 'gatherer' | |||||
}; | |||||
}, | |||||
gather: function () { | |||||
if (this.gathering) | |||||
return; | |||||
let nodes = this.nodes; | |||||
if (nodes.length === 0) | |||||
return; | |||||
const { obj: { equipment, stats } } = this; | |||||
let firstNode = nodes[0]; | |||||
if (!this.hasSpace(firstNode)) { | |||||
this.sendAnnouncement('Your bags are too full to gather any more resources.'); | |||||
return; | |||||
} | |||||
this.gathering = firstNode; | |||||
let ttlMax = firstNode.resourceNode.ttl || this.defaultTtlMax; | |||||
if (firstNode.resourceNode.nodeType === 'fish') { | |||||
if (equipment.isSlotEmpty('tool')) { | |||||
this.sendAnnouncement('You need a fishing rod to fish'); | |||||
this.gathering = null; | |||||
return; | |||||
} | |||||
let statCatchSpeed = Math.min(150, stats.values.catchSpeed); | |||||
ttlMax *= (1 - (statCatchSpeed / 200)); | |||||
} | |||||
this.gatheringTtlMax = ttlMax; | |||||
this.gatheringTtl = this.gatheringTtlMax; | |||||
}, | |||||
update: function () { | |||||
let gathering = this.gathering; | |||||
if (!gathering) | |||||
return; | |||||
let isFish = (gathering.resourceNode.nodeType === 'fish'); | |||||
let hasSpace = this.hasSpace(this.gathering); | |||||
if (gathering.destroyed || !hasSpace) { | |||||
this.gathering = null; | |||||
this.gatheringTtl = 0; | |||||
this.obj.syncer.set(false, 'gatherer', 'progress', 100); | |||||
this.obj.syncer.set(true, 'gatherer', 'progress', 100); | |||||
if (isFish) | |||||
this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing'); | |||||
if (!hasSpace) | |||||
this.sendAnnouncement('Your bags are too full to gather any more resources.'); | |||||
return; | |||||
} | |||||
if (this.gatheringTtl > 0) { | |||||
if ((this.gatheringTtl === this.gatheringTtlMax) && (gathering.width)) { | |||||
['x', 'y', 'width', 'height'].forEach(function (p) { | |||||
this.obj.syncer.set(false, 'gatherer', p, gathering[p]); | |||||
}, this); | |||||
} | |||||
this.gatheringTtl--; | |||||
let progress = 100 - ~~((this.gatheringTtl / this.gatheringTtlMax) * 100); | |||||
this.obj.syncer.set(true, 'gatherer', 'progress', progress); | |||||
if (isFish) | |||||
this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing'); | |||||
return; | |||||
} | |||||
this.completeGathering(gathering, isFish); | |||||
}, | |||||
completeGathering: function (gathering, isFish) { | |||||
let resourceNode = gathering.resourceNode; | |||||
let gatherResult = extend({ | |||||
obj: gathering | |||||
}, { | |||||
nodeType: resourceNode.nodeType, | |||||
blueprint: resourceNode.blueprint, | |||||
xp: resourceNode.xp, | |||||
items: gathering.inventory.items | |||||
}); | |||||
this.obj.instance.eventEmitter.emitNoSticky('beforeGatherResource', gatherResult, this.obj); | |||||
this.obj.fireEvent('beforeGatherResource', gatherResult, this.obj); | |||||
this.obj.syncer.set(false, 'gatherer', 'progress', 100); | |||||
if (isFish) { | |||||
let catchChance = 40 + this.obj.stats.values.catchChance; | |||||
if (~~(Math.random() * 100) >= catchChance) { | |||||
this.sendAnnouncement('The fish got away'); | |||||
this.gathering = null; | |||||
return; | |||||
} | |||||
gatherResult.items.forEach(function (g) { | |||||
if (g.slot) | |||||
return; | |||||
delete g.quantity; | |||||
qualityGenerator.generate(g, { | |||||
//100 x 2.86 = 2000 (chance for a common) | |||||
bonusMagicFind: this.obj.stats.values.fishRarity * 2.82 | |||||
}); | |||||
g.name = { | |||||
0: '', | |||||
1: 'Big ', | |||||
2: 'Giant ', | |||||
3: 'Trophy ', | |||||
4: 'Fabled ' | |||||
}[g.quality] + g.name; | |||||
let statFishWeight = 1 + (this.obj.stats.values.fishWeight / 100); | |||||
let weight = ~~((gatherResult.blueprint.baseWeight + g.quality + (Math.random() * statFishWeight)) * 100) / 100; | |||||
g.stats = { | |||||
weight: weight | |||||
}; | |||||
g.worth = ~~(weight * 10); | |||||
}, this); | |||||
} | |||||
if (isFish) { | |||||
let itemChance = 1 + this.obj.stats.values.fishItems; | |||||
if (~~(Math.random() * 500) < itemChance) { | |||||
gatherResult.items = [{ | |||||
name: 'Cerulean Pearl', | |||||
material: true, | |||||
quantity: 1, | |||||
quality: 3, | |||||
sprite: [11, 9] | |||||
}]; | |||||
} | |||||
} | |||||
let blueprint = gatherResult.blueprint; | |||||
gatherResult.items.forEach((item, i) => { | |||||
delete item.pos; | |||||
if (i === 0) { | |||||
if (blueprint.itemName) | |||||
item.name = blueprint.itemName; | |||||
if (blueprint.itemAmount) | |||||
item.quantity = ~~(Math.random() * blueprint.itemAmount[1]) + blueprint.itemAmount[0]; | |||||
} | |||||
this.obj.inventory.getItem(item, false, false, true); | |||||
if (item.material) | |||||
this.obj.fireEvent('afterGatherResource', gatherResult); | |||||
}); | |||||
if (!gatherResult.noChangeAmount) | |||||
resourceNode.gather(); | |||||
this.obj.stats.getXp(gatherResult.xp, this.obj, gatherResult.obj); | |||||
if (gathering.destroyed) { | |||||
if (isFish) | |||||
this.sendAnnouncement('The school has been depleted'); | |||||
this.nodes.spliceWhere(n => (n === gathering)); | |||||
this.updateServerActions(false); | |||||
} | |||||
this.gathering = null; | |||||
}, | |||||
hasSpace: function (node) { | |||||
// By default, the player is allowed to gather "nothing" | |||||
if (!node.inventory || !node.inventory.items) | |||||
return true; | |||||
return this.obj.inventory.hasSpaceList(node.inventory.items); | |||||
}, | |||||
enter: function (node) { | |||||
const { obj } = this; | |||||
let gatherResult = extend({ | |||||
nodeName: node.name | |||||
}); | |||||
obj.instance.eventEmitter.emitNoSticky('beforeEnterPool', gatherResult, obj); | |||||
let nodeType = node.resourceNode.nodeType; | |||||
if (nodeType === 'fish') { | |||||
if (!obj.equipment.eq.has('tool')) { | |||||
this.sendAnnouncement('You need a fishing rod to fish'); | |||||
return; | |||||
} | |||||
} | |||||
this.updateServerActions(true); | |||||
let action = null; | |||||
if (nodeType === 'fish') | |||||
action = 'fish for'; | |||||
else if (nodeType === 'herb') | |||||
action = 'gather the'; | |||||
const actionString = `${action} ${gatherResult.nodeName}`; | |||||
this.sendAnnouncement(`Press U to ${actionString}`); | |||||
this.nodes.spliceWhere(n => (n === node)); | |||||
this.nodes.push(node); | |||||
}, | |||||
exit: function (node) { | |||||
if (!this.nodes.includes(node)) | |||||
return; | |||||
this.updateServerActions(false); | |||||
this.nodes.spliceWhere(n => (n === node)); | |||||
}, | |||||
sendAnnouncement: function (msg) { | |||||
process.send({ | |||||
method: 'events', | |||||
data: { | |||||
onGetAnnouncement: [{ | |||||
obj: { | |||||
msg: msg | |||||
}, | |||||
to: [this.obj.serverId] | |||||
}] | |||||
} | |||||
}); | |||||
}, | |||||
updateServerActions: function (isAdd) { | |||||
const { obj } = this; | |||||
const action = isAdd ? 'addActions' : 'removeActions'; | |||||
obj.syncer.setArray(true, 'serverActions', action, { | |||||
key: 'u', | |||||
action: { | |||||
targetId: obj.id, | |||||
cpn: 'gatherer', | |||||
method: 'gather' | |||||
} | |||||
}); | |||||
}, | |||||
events: { | |||||
beforeRezone: function () { | |||||
this.events.beforeMove.call(this); | |||||
}, | |||||
beforeMove: function () { | |||||
if (!this.gathering) | |||||
return; | |||||
['x', 'y', 'width', 'height'].forEach(p => { | |||||
this.obj.syncer.delete(false, 'gatherer', p); | |||||
}); | |||||
this.obj.syncer.set(true, 'gatherer', 'progress', 100); | |||||
this.obj.syncer.set(false, 'gatherer', 'progress', 100); | |||||
if (this.gathering.resourceNode.nodeType === 'fish') | |||||
this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing'); | |||||
this.gathering = null; | |||||
}, | |||||
beforeCastSpell: function () { | |||||
this.events.beforeMove.call(this); | |||||
}, | |||||
beforeTakeDamage: function () { | |||||
this.events.beforeMove.call(this); | |||||
}, | |||||
afterEquipItem: function (item) { | |||||
let nodes = this.nodes; | |||||
let nLen = nodes.length; | |||||
for (let i = 0; i < nLen; i++) { | |||||
let node = nodes[i]; | |||||
if (item.slot !== 'tool') | |||||
continue; | |||||
if (node.resourceNode.nodeType === 'fish') { | |||||
if (!this.obj.equipment.eq.has('tool')) { | |||||
this.sendAnnouncement('You need a fishing rod to fish'); | |||||
if (this.gathering === node) { | |||||
if (this.gathering.resourceNode.nodeType === 'fish') | |||||
this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing'); | |||||
this.gathering = null; | |||||
this.obj.syncer.set(true, 'gatherer', 'progress', 100); | |||||
this.obj.syncer.set(false, 'gatherer', 'progress', 100); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
}, | |||||
afterUnequipItem: function (item) { | |||||
this.events.afterEquipItem.call(this, item); | |||||
} | |||||
} | |||||
}; |
@@ -1,5 +1,4 @@ | |||||
let generator = require('../items/generator'); | let generator = require('../items/generator'); | ||||
let salvager = require('../items/salvager'); | |||||
let classes = require('../config/spirits'); | let classes = require('../config/spirits'); | ||||
let mtx = require('../mtx/mtx'); | let mtx = require('../mtx/mtx'); | ||||
let factions = require('../config/factions'); | let factions = require('../config/factions'); | ||||
@@ -302,29 +301,6 @@ module.exports = { | |||||
this.destroyItem(id, null, true); | this.destroyItem(id, null, true); | ||||
}, | }, | ||||
salvageItem: function (id) { | |||||
let item = this.findItem(id); | |||||
if ((!item) || (item.material) || (item.quest) || (item.noSalvage) || (item.eq)) | |||||
return; | |||||
let messages = []; | |||||
let items = salvager.salvage(item); | |||||
this.destroyItem(id); | |||||
for (const material of items) { | |||||
this.getItem(material, true, false, false, true); | |||||
messages.push({ | |||||
className: 'q' + material.quality, | |||||
message: 'salvage (' + material.name + ' x' + material.quantity + ')' | |||||
}); | |||||
} | |||||
this.obj.social.notifySelfArray(messages); | |||||
}, | |||||
destroyItem: function (id, amount, force) { | destroyItem: function (id, amount, force) { | ||||
let item = this.findItem(id); | let item = this.findItem(id); | ||||
if (!item || (item.noDestroy && !force)) | if (!item || (item.noDestroy && !force)) | ||||
@@ -1,30 +0,0 @@ | |||||
module.exports = { | |||||
type: 'resourceNode', | |||||
collisionEnter: function (obj) { | |||||
if (!obj.player) | |||||
return; | |||||
obj.gatherer.enter(this.obj); | |||||
}, | |||||
collisionExit: function (obj) { | |||||
if (!obj.player) | |||||
return; | |||||
obj.gatherer.exit(this.obj); | |||||
}, | |||||
gather: function () { | |||||
this.quantity--; | |||||
if (this.quantity <= 0) | |||||
this.obj.destroyed = true; | |||||
}, | |||||
simplify: function () { | |||||
return { | |||||
type: 'resourceNode', | |||||
nodeType: this.nodeType | |||||
}; | |||||
} | |||||
}; |
@@ -2,6 +2,7 @@ let spellTemplate = require('../config/spells/spellTemplate'); | |||||
let animations = require('../config/animations'); | let animations = require('../config/animations'); | ||||
let playerSpells = require('../config/spells'); | let playerSpells = require('../config/spells'); | ||||
let playerSpellsConfig = require('../config/spellsConfig'); | let playerSpellsConfig = require('../config/spellsConfig'); | ||||
const { buildValues: buildRuneValues } = require('../items/generators/spellbook'); | |||||
module.exports = { | module.exports = { | ||||
type: 'spellbook', | type: 'spellbook', | ||||
@@ -170,24 +171,15 @@ module.exports = { | |||||
values: {} | values: {} | ||||
}, playerSpell, playerSpellConfig, runeSpell); | }, playerSpell, playerSpellConfig, runeSpell); | ||||
for (let r in builtSpell.random) { | |||||
let range = builtSpell.random[r]; | |||||
let roll = runeSpell.rolls[r] || 0; | |||||
runeSpell.rolls[r] = roll; | |||||
const runeValues = buildRuneValues(builtSpell); | |||||
let int = r.indexOf('i_') === 0; | |||||
Object.entries(runeValues).forEach(e => { | |||||
const [ property, value ] = e; | |||||
let val = range[0] + ((range[1] - range[0]) * roll); | |||||
if (int) { | |||||
val = ~~val; | |||||
r = r.replace('i_', ''); | |||||
} else | |||||
val = ~~(val * 100) / 100; | |||||
builtSpell[r] = val; | |||||
builtSpell.values[r] = val; | |||||
runeSpell.values[r] = val; | |||||
} | |||||
builtSpell[property] = value; | |||||
builtSpell.values[property] = value; | |||||
runeSpell.values[property] = value; | |||||
}); | |||||
if (runeSpell.properties) { | if (runeSpell.properties) { | ||||
for (let p in runeSpell.properties) | for (let p in runeSpell.properties) | ||||
@@ -1,6 +1,7 @@ | |||||
let generator = require('../items/generator'); | let generator = require('../items/generator'); | ||||
let statGenerator = require('../items/generators/stats'); | let statGenerator = require('../items/generators/stats'); | ||||
let skins = require('../config/skins'); | let skins = require('../config/skins'); | ||||
const events = require('../misc/events'); | |||||
const sendMessage = ({ instance, id, serverId }, color, message) => { | const sendMessage = ({ instance, id, serverId }, color, message) => { | ||||
instance.syncer.queue('onGetMessages', { | instance.syncer.queue('onGetMessages', { | ||||
@@ -263,24 +264,35 @@ module.exports = { | |||||
if (!target) | if (!target) | ||||
return; | return; | ||||
const { obj: { inventory, syncer } } = this; | |||||
let targetTrade = target.trade; | let targetTrade = target.trade; | ||||
const item = this.obj.inventory.findItem(msg.itemId); | |||||
const item = inventory.findItem(msg.itemId); | |||||
if (!item) | if (!item) | ||||
return; | return; | ||||
const oldQuantity = item.quantity; | const oldQuantity = item.quantity; | ||||
this.obj.inventory.destroyItem(msg.itemId); | |||||
inventory.destroyItem(msg.itemId); | |||||
if (oldQuantity) | if (oldQuantity) | ||||
item.quantity = oldQuantity; | item.quantity = oldQuantity; | ||||
let worth = ~~(item.worth * targetTrade.markup.buy); | |||||
const sellEventMsg = { | |||||
item, | |||||
worth: ~~(item.worth * targetTrade.markup.buy) | |||||
}; | |||||
events.emit('onBeforeSellItem', sellEventMsg); | |||||
const { worth } = sellEventMsg; | |||||
this.gold += worth; | |||||
if (typeof(worth) !== 'object') { | |||||
this.gold += worth; | |||||
syncer.set(true, 'trade', 'gold', this.gold); | |||||
} else | |||||
inventory.getItem(worth, false, false, false, true); | |||||
this.obj.syncer.set(true, 'trade', 'gold', this.gold); | |||||
this.obj.syncer.setArray(true, 'trade', 'removeItems', item.id); | |||||
syncer.setArray(true, 'trade', 'removeItems', item.id); | |||||
let buybackList = targetTrade.buybackList; | let buybackList = targetTrade.buybackList; | ||||
let name = this.obj.name; | let name = this.obj.name; | ||||
@@ -311,14 +323,16 @@ module.exports = { | |||||
this.target = target; | this.target = target; | ||||
let itemList = this.obj.inventory.items | |||||
.filter(i => ((i.worth > 0) && (!i.eq))); | |||||
itemList = extend([], itemList); | |||||
const itemList = extend([], this.obj.inventory.items.filter(i => i.worth && !i.eq)); | |||||
this.obj.syncer.set(true, 'trade', 'sellList', { | |||||
markup: target.trade.markup.buy, | |||||
items: itemList.map(i => this.obj.inventory.simplifyItem(i)) | |||||
}); | |||||
const sellEventMsg = { | |||||
items: itemList, | |||||
markup: target.trade.markup.buy | |||||
}; | |||||
events.emit('onBeforeGetSellList', sellEventMsg); | |||||
this.obj.syncer.set(true, 'trade', 'sellList', sellEventMsg); | |||||
}, | }, | ||||
startBuyback: function (msg) { | startBuyback: function (msg) { | ||||
@@ -7,6 +7,9 @@ module.exports = (crafter, recipe, { pickedItemIds = [] }) => { | |||||
const result = pickedItemIds.map((pickedId, i) => { | const result = pickedItemIds.map((pickedId, i) => { | ||||
const item = items.find(f => f.id === pickedId); | const item = items.find(f => f.id === pickedId); | ||||
if (!item) | |||||
return null; | |||||
const isItemValid = needItems[i].allowedItemIds.includes(item.id); | const isItemValid = needItems[i].allowedItemIds.includes(item.id); | ||||
if (!isItemValid) | if (!isItemValid) | ||||
@@ -20,7 +20,7 @@ module.exports = (cpnWorkbench, msg) => { | |||||
return null; | return null; | ||||
const { needItems = [] } = recipe; | const { needItems = [] } = recipe; | ||||
const { syncer, inventory, equipment, spellbook } = crafter; | |||||
const { inventory, equipment, spellbook } = crafter; | |||||
const materials = buildMaterials(crafter, recipe, msg); | const materials = buildMaterials(crafter, recipe, msg); | ||||
const pickedItems = buildPickedItems(crafter, recipe, msg); | const pickedItems = buildPickedItems(crafter, recipe, msg); | ||||
@@ -47,11 +47,8 @@ module.exports = (cpnWorkbench, msg) => { | |||||
resultMsg = recipe.craftAction(crafter, pickedItems); | resultMsg = recipe.craftAction(crafter, pickedItems); | ||||
pickedItems.forEach((p, i) => { | pickedItems.forEach((p, i) => { | ||||
if (!p.eq) { | |||||
pickedItems.forEach(item => syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item))); | |||||
if (!p.eq) | |||||
return; | return; | ||||
} | |||||
applyItemStats(crafter, p, true); | applyItemStats(crafter, p, true); | ||||
@@ -59,8 +56,6 @@ module.exports = (cpnWorkbench, msg) => { | |||||
equipment.unequip(p.id); | equipment.unequip(p.id); | ||||
spellbook.calcDps(); | spellbook.calcDps(); | ||||
pickedItems.forEach(item => syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item))); | |||||
}); | }); | ||||
equipment.unequipAttrRqrGear(); | equipment.unequipAttrRqrGear(); | ||||
@@ -84,6 +79,8 @@ module.exports = (cpnWorkbench, msg) => { | |||||
if (quantity && quantity.push) | if (quantity && quantity.push) | ||||
item.quantity = quantity[0] + ~~(Math.random() * (quantity[1] - quantity[0])); | item.quantity = quantity[0] + ~~(Math.random() * (quantity[1] - quantity[0])); | ||||
console.log(item); | |||||
crafter.inventory.getItem(item); | crafter.inventory.getItem(item); | ||||
}); | }); | ||||
} | } | ||||
@@ -10,14 +10,14 @@ module.exports = { | |||||
type: 'herb', | type: 'herb', | ||||
max: 1, | max: 1, | ||||
cdMax: 1710 | cdMax: 1710 | ||||
}, | |||||
'Sun Carp School': { | |||||
max: 900, | |||||
type: 'fish', | |||||
quantity: [6, 12] | |||||
} | } | ||||
}, | }, | ||||
objects: { | objects: { | ||||
'sun carp school': { | |||||
max: 9, | |||||
type: 'fish', | |||||
quantity: [6, 12] | |||||
}, | |||||
shopestrid: { | shopestrid: { | ||||
properties: { | properties: { | ||||
cpnNotice: { | cpnNotice: { | ||||
@@ -1,94 +0,0 @@ | |||||
const calculateAugmentMaterials = require('./enchanting/calculateAugmentMaterials'); | |||||
const reroll = require('./enchanting/craftActions/reroll'); | |||||
const relevel = require('./enchanting/craftActions/relevel'); | |||||
const augment = require('./enchanting/craftActions/augment'); | |||||
const reslot = require('./enchanting/craftActions/reslot'); | |||||
const reforge = require('./enchanting/craftActions/reforge'); | |||||
const scour = require('./enchanting/craftActions/scour'); | |||||
module.exports = [{ | |||||
name: 'Augment', | |||||
description: 'Adds a random stat to an item. Items can hold a maximum of three augments.', | |||||
materialGenerator: calculateAugmentMaterials, | |||||
craftAction: augment, | |||||
needItems: [{ | |||||
info: 'Pick an item to augment', | |||||
withProps: ['slot'], | |||||
withoutProps: ['noAugment'], | |||||
checks: [ | |||||
item => !item.power || item.power < 3 | |||||
] | |||||
}] | |||||
}, { | |||||
name: 'Reroll', | |||||
description: 'Rerolls an item\'s implicit and explicit stats. Augmentations are not affected.', | |||||
materials: [{ | |||||
name: 'Unstable Idol', | |||||
quantity: 1 | |||||
}], | |||||
needItems: [{ | |||||
info: 'Pick an item to reroll', | |||||
withProps: ['slot'], | |||||
withoutProps: ['noAugment'] | |||||
}], | |||||
craftAction: reroll | |||||
}, { | |||||
name: 'Increase Level', | |||||
description: 'Adds [1 - 3] to an item\'s required level. Items with higher levels yield better stats when rerolled.', | |||||
materials: [{ | |||||
name: 'Ascendant Idol', | |||||
quantity: 1 | |||||
}], | |||||
needItems: [{ | |||||
info: 'Pick the item you wish to ascend', | |||||
withProps: ['slot'], | |||||
withoutProps: ['noAugment'], | |||||
checks: [ | |||||
item => item.level && item.level < consts.maxLevel | |||||
] | |||||
}], | |||||
craftAction: relevel | |||||
}, { | |||||
name: 'Reslot', | |||||
description: 'Reforms the item into a random new item that retains the source item\'s quality and stat types.', | |||||
materials: [{ | |||||
name: 'Dragon-Glass Idol', | |||||
quantity: 1 | |||||
}], | |||||
needItems: [{ | |||||
info: 'Pick an item to reslot', | |||||
withProps: ['slot'], | |||||
withoutProps: ['noAugment', 'effects'] | |||||
}], | |||||
craftAction: reslot | |||||
}, { | |||||
name: 'Reforge Weapon', | |||||
description: 'Rerolls a weapon\'s damage range.', | |||||
materials: [{ | |||||
name: 'Bone Idol', | |||||
quantity: 1 | |||||
}], | |||||
needItems: [{ | |||||
info: 'Pick an item to reforge', | |||||
withProps: ['slot', 'spell'], | |||||
withoutProps: ['noAugment'] | |||||
}], | |||||
craftAction: reforge | |||||
}, { | |||||
name: 'Scour', | |||||
description: 'Wipe all augments from an item.', | |||||
materials: [{ | |||||
name: 'Smoldering Idol', | |||||
quantity: 1 | |||||
}], | |||||
needItems: [{ | |||||
info: 'Pick an item to scour', | |||||
withProps: ['slot', 'power'], | |||||
withoutProps: ['noAugment'] | |||||
}], | |||||
craftAction: scour, | |||||
checks: [ | |||||
item => item.power && item.power >= 1 | |||||
] | |||||
}]; |
@@ -1,17 +0,0 @@ | |||||
const salvager = require('../../../items/salvager'); | |||||
module.exports = (obj, [item]) => { | |||||
let powerLevel = item.power || 0; | |||||
let mult = null; | |||||
if (powerLevel < 3) | |||||
mult = [5, 10, 20][powerLevel]; | |||||
else | |||||
return; | |||||
const result = salvager.salvage(item, true); | |||||
result.forEach(r => { | |||||
r.quantity = Math.max(1, ~~(r.quantity * mult)); | |||||
}); | |||||
return result; | |||||
}; |
@@ -1,17 +0,0 @@ | |||||
let generatorStats = require('../../../../items/generators/stats'); | |||||
module.exports = (obj, [item]) => { | |||||
let newPower = (item.power || 0) + 1; | |||||
if (newPower > 3) | |||||
return; | |||||
item.power = newPower; | |||||
const result = { msg: 'Augment successful', addStatMsgs: [] }; | |||||
generatorStats.generate(item, { | |||||
statCount: 1 | |||||
}, result); | |||||
return result; | |||||
}; |
@@ -1,20 +0,0 @@ | |||||
let generatorSpells = require('../../../../items/generators/spellbook'); | |||||
module.exports = (obj, [item]) => { | |||||
if (!item.spell) | |||||
return; | |||||
let spellName = item.spell.name.toLowerCase(); | |||||
let oldSpell = item.spell; | |||||
delete item.spell; | |||||
generatorSpells.generate(item, { | |||||
spellName: spellName | |||||
}); | |||||
item.spell = extend(oldSpell, item.spell); | |||||
const damage = item.spell.values.damage; | |||||
const msg = `Reforged weapon to damage: ${damage}`; | |||||
return { msg }; | |||||
}; |
@@ -1,20 +0,0 @@ | |||||
module.exports = (obj, [item]) => { | |||||
if (item.slot === 'tool') | |||||
return; | |||||
let offset = 1 + ~~(Math.random() * 2); | |||||
const maxLevel = consts.maxLevel; | |||||
if (!item.originalLevel) | |||||
item.level = Math.min(maxLevel, item.level + offset); | |||||
else { | |||||
offset = Math.min(maxLevel - item.originalLevel, offset); | |||||
item.originalLevel = Math.min(maxLevel, item.originalLevel + offset); | |||||
item.level = Math.min(maxLevel, item.level + offset); | |||||
} | |||||
const msg = `Relevelled item to level ${item.level}`; | |||||
return { msg }; | |||||
}; |
@@ -1,58 +0,0 @@ | |||||
let generatorStats = require('../../../../items/generators/stats'); | |||||
let generatorSlots = require('../../../../items/generators/slots'); | |||||
let generatorTypes = require('../../../../items/generators/types'); | |||||
module.exports = (obj, [item]) => { | |||||
const enchantedStats = item.enchantedStats; | |||||
const implicitStats = item.implicitStats; | |||||
delete item.enchantedStats; | |||||
delete item.implicitStats; | |||||
if ((item.stats) && (item.stats.lvlRequire)) { | |||||
item.level = Math.min(consts.maxLevel, item.level + item.stats.lvlRequire); | |||||
delete item.originalLevel; | |||||
} | |||||
item.stats = {}; | |||||
let bpt = { | |||||
slot: item.slot, | |||||
type: item.type, | |||||
sprite: item.sprite, | |||||
spritesheet: item.spritesheet | |||||
}; | |||||
generatorSlots.generate(item, bpt); | |||||
generatorTypes.generate(item, bpt); | |||||
generatorStats.generate(item, bpt); | |||||
for (let p in enchantedStats) { | |||||
if (!item.stats[p]) | |||||
item.stats[p] = 0; | |||||
item.stats[p] += enchantedStats[p]; | |||||
if (p === 'lvlRequire') { | |||||
if (!item.originalLevel) | |||||
item.originalLevel = item.level; | |||||
item.level -= enchantedStats[p]; | |||||
if (item.level < 1) | |||||
item.level = 1; | |||||
} | |||||
} | |||||
item.enchantedStats = enchantedStats || null; | |||||
//Some items have special implicits (different stats than their types imply) | |||||
// We add the old one back in if this is the case. Ideally we'd like to reroll | |||||
// these but that'd be a pretty big hack. We'll solve this one day | |||||
if ( | |||||
item.implicitStats && | |||||
implicitStats && | |||||
item.implicitStats[0] && | |||||
implicitStats[0] && | |||||
item.implicitStats[0].stat !== implicitStats[0].stat | |||||
) | |||||
item.implicitStats = implicitStats; | |||||
return { msg: 'Reroll successful' }; | |||||
}; |
@@ -1,36 +0,0 @@ | |||||
let configSlots = require('../../../../items/config/slots'); | |||||
let generator = require('../../../../items/generator'); | |||||
module.exports = (obj, [item]) => { | |||||
if (item.effects || item.slot === 'tool') | |||||
return; | |||||
if (item.originalLevel) | |||||
item.level = item.originalLevel; | |||||
delete item.enchantedStats; | |||||
let possibleStats = Object.keys(item.stats || {}); | |||||
let newItem = generator.generate({ | |||||
slot: configSlots.getRandomSlot(item.slot), | |||||
level: item.level, | |||||
quality: item.quality, | |||||
stats: possibleStats, | |||||
limitSlotStats: true | |||||
}); | |||||
delete item.spritesheet; | |||||
delete item.stats; | |||||
delete item.spell; | |||||
delete item.implicitStats; | |||||
delete item.power; | |||||
delete item.range; | |||||
delete item.requires; | |||||
extend(item, newItem); | |||||
const msg = `Reslotted item to slot: ${item.slot}`; | |||||
return { msg }; | |||||
}; |
@@ -1,31 +0,0 @@ | |||||
module.exports = (obj, [item]) => { | |||||
if (!item.power) | |||||
return; | |||||
const result = { msg: 'Scour successful', addStatMsgs: [] }; | |||||
for (let p in item.enchantedStats) { | |||||
let value = item.enchantedStats[p]; | |||||
if (item.stats[p]) { | |||||
result.addStatMsgs.push({ | |||||
stat: p, | |||||
value: -value | |||||
}); | |||||
item.stats[p] -= value; | |||||
if (item.stats[p] <= 0) | |||||
delete item.stats[p]; | |||||
if (p === 'lvlRequire') { | |||||
item.level = Math.min(consts.maxLevel, item.level + value); | |||||
delete item.originalLevel; | |||||
} | |||||
} | |||||
} | |||||
delete item.enchantedStats; | |||||
delete item.power; | |||||
return result; | |||||
}; |
@@ -3,13 +3,11 @@ let events = require('../../misc/events'); | |||||
const recipesAlchemy = require('./alchemy'); | const recipesAlchemy = require('./alchemy'); | ||||
const recipesCooking = require('./cooking'); | const recipesCooking = require('./cooking'); | ||||
const recipesEtching = require('./etching'); | const recipesEtching = require('./etching'); | ||||
const recipesEnchanting = require('./enchanting'); | |||||
let recipes = { | let recipes = { | ||||
alchemy: [ ...recipesAlchemy ], | alchemy: [ ...recipesAlchemy ], | ||||
cooking: [ ...recipesCooking ], | cooking: [ ...recipesCooking ], | ||||
etching: [ ...recipesEtching ], | |||||
enchanting: [ ...recipesEnchanting ] | |||||
etching: [ ...recipesEtching ] | |||||
}; | }; | ||||
module.exports = { | module.exports = { | ||||
@@ -2,7 +2,7 @@ let events = require('../misc/events'); | |||||
module.exports = { | module.exports = { | ||||
init: function () { | init: function () { | ||||
events.emit('onBeforeGetHerbConfig', this); | |||||
events.emit('onBeforeGetResourceNodeConfig', this); | |||||
}, | }, | ||||
Moonbell: { | Moonbell: { | ||||
@@ -20,7 +20,7 @@ module.exports = { | |||||
cell: 51, | cell: 51, | ||||
itemSprite: [1, 0] | itemSprite: [1, 0] | ||||
}, | }, | ||||
'Sun Carp': { | |||||
'Sun Carp School': { | |||||
sheetName: 'objects', | sheetName: 'objects', | ||||
itemSprite: [11, 2], | itemSprite: [11, 2], | ||||
baseWeight: 3, | baseWeight: 3, |
@@ -1,38 +0,0 @@ | |||||
module.exports = { | |||||
'Iron Bar': { | |||||
sprite: [0, 0], | |||||
quality: 0 | |||||
}, | |||||
'Cloth Scrap': { | |||||
sprite: [0, 1], | |||||
quality: 0 | |||||
}, | |||||
'Leather Scrap': { | |||||
sprite: [0, 7], | |||||
quality: 0 | |||||
}, | |||||
'Common Essence': { | |||||
sprite: [0, 2], | |||||
quality: 0 | |||||
}, | |||||
'Magic Essence': { | |||||
sprite: [0, 3], | |||||
quality: 1 | |||||
}, | |||||
'Rare Essence': { | |||||
sprite: [0, 4], | |||||
quality: 2 | |||||
}, | |||||
'Epic Essence': { | |||||
sprite: [0, 5], | |||||
quality: 3 | |||||
}, | |||||
'Legendary Essence': { | |||||
sprite: [0, 6], | |||||
quality: 4 | |||||
}, | |||||
'Cerulean Pearl': { | |||||
sprite: [11, 9], | |||||
quality: 3 | |||||
} | |||||
}; |
@@ -42,6 +42,42 @@ const buildRolls = (item, blueprint, { random: spellProperties, negativeStats = | |||||
return result; | return result; | ||||
}; | }; | ||||
const buildValues = item => { | |||||
//Weapons have item.spell, runes just have item | |||||
const spell = item.spell ? item.spell : item; | |||||
const { name, type, rolls } = spell; | |||||
const useName = (name || type).toLowerCase(); | |||||
const randomSpec = spellsConfig.spells[useName].random; | |||||
const result = {}; | |||||
Object.entries(rolls).forEach(entry => { | |||||
const [ property, roll ] = entry; | |||||
const range = randomSpec[property]; | |||||
const isInt = property.indexOf('i_') === 0; | |||||
let useProperty = property; | |||||
const minRange = range[0]; | |||||
const maxRange = range[1]; | |||||
let val = minRange + ((maxRange - minRange) * roll); | |||||
if (isInt) { | |||||
useProperty = property.substr(2); | |||||
val = Math.round(val); | |||||
} else | |||||
val = ~~(val * 100) / 100; | |||||
val = Math.max(range[0], Math.min(range[1], val)); | |||||
result[useProperty] = val; | |||||
}); | |||||
return result; | |||||
}; | |||||
module.exports = { | module.exports = { | ||||
generate: function (item, blueprint) { | generate: function (item, blueprint) { | ||||
blueprint = blueprint || {}; | blueprint = blueprint || {}; | ||||
@@ -111,30 +147,10 @@ module.exports = { | |||||
} | } | ||||
const rolls = buildRolls(item, blueprint, spell, quality); | const rolls = buildRolls(item, blueprint, spell, quality); | ||||
Object.entries(spell.random || {}).forEach(entry => { | |||||
const [ property, range ] = entry; | |||||
const roll = rolls[property]; | |||||
item.spell.rolls[property] = roll; | |||||
const isInt = property.indexOf('i_') === 0; | |||||
let useProperty = property; | |||||
const minRange = range[0]; | |||||
const maxRange = range[1]; | |||||
item.spell.rolls = rolls; | |||||
let val = minRange + ((maxRange - minRange) * roll); | |||||
if (isInt) { | |||||
useProperty = property.substr(2); | |||||
val = Math.round(val); | |||||
} else | |||||
val = ~~(val * 100) / 100; | |||||
val = Math.max(range[0], Math.min(range[1], val)); | |||||
item.spell.values[useProperty] = val; | |||||
}); | |||||
const values = buildValues(item); | |||||
item.spell.values = values; | |||||
if (blueprint.spellProperties) { | if (blueprint.spellProperties) { | ||||
item.spell.properties = {}; | item.spell.properties = {}; | ||||
@@ -146,5 +162,7 @@ module.exports = { | |||||
item.spell.properties = item.spell.properties || {}; | item.spell.properties = item.spell.properties || {}; | ||||
item.spell.properties.range = item.range; | item.spell.properties.range = item.range; | ||||
} | } | ||||
} | |||||
}, | |||||
buildValues | |||||
}; | }; |
@@ -1,159 +0,0 @@ | |||||
let mappings = { | |||||
rune: [{ | |||||
materials: [{ | |||||
name: 'Essence', | |||||
qualityName: ['Common Essence', 'Magic Essence', 'Rare Essence', 'Epic Essence', 'Legendary Essence'], | |||||
chance: 100, | |||||
quantity: 1 | |||||
}] | |||||
}], | |||||
slots: [{ | |||||
list: ['neck', 'finger', 'twoHanded', 'oneHanded', 'offHand'], | |||||
materials: [{ | |||||
name: 'Iron Bar', | |||||
chance: 100, | |||||
quantity: 3, | |||||
qualityMult: 1 | |||||
}] | |||||
}, { | |||||
list: ['trinket'], | |||||
materials: [{ | |||||
name: 'Essence', | |||||
qualityName: ['Common Essence', 'Magic Essence', 'Rare Essence', 'Epic Essence', 'Legendary Essence'], | |||||
chance: 100, | |||||
quantity: 1 | |||||
}] | |||||
}, { | |||||
list: ['tool'], | |||||
materials: [{ | |||||
name: 'Cerulean Pearl', | |||||
chance: 100, | |||||
quantity: 1, | |||||
quality: 3, | |||||
qualityMult: 1 | |||||
}] | |||||
}], | |||||
types: [{ | |||||
list: ['Helmet', 'Belt', 'Legplates', 'Gauntlets', 'Steel Boots', 'Breastplate'], | |||||
materials: [{ | |||||
name: 'Iron Bar', | |||||
chance: 100, | |||||
quantity: 3, | |||||
qualityMult: 1 | |||||
}] | |||||
}, { | |||||
list: ['Cowl', 'Robe', 'Gloves', 'Sash', 'Pants', 'Boots'], | |||||
materials: [{ | |||||
name: 'Cloth Scrap', | |||||
chance: 100, | |||||
quantity: 3, | |||||
qualityMult: 1 | |||||
}] | |||||
}, { | |||||
list: ['Leather Cap', 'Leather Armor', 'Leather Gloves', 'Leather Belt', 'Leather Pants', 'Leather Boots', 'Facemask', 'Scalemail', 'Scale Gloves', 'Scaled Binding', 'Scale Leggings', 'Scale Boots'], | |||||
materials: [{ | |||||
name: 'Leather Scrap', | |||||
chance: 100, | |||||
quantity: 3, | |||||
qualityMult: 1 | |||||
}] | |||||
}, { | |||||
list: ['Fishing Rod'], | |||||
materials: [{ | |||||
name: 'Cerulean Pearl', | |||||
chance: 100, | |||||
quantity: 1, | |||||
qualityMult: 1 | |||||
}] | |||||
}] | |||||
}; | |||||
let materialItems = { | |||||
'Iron Bar': { | |||||
sprite: [0, 0] | |||||
}, | |||||
'Cloth Scrap': { | |||||
sprite: [0, 1] | |||||
}, | |||||
'Leather Scrap': { | |||||
sprite: [0, 7] | |||||
}, | |||||
'Common Essence': { | |||||
sprite: [0, 2] | |||||
}, | |||||
'Magic Essence': { | |||||
sprite: [0, 3] | |||||
}, | |||||
'Rare Essence': { | |||||
sprite: [0, 4] | |||||
}, | |||||
'Epic Essence': { | |||||
sprite: [0, 5] | |||||
}, | |||||
'Legendary Essence': { | |||||
sprite: [0, 6] | |||||
}, | |||||
'Cerulean Pearl': { | |||||
sprite: [11, 9] | |||||
} | |||||
}; | |||||
module.exports = { | |||||
salvage: function (item, maxRoll) { | |||||
let result = []; | |||||
let materials = []; | |||||
let temp = mappings.slots.filter(m => m.list.indexOf(item.slot) > -1); | |||||
temp = temp.concat(mappings.types.filter(m => m.list.indexOf(item.type) > -1)); | |||||
if (item.ability) | |||||
temp = temp.concat(mappings.rune); | |||||
temp.forEach(function (t) { | |||||
let mats = t.materials; | |||||
mats.forEach(function (m) { | |||||
let exists = materials.find(mf => (mf.name === m.name)); | |||||
if (exists) { | |||||
exists.chance = Math.max(exists.chance, m.chance); | |||||
exists.quantity = Math.max(exists.quantity, m.quantity); | |||||
exists.qualityMult = Math.max(exists.qualityMult, m.qualityMult); | |||||
} else | |||||
materials.push(extend({}, m)); | |||||
}); | |||||
}); | |||||
materials.forEach(function (m) { | |||||
if ((!maxRoll) && (Math.random() * 100 > m.chance)) | |||||
return; | |||||
let max = m.quantity; | |||||
if (m.qualityMult) | |||||
max *= (m.qualityMult * (item.quality + 1)); | |||||
let quantity = Math.ceil(random.norm(0, 1) * max) || 1; | |||||
if (maxRoll) | |||||
quantity = Math.ceil(max); | |||||
let newItem = { | |||||
name: m.name, | |||||
quantity: quantity, | |||||
quality: 0, | |||||
material: true, | |||||
sprite: null | |||||
}; | |||||
if (m.qualityName) { | |||||
newItem.quality = item.quality; | |||||
newItem.name = m.qualityName[item.quality]; | |||||
} else if (m.has('quality')) | |||||
newItem.quality = m.quality; | |||||
newItem.sprite = materialItems[newItem.name].sprite; | |||||
result.push(newItem); | |||||
}); | |||||
return result; | |||||
} | |||||
}; |
@@ -1,40 +1,3 @@ | |||||
const defaultConfig = [{ | |||||
name: 'Iron Bar', | |||||
sprite: [0, 0], | |||||
quality: 0, | |||||
chance: 15 | |||||
}, { | |||||
name: 'Cloth Scrap', | |||||
sprite: [0, 1], | |||||
quality: 0, | |||||
chance: 15 | |||||
}, { | |||||
name: 'Leather Scrap', | |||||
sprite: [0, 7], | |||||
quality: 0, | |||||
chance: 15 | |||||
}, { | |||||
name: 'Skyblossom', | |||||
sprite: [1, 2], | |||||
quality: 0, | |||||
chance: 8 | |||||
}, { | |||||
name: 'Common Essence', | |||||
sprite: [0, 2], | |||||
quality: 0, | |||||
chance: 5 | |||||
}, { | |||||
name: 'Magic Essence', | |||||
sprite: [0, 3], | |||||
quality: 1, | |||||
chance: 2 | |||||
}, { | |||||
name: 'Rare Essence', | |||||
sprite: [0, 4], | |||||
quality: 2, | |||||
chance: 1 | |||||
}]; | |||||
const buildPool = config => { | const buildPool = config => { | ||||
const pool = []; | const pool = []; | ||||
@@ -46,11 +9,9 @@ const buildPool = config => { | |||||
return pool; | return pool; | ||||
}; | }; | ||||
const defaultPool = buildPool(defaultConfig); | |||||
module.exports = (itemCount, useConfig) => { | |||||
const config = useConfig || defaultConfig; | |||||
const pool = useConfig ? buildPool(useConfig) : defaultPool; | |||||
module.exports = (itemCount, useConfig = []) => { | |||||
const config = useConfig; | |||||
const pool = buildPool(useConfig); | |||||
const items = []; | const items = []; | ||||
@@ -58,13 +19,13 @@ module.exports = (itemCount, useConfig) => { | |||||
let pickName = pool[~~(Math.random() * pool.length)]; | let pickName = pool[~~(Math.random() * pool.length)]; | ||||
const pick = config.find(f => f.name === pickName); | const pick = config.find(f => f.name === pickName); | ||||
if (!pick) | |||||
break; | |||||
let item = items.find(f => f.name === pickName); | let item = items.find(f => f.name === pickName); | ||||
if (!item) { | if (!item) { | ||||
items.push({ | items.push({ | ||||
name: pick.name, | |||||
material: true, | |||||
quality: pick.quality, | |||||
sprite: pick.sprite, | |||||
...pick, | |||||
quantity: pick.quantity || 1 | quantity: pick.quantity || 1 | ||||
}); | }); | ||||
} else | } else | ||||
@@ -10,7 +10,7 @@ const routerConfig = { | |||||
dialogue: ['talk'], | dialogue: ['talk'], | ||||
gatherer: ['gather'], | gatherer: ['gather'], | ||||
quests: ['complete'], | quests: ['complete'], | ||||
inventory: ['combineStacks', 'splitStack', 'activateMtx', 'useItem', 'moveItem', 'learnAbility', 'unlearnAbility', 'dropItem', 'destroyItem', 'salvageItem', 'stashItem', 'mailItem', 'sortInventory'], | |||||
inventory: ['combineStacks', 'splitStack', 'activateMtx', 'useItem', 'moveItem', 'learnAbility', 'unlearnAbility', 'dropItem', 'destroyItem', 'stashItem', 'mailItem', 'sortInventory'], | |||||
equipment: ['equip', 'unequip', 'setQuickSlot', 'useQuickSlot', 'inspect'], | equipment: ['equip', 'unequip', 'setQuickSlot', 'useQuickSlot', 'inspect'], | ||||
stash: ['withdraw', 'open'], | stash: ['withdraw', 'open'], | ||||
trade: ['buySell'], | trade: ['buySell'], | ||||
@@ -3,14 +3,13 @@ let syncer = require('./syncer'); | |||||
let objects = require('../objects/objects'); | let objects = require('../objects/objects'); | ||||
let spawners = require('./spawners'); | let spawners = require('./spawners'); | ||||
let physics = require('./physics'); | let physics = require('./physics'); | ||||
let resourceSpawner = require('./resourceSpawner'); | |||||
let spellCallbacks = require('../config/spells/spellCallbacks'); | let spellCallbacks = require('../config/spells/spellCallbacks'); | ||||
let questBuilder = require('../config/quests/questBuilder'); | let questBuilder = require('../config/quests/questBuilder'); | ||||
let randomMap = require('./randomMap'); | let randomMap = require('./randomMap'); | ||||
let events = require('../events/events'); | let events = require('../events/events'); | ||||
let scheduler = require('../misc/scheduler'); | let scheduler = require('../misc/scheduler'); | ||||
let mail = require('../mail/mail'); | let mail = require('../mail/mail'); | ||||
let herbs = require('../config/herbs'); | |||||
let resourceNodes = require('../config/resourceNodes'); | |||||
let eventEmitter = require('../misc/events'); | let eventEmitter = require('../misc/events'); | ||||
const transactions = require('../security/transactions'); | const transactions = require('../security/transactions'); | ||||
@@ -25,7 +24,7 @@ module.exports = { | |||||
this.zoneId = args.zoneId; | this.zoneId = args.zoneId; | ||||
spellCallbacks.init(); | spellCallbacks.init(); | ||||
herbs.init(); | |||||
resourceNodes.init(); | |||||
map.init(args); | map.init(args); | ||||
const fakeInstance = { | const fakeInstance = { | ||||
@@ -64,15 +63,17 @@ module.exports = { | |||||
map.clientMap.zoneId = this.zoneId; | map.clientMap.zoneId = this.zoneId; | ||||
[resourceSpawner, syncer, objects, questBuilder, events, mail].forEach(i => i.init(fakeInstance)); | |||||
[syncer, objects, questBuilder, events, mail].forEach(i => i.init(fakeInstance)); | |||||
eventEmitter.emitNoSticky('onInitModules', fakeInstance); | |||||
this.tick(); | this.tick(); | ||||
}, | }, | ||||
tick: function () { | tick: function () { | ||||
eventEmitter.emitNoSticky('onBeforeZoneUpdate'); | |||||
events.update(); | events.update(); | ||||
objects.update(); | objects.update(); | ||||
resourceSpawner.update(); | |||||
spawners.update(); | spawners.update(); | ||||
syncer.update(); | syncer.update(); | ||||
scheduler.update(); | scheduler.update(); | ||||
@@ -1,7 +1,6 @@ | |||||
let objects = require('../objects/objects'); | let objects = require('../objects/objects'); | ||||
let physics = require('./physics'); | let physics = require('./physics'); | ||||
let spawners = require('./spawners'); | let spawners = require('./spawners'); | ||||
let resourceSpawner = require('./resourceSpawner'); | |||||
let globalZone = require('../config/zoneBase'); | let globalZone = require('../config/zoneBase'); | ||||
let randomMap = require('./randomMap'); | let randomMap = require('./randomMap'); | ||||
let events = require('../misc/events'); | let events = require('../misc/events'); | ||||
@@ -97,10 +96,6 @@ module.exports = { | |||||
this.zone = extend({}, globalZone, this.zone); | this.zone = extend({}, globalZone, this.zone); | ||||
let resources = this.zone.resources || {}; | |||||
for (let r in resources) | |||||
resourceSpawner.register(r, resources[r]); | |||||
mapFile = require('../' + this.path + '/' + this.name + '/map'); | mapFile = require('../' + this.path + '/' + this.name + '/map'); | ||||
this.mapFile = mapFile; | this.mapFile = mapFile; | ||||
//Fix for newer versions of Tiled | //Fix for newer versions of Tiled | ||||
@@ -208,6 +203,8 @@ module.exports = { | |||||
}, | }, | ||||
build: function () { | build: function () { | ||||
events.emit('onBeforeBuildMap', this.name, this.zone); | |||||
const mapSize = { | const mapSize = { | ||||
w: mapFile.width, | w: mapFile.width, | ||||
h: mapFile.height | h: mapFile.height | ||||
@@ -360,6 +357,17 @@ module.exports = { | |||||
} | } | ||||
}, | }, | ||||
object: function (layerName, cell) { | object: function (layerName, cell) { | ||||
const buildObjectMsg = { | |||||
layerName, | |||||
mapScale, | |||||
obj: cell, | |||||
zoneConfig: this.zone, | |||||
ignore: false | |||||
}; | |||||
events.emit('onBeforeBuildMapObject', buildObjectMsg); | |||||
if (buildObjectMsg.built) | |||||
return; | |||||
//Fixes for newer versions of tiled | //Fixes for newer versions of tiled | ||||
cell.properties = objectifyProperties(cell.properties); | cell.properties = objectifyProperties(cell.properties); | ||||
cell.polyline = cell.polyline || cell.polygon; | cell.polyline = cell.polyline || cell.polygon; | ||||
@@ -421,9 +429,7 @@ module.exports = { | |||||
}); | }); | ||||
room.exits.push(blueprint); | room.exits.push(blueprint); | ||||
} else if (blueprint.properties.resource) | |||||
resourceSpawner.register(blueprint.properties.resource, blueprint); | |||||
else { | |||||
} else { | |||||
blueprint.exits = []; | blueprint.exits = []; | ||||
blueprint.objects = []; | blueprint.objects = []; | ||||
this.rooms.push(blueprint); | this.rooms.push(blueprint); | ||||
@@ -1,199 +0,0 @@ | |||||
let herbs = require('../config/herbs'); | |||||
module.exports = { | |||||
nodes: [], | |||||
objects: null, | |||||
syncer: null, | |||||
zone: null, | |||||
physics: null, | |||||
map: null, | |||||
cdMax: 171, | |||||
init: function (instance) { | |||||
Object.assign(this, { | |||||
objects: instance.objects, | |||||
syncer: instance.syncer, | |||||
physics: instance.physics, | |||||
map: instance.map, | |||||
zone: instance.zone | |||||
}); | |||||
}, | |||||
register: function (name, blueprint) { | |||||
let exists = this.nodes.find(n => (n.blueprint.name === name)); | |||||
if (exists) { | |||||
if (!exists.blueprint.positions) { | |||||
exists.blueprint.positions = [{ | |||||
x: exists.blueprint.x, | |||||
y: exists.blueprint.y, | |||||
width: exists.blueprint.width, | |||||
height: exists.blueprint.height | |||||
}]; | |||||
} | |||||
exists.blueprint.positions.push({ | |||||
x: blueprint.x, | |||||
y: blueprint.y, | |||||
width: blueprint.width, | |||||
height: blueprint.height | |||||
}); | |||||
return; | |||||
} | |||||
blueprint = extend({}, blueprint, herbs[name], { | |||||
name: name | |||||
}); | |||||
let max = blueprint.max; | |||||
delete blueprint.max; | |||||
let chance = blueprint.chance; | |||||
delete blueprint.chance; | |||||
let cdMax = blueprint.cdMax; | |||||
delete blueprint.cdMax; | |||||
this.nodes.push({ | |||||
cd: 0, | |||||
max: max, | |||||
chance: chance, | |||||
cdMax: cdMax, | |||||
blueprint: blueprint, | |||||
spawns: [] | |||||
}); | |||||
}, | |||||
getRandomSpawnPosition: function (node, blueprint) { | |||||
//Get an accessible position | |||||
let w = this.physics.width; | |||||
let h = this.physics.height; | |||||
let x = blueprint.x; | |||||
let y = blueprint.y; | |||||
let position = null; | |||||
if (blueprint.type === 'herb') { | |||||
x = ~~(Math.random() * w); | |||||
y = ~~(Math.random() * h); | |||||
if (this.physics.isTileBlocking(x, y)) | |||||
return false; | |||||
let spawn = this.map.spawn[0]; | |||||
let path = this.physics.getPath(spawn, { | |||||
x: x, | |||||
y: y | |||||
}); | |||||
let endTile = path[path.length - 1]; | |||||
if (!endTile) | |||||
return false; | |||||
else if ((endTile.x !== x) || (endTile.y !== y)) | |||||
return false; | |||||
//Don't spawn in rooms or on objects/other resources | |||||
let cell = this.physics.getCell(x, y); | |||||
if (cell.length > 0) | |||||
return false; | |||||
position = { x, y }; | |||||
} else if (blueprint.positions) { | |||||
//Find all possible positions in which a node hasn't spawned yet | |||||
position = blueprint.positions.filter(f => !node.spawns.some(s => ((s.x === f.x) && (s.y === f.y)))); | |||||
if (position.length === 0) | |||||
return false; | |||||
position = position[~~(Math.random() * position.length)]; | |||||
} | |||||
return position; | |||||
}, | |||||
spawn: function (node) { | |||||
let blueprint = node.blueprint; | |||||
let position = this.getRandomSpawnPosition(node, blueprint); | |||||
if (!position) | |||||
return false; | |||||
let quantity = 1; | |||||
if (blueprint.quantity) | |||||
quantity = blueprint.quantity[0] + ~~(Math.random() * (blueprint.quantity[1] - blueprint.quantity[0])); | |||||
let zoneLevel = this.zone.level; | |||||
zoneLevel = ~~(zoneLevel[0] + ((zoneLevel[1] - zoneLevel[0]) / 2)); | |||||
let objBlueprint = extend({}, blueprint, position); | |||||
objBlueprint.properties = { | |||||
cpnResourceNode: { | |||||
nodeType: blueprint.type, | |||||
ttl: blueprint.ttl, | |||||
xp: zoneLevel * zoneLevel, | |||||
blueprint: extend({}, blueprint), | |||||
quantity: quantity | |||||
} | |||||
}; | |||||
let obj = this.objects.buildObjects([objBlueprint]); | |||||
delete obj.ttl; | |||||
if (blueprint.type === 'herb') { | |||||
this.syncer.queue('onGetObject', { | |||||
x: obj.x, | |||||
y: obj.y, | |||||
components: [{ | |||||
type: 'attackAnimation', | |||||
row: 0, | |||||
col: 4 | |||||
}] | |||||
}, -1); | |||||
} | |||||
let inventory = obj.addComponent('inventory'); | |||||
obj.layerName = 'objects'; | |||||
node.spawns.push(obj); | |||||
let item = { | |||||
material: true, | |||||
type: node.type || null, | |||||
sprite: node.blueprint.itemSprite, | |||||
name: node.blueprint.name, | |||||
quantity: (blueprint.type !== 'fish') ? 1 : null, | |||||
quality: 0 | |||||
}; | |||||
if (blueprint.itemSheet) | |||||
item.spritesheet = blueprint.itemSheet; | |||||
if (blueprint.type === 'fish') | |||||
item.noStack = true; | |||||
inventory.getItem(item); | |||||
return true; | |||||
}, | |||||
update: function () { | |||||
let nodes = this.nodes; | |||||
let nLen = nodes.length; | |||||
for (let i = 0; i < nLen; i++) { | |||||
let node = nodes[i]; | |||||
let spawns = node.spawns; | |||||
spawns.spliceWhere(f => f.destroyed); | |||||
if (spawns.length < node.max) { | |||||
if (node.cd > 0) | |||||
node.cd--; | |||||
else if ((!node.chance || Math.random() < node.chance) && this.spawn(node)) | |||||
node.cd = node.cdMax || this.cdMax; | |||||
} | |||||
} | |||||
} | |||||
}; |