diff --git a/src/client/js/components/inventory.js b/src/client/js/components/inventory.js index df681310..a429f7ad 100644 --- a/src/client/js/components/inventory.js +++ b/src/client/js/components/inventory.js @@ -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); } diff --git a/src/client/ui/templates/inventory/inventory.js b/src/client/ui/templates/inventory/inventory.js index f3948007..f7e2b809 100644 --- a/src/client/ui/templates/inventory/inventory.js +++ b/src/client/ui/templates/inventory/inventory.js @@ -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(); diff --git a/src/server/components/auth/checkLoginRewards.js b/src/server/components/auth/checkLoginRewards.js index 57570714..a9e2b16d 100644 --- a/src/server/components/auth/checkLoginRewards.js +++ b/src/server/components/auth/checkLoginRewards.js @@ -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; } diff --git a/src/server/components/extensions/socialCommands.js b/src/server/components/extensions/socialCommands.js index 717fc289..6ef5c60b 100644 --- a/src/server/components/extensions/socialCommands.js +++ b/src/server/components/extensions/socialCommands.js @@ -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(' '); diff --git a/src/server/components/gatherer.js b/src/server/components/gatherer.js deleted file mode 100644 index 7a586d96..00000000 --- a/src/server/components/gatherer.js +++ /dev/null @@ -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); - } - } -}; diff --git a/src/server/components/inventory.js b/src/server/components/inventory.js index 4f4a22e6..9c1dac07 100644 --- a/src/server/components/inventory.js +++ b/src/server/components/inventory.js @@ -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)) diff --git a/src/server/components/resourceNode.js b/src/server/components/resourceNode.js deleted file mode 100644 index a380d5fa..00000000 --- a/src/server/components/resourceNode.js +++ /dev/null @@ -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 - }; - } -}; diff --git a/src/server/components/spellbook.js b/src/server/components/spellbook.js index b01b8563..6cbb211b 100644 --- a/src/server/components/spellbook.js +++ b/src/server/components/spellbook.js @@ -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) diff --git a/src/server/components/trade.js b/src/server/components/trade.js index ad9bd7f0..f9cc2ac8 100644 --- a/src/server/components/trade.js +++ b/src/server/components/trade.js @@ -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) { diff --git a/src/server/components/workbench/buildPickedItems.js b/src/server/components/workbench/buildPickedItems.js index 0ca9edcf..5699005d 100644 --- a/src/server/components/workbench/buildPickedItems.js +++ b/src/server/components/workbench/buildPickedItems.js @@ -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) diff --git a/src/server/components/workbench/craft.js b/src/server/components/workbench/craft.js index 8c817287..59787fde 100644 --- a/src/server/components/workbench/craft.js +++ b/src/server/components/workbench/craft.js @@ -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); }); } diff --git a/src/server/config/maps/fjolarok/map.json b/src/server/config/maps/fjolarok/map.json index abbe9045..7076ed4c 100644 --- a/src/server/config/maps/fjolarok/map.json +++ b/src/server/config/maps/fjolarok/map.json @@ -3294,178 +3294,178 @@ "y":1584 }, { - "height":48, - "id":638, - "name":"sun carp school", + "height":16, + "id":652, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":24, - "x":1176, - "y":336 + "width":96, + "x":512, + "y":1520 }, { - "height":48, - "id":639, - "name":"sun carp school", + "height":16, + "id":675, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":32, - "x":952, - "y":592 + "width":96, + "x":608, + "y":1552 }, { - "height":40, - "id":640, - "name":"sun carp school", + "height":16, + "id":693, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":48, - "x":1104, - "y":1072 + "width":96, + "x":224, + "y":1536 }, { - "height":24, - "id":641, - "name":"sun carp school", + "height":16, + "id":711, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":48, - "x":1096, - "y":1160 + "width":96, + "x":224, + "y":1568 }, { - "height":40, - "id":642, - "name":"sun carp school", + "height":16, + "id":712, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":48, - "x":872, - "y":1192 + "width":96, + "x":224, + "y":1552 }, { - "height":32, - "id":643, - "name":"sun carp school", + "height":16, + "id":763, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":40, - "x":848, - "y":1088 + "width":96, + "x":608, + "y":1536 }, { - "height":40, - "id":645, - "name":"sun carp school", + "height":16, + "id":764, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":40, - "x":776, - "y":584 + "width":96, + "x":224, + "y":1584 }, { - "height":40, - "id":646, - "name":"sun carp school", + "height":16, + "id":777, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":32, - "x":648, - "y":600 + "width":96, + "x":728, + "y":1584 }, { - "height":32, - "id":649, - "name":"sun carp school", + "height":16, + "id":785, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":48, - "x":176, - "y":1184 + "width":96, + "x":128, + "y":1584 }, { - "height":32, - "id":651, - "name":"sun carp school", + "height":16, + "id":786, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":24, - "x":608, - "y":1048 + "width":96, + "x":128, + "y":1568 }, { "height":16, - "id":652, + "id":787, "name":"", "properties":[ { @@ -3477,148 +3477,148 @@ "type":"", "visible":true, "width":96, - "x":512, - "y":1520 + "x":128, + "y":1552 }, { - "height":48, - "id":655, - "name":"sun carp school", + "height":16, + "id":790, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":24, - "x":1152, - "y":336 + "width":96, + "x":128, + "y":1536 }, { - "height":48, - "id":656, - "name":"sun carp school", + "height":16, + "id":791, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":24, - "x":1152, - "y":392 + "width":96, + "x":32, + "y":1536 }, { - "height":48, - "id":657, - "name":"sun carp school", + "height":16, + "id":792, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":24, - "x":1176, - "y":392 + "width":96, + "x":32, + "y":1552 }, { - "height":48, - "id":658, - "name":"sun carp school", + "height":16, + "id":793, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":56, - "x":1200, - "y":360 + "width":96, + "x":32, + "y":1568 }, { - "height":40, - "id":668, - "name":"sun carp school", + "height":16, + "id":802, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":64, - "x":152, - "y":1256 + "width":96, + "x":32, + "y":1584 }, { - "height":24, - "id":671, - "name":"sun carp school", + "height":16, + "id":830, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":48, - "x":488, - "y":1048 + "width":96, + "x":32, + "y":1520 }, { - "height":24, - "id":672, - "name":"sun carp school", + "height":16, + "id":831, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":48, - "x":416, - "y":904 + "width":96, + "x":128, + "y":1520 }, { - "height":48, - "id":673, - "name":"sun carp school", + "height":16, + "id":835, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":32, - "x":248, - "y":1096 + "width":96, + "x":32, + "y":1504 }, { "height":16, - "id":675, + "id":836, "name":"", "properties":[ { @@ -3630,12 +3630,12 @@ "type":"", "visible":true, "width":96, - "x":608, - "y":1552 + "x":32, + "y":1488 }, { "height":16, - "id":693, + "id":837, "name":"", "properties":[ { @@ -3647,569 +3647,394 @@ "type":"", "visible":true, "width":96, - "x":224, - "y":1536 + "x":32, + "y":1472 }, { - "height":24, - "id":694, - "name":"sun carp school", + "height":16, + "id":851, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":32, - "x":680, - "y":896 + "width":96, + "x":824, + "y":1584 }, { - "height":40, - "id":695, - "name":"sun carp school", + "height":16, + "id":934, + "name":"", "properties":[ { - "name":"resource", + "name":"mapping", "type":"string", - "value":"Sun Carp" + "value":"1" }], "rotation":0, "type":"", "visible":true, - "width":24, - "x":712, - "y":936 - }, + "width":96, + "x":32, + "y":1456 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":31, + "name":"resources", + "objects":[ { - "height":40, - "id":696, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":48, + "id":991, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, "width":24, - "x":736, - "y":864 + "x":1176, + "y":336 }, { - "height":24, - "id":697, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":48, + "id":992, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, "width":32, - "x":648, - "y":1088 + "x":952, + "y":592 }, { - "height":16, - "id":711, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":993, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":224, - "y":1568 + "width":48, + "x":1104, + "y":1072 }, { - "height":16, - "id":712, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":24, + "id":994, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":224, - "y":1552 + "width":48, + "x":1096, + "y":1160 }, { - "height":16, - "id":763, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":995, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":608, - "y":1536 + "width":48, + "x":872, + "y":1192 }, { - "height":16, - "id":764, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":32, + "id":996, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":224, - "y":1584 + "width":40, + "x":848, + "y":1088 }, { - "height":16, - "id":777, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":997, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":728, - "y":1584 + "width":40, + "x":776, + "y":584 }, { - "height":16, - "id":785, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":998, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":128, - "y":1584 + "width":32, + "x":648, + "y":600 }, { - "height":16, - "id":786, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":32, + "id":999, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":128, - "y":1568 + "width":48, + "x":176, + "y":1184 }, { - "height":16, - "id":787, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":32, + "id":1000, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":128, - "y":1552 + "width":24, + "x":608, + "y":1048 }, { - "height":16, - "id":790, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":48, + "id":1001, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":128, - "y":1536 + "width":24, + "x":1152, + "y":336 }, { - "height":16, - "id":791, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":48, + "id":1002, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1536 + "width":24, + "x":1152, + "y":392 }, { - "height":16, - "id":792, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":48, + "id":1003, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1552 + "width":24, + "x":1176, + "y":392 }, { - "height":16, - "id":793, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":48, + "id":1004, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1568 + "width":56, + "x":1200, + "y":360 }, { - "height":32, - "id":794, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":40, + "id":1005, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":8, - "x":1048, - "y":384 + "width":64, + "x":152, + "y":1256 }, { - "height":16, - "id":802, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":24, + "id":1006, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1584 + "width":48, + "x":488, + "y":1048 }, { - "height":40, - "id":808, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":24, + "id":1007, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":32, - "x":584, - "y":568 + "width":48, + "x":416, + "y":904 }, { - "height":40, - "id":809, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":48, + "id":1008, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":24, - "x":456, - "y":528 + "width":32, + "x":248, + "y":1096 }, { "height":24, - "id":810, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "id":1009, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":40, - "x":360, - "y":408 + "width":32, + "x":680, + "y":896 }, { - "height":24, - "id":811, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":40, + "id":1010, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":48, - "x":376, - "y":336 + "width":24, + "x":712, + "y":936 }, { "height":40, - "id":812, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "id":1011, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":32, - "x":464, - "y":256 + "width":24, + "x":736, + "y":864 }, { - "height":40, - "id":813, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":24, + "id":1012, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, "width":32, - "x":944, - "y":312 + "x":648, + "y":1088 }, { - "height":40, - "id":814, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "height":32, + "id":1013, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":24, - "x":1056, - "y":224 + "width":8, + "x":1048, + "y":384 }, { "height":40, - "id":817, - "name":"sun carp school", - "properties":[ - { - "name":"resource", - "type":"string", - "value":"Sun Carp" - }], + "id":1014, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, "width":32, - "x":984, - "y":496 + "x":584, + "y":568 }, { - "height":16, - "id":830, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":1015, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1520 + "width":24, + "x":456, + "y":528 }, { - "height":16, - "id":831, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":24, + "id":1016, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":128, - "y":1520 + "width":40, + "x":360, + "y":408 }, { - "height":16, - "id":835, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":24, + "id":1017, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1504 + "width":48, + "x":376, + "y":336 }, { - "height":16, - "id":836, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":1018, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1488 + "width":32, + "x":464, + "y":256 }, { - "height":16, - "id":837, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":1019, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1472 + "width":32, + "x":944, + "y":312 }, { - "height":16, - "id":851, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":1020, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":824, - "y":1584 + "width":24, + "x":1056, + "y":224 }, { - "height":16, - "id":934, - "name":"", - "properties":[ - { - "name":"mapping", - "type":"string", - "value":"1" - }], + "height":40, + "id":1021, + "name":"Sun Carp School", "rotation":0, "type":"", "visible":true, - "width":96, - "x":32, - "y":1456 + "width":32, + "x":984, + "y":496 }], "opacity":1, "type":"objectgroup", @@ -4217,8 +4042,8 @@ "x":0, "y":0 }], - "nextlayerid":31, - "nextobjectid":991, + "nextlayerid":32, + "nextobjectid":1022, "orientation":"orthogonal", "properties":[ { diff --git a/src/server/config/maps/fjolarok/zone.js b/src/server/config/maps/fjolarok/zone.js index 79606c6f..d2ab7577 100644 --- a/src/server/config/maps/fjolarok/zone.js +++ b/src/server/config/maps/fjolarok/zone.js @@ -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: { diff --git a/src/server/config/recipes/enchanting.js b/src/server/config/recipes/enchanting.js deleted file mode 100644 index 14ed50f1..00000000 --- a/src/server/config/recipes/enchanting.js +++ /dev/null @@ -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 - ] -}]; diff --git a/src/server/config/recipes/enchanting/calculateAugmentMaterials.js b/src/server/config/recipes/enchanting/calculateAugmentMaterials.js deleted file mode 100644 index 8d854a1b..00000000 --- a/src/server/config/recipes/enchanting/calculateAugmentMaterials.js +++ /dev/null @@ -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; -}; diff --git a/src/server/config/recipes/enchanting/craftActions/augment.js b/src/server/config/recipes/enchanting/craftActions/augment.js deleted file mode 100644 index bc8c841f..00000000 --- a/src/server/config/recipes/enchanting/craftActions/augment.js +++ /dev/null @@ -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; -}; diff --git a/src/server/config/recipes/enchanting/craftActions/reforge.js b/src/server/config/recipes/enchanting/craftActions/reforge.js deleted file mode 100644 index 2459c122..00000000 --- a/src/server/config/recipes/enchanting/craftActions/reforge.js +++ /dev/null @@ -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 }; -}; diff --git a/src/server/config/recipes/enchanting/craftActions/relevel.js b/src/server/config/recipes/enchanting/craftActions/relevel.js deleted file mode 100644 index 757752e7..00000000 --- a/src/server/config/recipes/enchanting/craftActions/relevel.js +++ /dev/null @@ -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 }; -}; diff --git a/src/server/config/recipes/enchanting/craftActions/reroll.js b/src/server/config/recipes/enchanting/craftActions/reroll.js deleted file mode 100644 index 675548fd..00000000 --- a/src/server/config/recipes/enchanting/craftActions/reroll.js +++ /dev/null @@ -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' }; -}; diff --git a/src/server/config/recipes/enchanting/craftActions/reslot.js b/src/server/config/recipes/enchanting/craftActions/reslot.js deleted file mode 100644 index 41cb480a..00000000 --- a/src/server/config/recipes/enchanting/craftActions/reslot.js +++ /dev/null @@ -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 }; -}; diff --git a/src/server/config/recipes/enchanting/craftActions/scour.js b/src/server/config/recipes/enchanting/craftActions/scour.js deleted file mode 100644 index 32913e07..00000000 --- a/src/server/config/recipes/enchanting/craftActions/scour.js +++ /dev/null @@ -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; -}; diff --git a/src/server/config/recipes/recipes.js b/src/server/config/recipes/recipes.js index 43df7935..6e556e0f 100644 --- a/src/server/config/recipes/recipes.js +++ b/src/server/config/recipes/recipes.js @@ -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 = { diff --git a/src/server/config/herbs.js b/src/server/config/resourceNodes.js similarity index 87% rename from src/server/config/herbs.js rename to src/server/config/resourceNodes.js index 790c0597..ddffa61a 100644 --- a/src/server/config/herbs.js +++ b/src/server/config/resourceNodes.js @@ -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, diff --git a/src/server/items/config/materials.js b/src/server/items/config/materials.js deleted file mode 100644 index 1aac97b6..00000000 --- a/src/server/items/config/materials.js +++ /dev/null @@ -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 - } -}; diff --git a/src/server/items/generators/spellbook.js b/src/server/items/generators/spellbook.js index 8e983ffc..240f74b9 100644 --- a/src/server/items/generators/spellbook.js +++ b/src/server/items/generators/spellbook.js @@ -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 }; diff --git a/src/server/items/salvager.js b/src/server/items/salvager.js deleted file mode 100644 index bc0b2233..00000000 --- a/src/server/items/salvager.js +++ /dev/null @@ -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; - } -}; diff --git a/src/server/misc/rewardGenerator.js b/src/server/misc/rewardGenerator.js index 1feafb5e..9efbf1e1 100644 --- a/src/server/misc/rewardGenerator.js +++ b/src/server/misc/rewardGenerator.js @@ -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 diff --git a/src/server/security/routerConfig.js b/src/server/security/routerConfig.js index e218aebc..39ee8075 100644 --- a/src/server/security/routerConfig.js +++ b/src/server/security/routerConfig.js @@ -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'], diff --git a/src/server/world/instancer.js b/src/server/world/instancer.js index 9a2933ca..bebd2399 100644 --- a/src/server/world/instancer.js +++ b/src/server/world/instancer.js @@ -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(); diff --git a/src/server/world/map.js b/src/server/world/map.js index 44e6c143..8ffddbeb 100644 --- a/src/server/world/map.js +++ b/src/server/world/map.js @@ -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); diff --git a/src/server/world/resourceSpawner.js b/src/server/world/resourceSpawner.js deleted file mode 100644 index 0449f784..00000000 --- a/src/server/world/resourceSpawner.js +++ /dev/null @@ -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; - } - } - } -};