@@ -16,6 +16,7 @@ define([ | |||
if (blueprint.destroyItems) { | |||
rerender = true; | |||
this.items.spliceWhere(i => blueprint.destroyItems.includes(i.id)); | |||
events.emit('onDestroyItems', blueprint.destroyItems, this.items); | |||
} | |||
@@ -22,8 +22,6 @@ define([ | |||
centered: true, | |||
items: [], | |||
dragItem: null, | |||
dragEl: null, | |||
hoverCell: null, | |||
@@ -65,7 +63,7 @@ define([ | |||
let container = this.el.find('.grid') | |||
.empty(); | |||
let items = this.items | |||
let items = window.player.inventory.items | |||
.filter(function (item) { | |||
return !item.eq; | |||
}); | |||
@@ -184,7 +182,7 @@ define([ | |||
pos: this.dragItem.index() | |||
}]; | |||
this.items.find(function (i) { | |||
window.player.inventory.items.find(function (i) { | |||
return (i.id === this.dragItem.data('item').id); | |||
}, this).pos = this.dragItem.index(); | |||
@@ -196,7 +194,7 @@ define([ | |||
pos: this.hoverCell.index() | |||
}); | |||
this.items.find(function (i) { | |||
window.player.inventory.items.find(function (i) { | |||
return (i.id === hoverCellItem.id); | |||
}, this).pos = this.hoverCell.index(); | |||
} else { | |||
@@ -264,11 +262,6 @@ define([ | |||
text: 'destroy', | |||
callback: this.performItemAction.bind(this, item, 'destroyItem') | |||
}, | |||
salvage: { | |||
text: 'salvage', | |||
callback: this.performItemAction.bind(this, item, 'salvageItem'), | |||
hotkey: 'f' | |||
}, | |||
stash: { | |||
text: 'stash', | |||
callback: this.performItemAction.bind(this, item, 'stashItem') | |||
@@ -341,9 +334,6 @@ define([ | |||
if (!item.noDrop) | |||
ctxConfig.push(menuItems.drop); | |||
if ((!item.material) && (!item.noSalvage)) | |||
ctxConfig.push(menuItems.salvage); | |||
} | |||
} | |||
@@ -477,19 +467,15 @@ define([ | |||
}, | |||
onGetItems: function (items, rerender) { | |||
this.items = items; | |||
if ((this.shown) && (rerender)) | |||
if (this.shown && rerender) | |||
this.build(); | |||
}, | |||
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) | |||
this.hideTooltip(); | |||
this.items.spliceWhere(i => i.id === id); | |||
}, this); | |||
}); | |||
if (this.shown) | |||
this.build(); | |||
@@ -1,6 +1,7 @@ | |||
const scheduler = require('../../misc/scheduler'); | |||
const rewardGenerator = require('../../misc/rewardGenerator'); | |||
const mail = require('../../mail/mail'); | |||
const events = require('../../misc/events'); | |||
const calculateDaysSkipped = (oldTime, newTime) => { | |||
let daysSkipped = 1; | |||
@@ -63,8 +64,11 @@ module.exports = async (cpnAuth, data, character, cbDone) => { | |||
accountInfo.loginStreak = loginStreak; | |||
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(); | |||
return; | |||
} | |||
@@ -1,9 +1,9 @@ | |||
let roles = require('../../config/roles'); | |||
let generator = require('../../items/generator'); | |||
let configSlots = require('../../items/config/slots'); | |||
let configMaterials = require('../../items/config/materials'); | |||
let factions = require('../../config/factions'); | |||
let connections = require('../../security/connections'); | |||
const events = require('../../misc/events'); | |||
const ban = require('../social/ban'); | |||
const rezone = require('../social/rezone'); | |||
@@ -45,7 +45,6 @@ let commandRoles = { | |||
getXp: 10, | |||
setPassword: 10, | |||
giveSkin: 10, | |||
getMaterials: 10, | |||
rezone: 10, | |||
startEvent: 10, | |||
stopEvent: 10, | |||
@@ -86,6 +85,8 @@ const contextActions = [ | |||
} | |||
]; | |||
const commandActions = {}; | |||
module.exports = { | |||
customChannels: [], | |||
roleLevel: null, | |||
@@ -96,6 +97,13 @@ module.exports = { | |||
.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.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) { | |||
if (typeof(msg) === 'object') | |||
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 salvager = require('../items/salvager'); | |||
let classes = require('../config/spirits'); | |||
let mtx = require('../mtx/mtx'); | |||
let factions = require('../config/factions'); | |||
@@ -302,29 +301,6 @@ module.exports = { | |||
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) { | |||
let item = this.findItem(id); | |||
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 playerSpells = require('../config/spells'); | |||
let playerSpellsConfig = require('../config/spellsConfig'); | |||
const { buildValues: buildRuneValues } = require('../items/generators/spellbook'); | |||
module.exports = { | |||
type: 'spellbook', | |||
@@ -170,24 +171,15 @@ module.exports = { | |||
values: {} | |||
}, 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) { | |||
for (let p in runeSpell.properties) | |||
@@ -1,6 +1,7 @@ | |||
let generator = require('../items/generator'); | |||
let statGenerator = require('../items/generators/stats'); | |||
let skins = require('../config/skins'); | |||
const events = require('../misc/events'); | |||
const sendMessage = ({ instance, id, serverId }, color, message) => { | |||
instance.syncer.queue('onGetMessages', { | |||
@@ -263,24 +264,35 @@ module.exports = { | |||
if (!target) | |||
return; | |||
const { obj: { inventory, syncer } } = this; | |||
let targetTrade = target.trade; | |||
const item = this.obj.inventory.findItem(msg.itemId); | |||
const item = inventory.findItem(msg.itemId); | |||
if (!item) | |||
return; | |||
const oldQuantity = item.quantity; | |||
this.obj.inventory.destroyItem(msg.itemId); | |||
inventory.destroyItem(msg.itemId); | |||
if (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 name = this.obj.name; | |||
@@ -311,14 +323,16 @@ module.exports = { | |||
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) { | |||
@@ -7,6 +7,9 @@ module.exports = (crafter, recipe, { pickedItemIds = [] }) => { | |||
const result = pickedItemIds.map((pickedId, i) => { | |||
const item = items.find(f => f.id === pickedId); | |||
if (!item) | |||
return null; | |||
const isItemValid = needItems[i].allowedItemIds.includes(item.id); | |||
if (!isItemValid) | |||
@@ -20,7 +20,7 @@ module.exports = (cpnWorkbench, msg) => { | |||
return null; | |||
const { needItems = [] } = recipe; | |||
const { syncer, inventory, equipment, spellbook } = crafter; | |||
const { inventory, equipment, spellbook } = crafter; | |||
const materials = buildMaterials(crafter, recipe, msg); | |||
const pickedItems = buildPickedItems(crafter, recipe, msg); | |||
@@ -47,11 +47,8 @@ module.exports = (cpnWorkbench, msg) => { | |||
resultMsg = recipe.craftAction(crafter, pickedItems); | |||
pickedItems.forEach((p, i) => { | |||
if (!p.eq) { | |||
pickedItems.forEach(item => syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item))); | |||
if (!p.eq) | |||
return; | |||
} | |||
applyItemStats(crafter, p, true); | |||
@@ -59,8 +56,6 @@ module.exports = (cpnWorkbench, msg) => { | |||
equipment.unequip(p.id); | |||
spellbook.calcDps(); | |||
pickedItems.forEach(item => syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item))); | |||
}); | |||
equipment.unequipAttrRqrGear(); | |||
@@ -84,6 +79,8 @@ module.exports = (cpnWorkbench, msg) => { | |||
if (quantity && quantity.push) | |||
item.quantity = quantity[0] + ~~(Math.random() * (quantity[1] - quantity[0])); | |||
console.log(item); | |||
crafter.inventory.getItem(item); | |||
}); | |||
} | |||
@@ -10,14 +10,14 @@ module.exports = { | |||
type: 'herb', | |||
max: 1, | |||
cdMax: 1710 | |||
}, | |||
'Sun Carp School': { | |||
max: 900, | |||
type: 'fish', | |||
quantity: [6, 12] | |||
} | |||
}, | |||
objects: { | |||
'sun carp school': { | |||
max: 9, | |||
type: 'fish', | |||
quantity: [6, 12] | |||
}, | |||
shopestrid: { | |||
properties: { | |||
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 recipesCooking = require('./cooking'); | |||
const recipesEtching = require('./etching'); | |||
const recipesEnchanting = require('./enchanting'); | |||
let recipes = { | |||
alchemy: [ ...recipesAlchemy ], | |||
cooking: [ ...recipesCooking ], | |||
etching: [ ...recipesEtching ], | |||
enchanting: [ ...recipesEnchanting ] | |||
etching: [ ...recipesEtching ] | |||
}; | |||
module.exports = { | |||
@@ -2,7 +2,7 @@ let events = require('../misc/events'); | |||
module.exports = { | |||
init: function () { | |||
events.emit('onBeforeGetHerbConfig', this); | |||
events.emit('onBeforeGetResourceNodeConfig', this); | |||
}, | |||
Moonbell: { | |||
@@ -20,7 +20,7 @@ module.exports = { | |||
cell: 51, | |||
itemSprite: [1, 0] | |||
}, | |||
'Sun Carp': { | |||
'Sun Carp School': { | |||
sheetName: 'objects', | |||
itemSprite: [11, 2], | |||
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; | |||
}; | |||
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 = { | |||
generate: function (item, blueprint) { | |||
blueprint = blueprint || {}; | |||
@@ -111,30 +147,10 @@ module.exports = { | |||
} | |||
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) { | |||
item.spell.properties = {}; | |||
@@ -146,5 +162,7 @@ module.exports = { | |||
item.spell.properties = item.spell.properties || {}; | |||
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 pool = []; | |||
@@ -46,11 +9,9 @@ const buildPool = config => { | |||
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 = []; | |||
@@ -58,13 +19,13 @@ module.exports = (itemCount, useConfig) => { | |||
let pickName = pool[~~(Math.random() * pool.length)]; | |||
const pick = config.find(f => f.name === pickName); | |||
if (!pick) | |||
break; | |||
let item = items.find(f => f.name === pickName); | |||
if (!item) { | |||
items.push({ | |||
name: pick.name, | |||
material: true, | |||
quality: pick.quality, | |||
sprite: pick.sprite, | |||
...pick, | |||
quantity: pick.quantity || 1 | |||
}); | |||
} else | |||
@@ -10,7 +10,7 @@ const routerConfig = { | |||
dialogue: ['talk'], | |||
gatherer: ['gather'], | |||
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'], | |||
stash: ['withdraw', 'open'], | |||
trade: ['buySell'], | |||
@@ -3,14 +3,13 @@ let syncer = require('./syncer'); | |||
let objects = require('../objects/objects'); | |||
let spawners = require('./spawners'); | |||
let physics = require('./physics'); | |||
let resourceSpawner = require('./resourceSpawner'); | |||
let spellCallbacks = require('../config/spells/spellCallbacks'); | |||
let questBuilder = require('../config/quests/questBuilder'); | |||
let randomMap = require('./randomMap'); | |||
let events = require('../events/events'); | |||
let scheduler = require('../misc/scheduler'); | |||
let mail = require('../mail/mail'); | |||
let herbs = require('../config/herbs'); | |||
let resourceNodes = require('../config/resourceNodes'); | |||
let eventEmitter = require('../misc/events'); | |||
const transactions = require('../security/transactions'); | |||
@@ -25,7 +24,7 @@ module.exports = { | |||
this.zoneId = args.zoneId; | |||
spellCallbacks.init(); | |||
herbs.init(); | |||
resourceNodes.init(); | |||
map.init(args); | |||
const fakeInstance = { | |||
@@ -64,15 +63,17 @@ module.exports = { | |||
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(); | |||
}, | |||
tick: function () { | |||
eventEmitter.emitNoSticky('onBeforeZoneUpdate'); | |||
events.update(); | |||
objects.update(); | |||
resourceSpawner.update(); | |||
spawners.update(); | |||
syncer.update(); | |||
scheduler.update(); | |||
@@ -1,7 +1,6 @@ | |||
let objects = require('../objects/objects'); | |||
let physics = require('./physics'); | |||
let spawners = require('./spawners'); | |||
let resourceSpawner = require('./resourceSpawner'); | |||
let globalZone = require('../config/zoneBase'); | |||
let randomMap = require('./randomMap'); | |||
let events = require('../misc/events'); | |||
@@ -97,10 +96,6 @@ module.exports = { | |||
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'); | |||
this.mapFile = mapFile; | |||
//Fix for newer versions of Tiled | |||
@@ -208,6 +203,8 @@ module.exports = { | |||
}, | |||
build: function () { | |||
events.emit('onBeforeBuildMap', this.name, this.zone); | |||
const mapSize = { | |||
w: mapFile.width, | |||
h: mapFile.height | |||
@@ -360,6 +357,17 @@ module.exports = { | |||
} | |||
}, | |||
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 | |||
cell.properties = objectifyProperties(cell.properties); | |||
cell.polyline = cell.polyline || cell.polygon; | |||
@@ -421,9 +429,7 @@ module.exports = { | |||
}); | |||
room.exits.push(blueprint); | |||
} else if (blueprint.properties.resource) | |||
resourceSpawner.register(blueprint.properties.resource, blueprint); | |||
else { | |||
} else { | |||
blueprint.exits = []; | |||
blueprint.objects = []; | |||
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; | |||
} | |||
} | |||
} | |||
}; |