@@ -179,66 +179,8 @@ module.exports = { | |||||
vikar: { | vikar: { | ||||
1: { | 1: { | ||||
msg: [{ | msg: [{ | ||||
msg: 'Is there anything I can help you with today?', | |||||
options: [1.1] | |||||
}], | |||||
options: { | |||||
1.1: { | |||||
msg: 'I want to hand in some cards.', | |||||
prereq: function (obj) { | |||||
let fullSet = obj.inventory.items.find(i => ((i.setSize) && (i.setSize <= i.quantity))); | |||||
return !!fullSet; | |||||
}, | |||||
goto: 'tradeCards' | |||||
} | |||||
} | |||||
}, | |||||
tradeCards: { | |||||
msg: [{ | |||||
msg: '', | |||||
msg: 'How may I help you today?', | |||||
options: [] | options: [] | ||||
}], | |||||
method: function (obj) { | |||||
let inventory = obj.inventory; | |||||
let items = inventory.items; | |||||
let sets = items.filter(function (i) { | |||||
return ( | |||||
(i.type === 'Reward Card') && | |||||
(i.quantity >= i.setSize) | |||||
); | |||||
}); | |||||
if (sets.length === 0) | |||||
return 'Sorry, you don\'t have any completed sets.'; | |||||
sets.forEach(function (s) { | |||||
obj.instance.eventEmitter.emit('onGetCardSetReward', s.name, obj); | |||||
inventory.destroyItem(s.id, s.setSize); | |||||
}); | |||||
return 'Thank you.'; | |||||
} | |||||
}, | |||||
tradeBuy: { | |||||
cpn: 'trade', | |||||
method: 'startBuy', | |||||
args: [{ | |||||
targetName: 'vikar' | |||||
}] | |||||
}, | |||||
tradeSell: { | |||||
cpn: 'trade', | |||||
method: 'startSell', | |||||
args: [{ | |||||
targetName: 'vikar' | |||||
}] | |||||
}, | |||||
tradeBuyback: { | |||||
cpn: 'trade', | |||||
method: 'startBuyback', | |||||
args: [{ | |||||
targetName: 'vikar' | |||||
}] | }] | ||||
} | } | ||||
}, | }, | ||||
@@ -1,4 +1,12 @@ | |||||
{ "backgroundcolor":"#32222e", | { "backgroundcolor":"#32222e", | ||||
"compressionlevel":-1, | |||||
"editorsettings": | |||||
{ | |||||
"export": | |||||
{ | |||||
"target":"." | |||||
} | |||||
}, | |||||
"height":120, | "height":120, | ||||
"infinite":false, | "infinite":false, | ||||
"layers":[ | "layers":[ | ||||
@@ -2043,7 +2051,7 @@ | |||||
"type":"", | "type":"", | ||||
"visible":true, | "visible":true, | ||||
"width":8, | "width":8, | ||||
"x":568, | |||||
"x":528, | |||||
"y":736 | "y":736 | ||||
}, | }, | ||||
{ | { | ||||
@@ -2175,8 +2183,8 @@ | |||||
"type":"", | "type":"", | ||||
"visible":true, | "visible":true, | ||||
"width":8, | "width":8, | ||||
"x":480, | |||||
"y":744 | |||||
"x":464, | |||||
"y":752 | |||||
}, | }, | ||||
{ | { | ||||
"gid":273, | "gid":273, | ||||
@@ -2307,7 +2315,7 @@ | |||||
"type":"", | "type":"", | ||||
"visible":true, | "visible":true, | ||||
"width":8, | "width":8, | ||||
"x":536, | |||||
"x":520, | |||||
"y":808 | "y":808 | ||||
}, | }, | ||||
{ | { | ||||
@@ -2319,8 +2327,20 @@ | |||||
"type":"", | "type":"", | ||||
"visible":true, | "visible":true, | ||||
"width":8, | "width":8, | ||||
"x":600, | |||||
"y":776 | |||||
"x":592, | |||||
"y":720 | |||||
}, | |||||
{ | |||||
"gid":273, | |||||
"height":8, | |||||
"id":1291, | |||||
"name":"Rat", | |||||
"rotation":0, | |||||
"type":"", | |||||
"visible":true, | |||||
"width":8, | |||||
"x":560, | |||||
"y":824 | |||||
}], | }], | ||||
"opacity":1, | "opacity":1, | ||||
"type":"objectgroup", | "type":"objectgroup", | ||||
@@ -2329,7 +2349,7 @@ | |||||
"y":0 | "y":0 | ||||
}], | }], | ||||
"nextlayerid":60, | "nextlayerid":60, | ||||
"nextobjectid":1291, | |||||
"nextobjectid":1292, | |||||
"orientation":"orthogonal", | "orientation":"orthogonal", | ||||
"properties":[ | "properties":[ | ||||
{ | { | ||||
@@ -2338,7 +2358,7 @@ | |||||
"value":"[{\"x\":97,\"y\":87}]" | "value":"[{\"x\":97,\"y\":87}]" | ||||
}], | }], | ||||
"renderorder":"right-down", | "renderorder":"right-down", | ||||
"tiledversion":"1.2.5", | |||||
"tiledversion":"1.3.3", | |||||
"tileheight":8, | "tileheight":8, | ||||
"tilesets":[ | "tilesets":[ | ||||
{ | { | ||||
@@ -1,57 +1,37 @@ | |||||
let itemGenerator = require('../../items/generator'); | |||||
let config = { | let config = { | ||||
'Runecrafter\'s Toil': { | 'Runecrafter\'s Toil': { | ||||
chance: 0.025, | chance: 0.025, | ||||
reward: 'Level 10 Rune', | reward: 'Level 10 Rune', | ||||
setSize: 3, | |||||
mobLevel: [3, 100] | |||||
mobLevel: [8, 12] | |||||
}, | }, | ||||
'Godly Promise': { | 'Godly Promise': { | ||||
chance: 0.01, | chance: 0.01, | ||||
reward: 'Level 15 Legendary Weapon', | reward: 'Level 15 Legendary Weapon', | ||||
setSize: 6, | |||||
zone: 'sewer' | zone: 'sewer' | ||||
}, | }, | ||||
'The Other Heirloom': { | 'The Other Heirloom': { | ||||
chance: 0.02, | chance: 0.02, | ||||
reward: 'Perfect Level 10 Ring', | reward: 'Perfect Level 10 Ring', | ||||
setSize: 3, | |||||
mobName: 'flamingo' | mobName: 'flamingo' | ||||
}, | }, | ||||
'Benthic Incantation': { | 'Benthic Incantation': { | ||||
chance: 0.015, | chance: 0.015, | ||||
reward: 'Princess Morgawsa\'s Trident', | reward: 'Princess Morgawsa\'s Trident', | ||||
setSize: 12, | |||||
zone: 'estuary' | zone: 'estuary' | ||||
}, | }, | ||||
'Fangs of Fury': { | 'Fangs of Fury': { | ||||
chance: 0.05, | chance: 0.05, | ||||
reward: 'Steelclaw\'s Bite', | reward: 'Steelclaw\'s Bite', | ||||
setSize: 20, | |||||
mobName: 'stinktooth' | mobName: 'stinktooth' | ||||
}, | }, | ||||
'Tradesman\'s Pride': { | 'Tradesman\'s Pride': { | ||||
chance: 0.007, | chance: 0.007, | ||||
reward: 'Five Random Idols', | |||||
setSize: 10 | |||||
reward: 'Five Random Idols' | |||||
} | } | ||||
}; | }; | ||||
module.exports = { | module.exports = { | ||||
init: function () { | |||||
}, | |||||
fixCard: function (card) { | |||||
let template = config[card.name]; | |||||
if (!template) | |||||
return; | |||||
card.setSize = template.setSize; | |||||
}, | |||||
getCard: function (looter, mob) { | |||||
getCard: function (modFolderPath, looter, mob) { | |||||
let pool = []; | let pool = []; | ||||
let mobLevel = mob.stats.values.level; | let mobLevel = mob.stats.values.level; | ||||
@@ -96,147 +76,14 @@ module.exports = { | |||||
let builtCard = { | let builtCard = { | ||||
name: pickName, | name: pickName, | ||||
spritesheet: pick.spritesheet || `${this.folderName}/images/items.png`, | |||||
type: 'Reward Card', | |||||
description: 'Reward: ' + pick.reward, | |||||
spritesheet: pick.spritesheet || `${modFolderPath}/images/items.png`, | |||||
type: 'Gambler\'s Card', | |||||
noSalvage: true, | noSalvage: true, | ||||
sprite: pick.sprite || [0, 0], | sprite: pick.sprite || [0, 0], | ||||
quantity: 1, | quantity: 1, | ||||
quality: pick.quality || 1, | |||||
setSize: pick.setSize | |||||
quality: pick.quality || 1 | |||||
}; | }; | ||||
return builtCard; | return builtCard; | ||||
}, | |||||
getReward: function (looter, set) { | |||||
let configs = extend({}, config); | |||||
looter.instance.eventEmitter.emit('onBeforeGetCardsConfig', configs); | |||||
let reward = configs[set].reward; | |||||
let msg = { | |||||
reward: reward, | |||||
handler: this.rewards[reward] | |||||
}; | |||||
looter.instance.eventEmitter.emit('onBeforeGetCardReward', msg); | |||||
return msg.handler(looter); | |||||
}, | |||||
rewards: { | |||||
'Level 10 Rune': function () { | |||||
return itemGenerator.generate({ | |||||
level: 10, | |||||
spell: true | |||||
}); | |||||
}, | |||||
'Level 15 Legendary Weapon': function () { | |||||
let slot = ['oneHanded', 'twoHanded'][~~(Math.random() * 2)]; | |||||
return itemGenerator.generate({ | |||||
level: 15, | |||||
quality: 4, | |||||
noSpell: true, | |||||
slot: slot | |||||
}); | |||||
}, | |||||
'Perfect Level 10 Ring': function () { | |||||
return itemGenerator.generate({ | |||||
level: 10, | |||||
noSpell: true, | |||||
quality: 1, | |||||
perfection: 1, | |||||
slot: 'finger' | |||||
}); | |||||
}, | |||||
"Princess Morgawsa's Trident": function () { | |||||
return itemGenerator.generate({ | |||||
name: 'Princess Morgawsa\'s Trident', | |||||
level: [18, 20], | |||||
attrRequire: 'int', | |||||
quality: 4, | |||||
noSpell: true, | |||||
slot: 'twoHanded', | |||||
sprite: [0, 0], | |||||
spritesheet: '../../../images/legendaryItems.png', | |||||
type: 'Trident', | |||||
description: 'Summoned from the ancient depths of the ocean by the Benthic Incantation.', | |||||
stats: ['elementFrostPercent', 'elementFrostPercent', 'elementFrostPercent'], | |||||
effects: [{ | |||||
type: 'freezeOnHit', | |||||
rolls: { | |||||
i_chance: [2, 5], | |||||
i_duration: [2, 4] | |||||
} | |||||
}], | |||||
spellName: 'projectile', | |||||
spellConfig: { | |||||
statType: 'int', | |||||
statMult: 1, | |||||
element: 'arcane', | |||||
auto: true, | |||||
cdMax: 7, | |||||
castTimeMax: 0, | |||||
manaCost: 0, | |||||
range: 9, | |||||
random: { | |||||
damage: [1.65, 10.81] | |||||
} | |||||
} | |||||
}); | |||||
}, | |||||
'Five Random Idols': function () { | |||||
let result = []; | |||||
for (let i = 0; i < 5; i++) { | |||||
result.push(itemGenerator.generate({ | |||||
currency: true | |||||
})); | |||||
} | |||||
return result; | |||||
}, | |||||
"Steelclaw's Bite": function () { | |||||
return itemGenerator.generate({ | |||||
name: 'Steelclaw\'s Bite', | |||||
level: [18, 20], | |||||
attrRequire: 'dex', | |||||
quality: 4, | |||||
noSpell: true, | |||||
slot: 'oneHanded', | |||||
sprite: [1, 0], | |||||
spritesheet: '../../../images/legendaryItems.png', | |||||
type: 'Curved Dagger', | |||||
description: 'The blade seems to be made of some kind of bone and steel alloy.', | |||||
stats: ['dex', 'dex', 'addCritMultiplier', 'addCritMultiplier'], | |||||
effects: [{ | |||||
type: 'damageSelf', | |||||
properties: { | |||||
element: 'poison' | |||||
}, | |||||
rolls: { | |||||
i_percentage: [8, 22] | |||||
} | |||||
}, { | |||||
type: 'alwaysCrit', | |||||
rolls: {} | |||||
}], | |||||
spellName: 'melee', | |||||
spellConfig: { | |||||
statType: 'dex', | |||||
statMult: 1, | |||||
cdMax: 3, | |||||
castTimeMax: 0, | |||||
useWeaponRange: true, | |||||
random: { | |||||
damage: [0.88, 5.79] | |||||
} | |||||
} | |||||
}); | |||||
} | |||||
} | } | ||||
}; | }; |
@@ -0,0 +1,17 @@ | |||||
module.exports = { | |||||
dealer: { | |||||
zoneName: 'sewer', | |||||
pos: { | |||||
x: 74, | |||||
y: 99 | |||||
}, | |||||
zoneConfig: { | |||||
name: 'Shady Dealer', | |||||
cell: 0, | |||||
sheetName: '$MODFOLDER$/images/mobs.png', | |||||
components: { | |||||
cpnWorkbench: { type: 'gambling' } | |||||
} | |||||
} | |||||
} | |||||
}; |
@@ -1,18 +1,52 @@ | |||||
let cards = require('./cards'); | |||||
const cardRecipes = require('./recipes/recipes'); | |||||
const cards = require('./cards'); | |||||
const { dealer } = require('./config'); | |||||
module.exports = { | module.exports = { | ||||
name: 'Feature: Cards', | name: 'Feature: Cards', | ||||
extraScripts: [ | |||||
'cards' | |||||
], | |||||
init: function () { | init: function () { | ||||
cards.init(); | |||||
this.events.on('onBeforeGetClientConfig', this.onBeforeGetClientConfig.bind(this)); | |||||
this.events.on('onBeforeDropBag', this.onBeforeDropBag.bind(this)); | this.events.on('onBeforeDropBag', this.onBeforeDropBag.bind(this)); | ||||
this.events.on('onGetCardSetReward', this.onGetCardSetReward.bind(this)); | |||||
this.events.on('onBeforeGetItem', this.onBeforeGetItem.bind(this)); | |||||
this.events.on('onBeforeGetRecipes', this.onBeforeGetRecipes.bind(this)); | |||||
this.events.on('onAfterGetZone', this.onAfterGetZone.bind(this)); | |||||
this.events.on('onAfterGetLayerObjects', this.onAfterGetLayerObjects.bind(this)); | |||||
}, | |||||
onBeforeGetClientConfig: function (config) { | |||||
config.textureList.push(`${this.folderName}/images/mobs.png`); | |||||
}, | |||||
onAfterGetZone: function (zoneName, config) { | |||||
const { zoneName: dealerZoneName, zoneConfig } = dealer; | |||||
const dealerName = zoneConfig.name.toLowerCase(); | |||||
if (zoneName !== dealerZoneName) | |||||
return; | |||||
zoneConfig.sheetName = zoneConfig.sheetName.replace('$MODFOLDER$', this.folderName); | |||||
config.objects[dealerName] = zoneConfig; | |||||
}, | |||||
onAfterGetLayerObjects: function ({ map, layer, objects, mapScale }) { | |||||
const { zoneName: dealerZoneName, pos: { x, y }, zoneConfig: { name } } = dealer; | |||||
if (map !== dealerZoneName || layer !== 'objects') | |||||
return; | |||||
objects.push({ | |||||
name, | |||||
x: x * mapScale, | |||||
y: y * mapScale, | |||||
height: 8, | |||||
width: 8, | |||||
visible: true | |||||
}); | |||||
}, | |||||
onBeforeGetRecipes: function (recipes) { | |||||
recipes.gambling = cardRecipes; | |||||
}, | }, | ||||
onBeforeDropBag: function (dropper, items, looter) { | onBeforeDropBag: function (dropper, items, looter) { | ||||
@@ -27,25 +61,10 @@ module.exports = { | |||||
if (Math.random() >= dropEvent.chanceMultiplier) | if (Math.random() >= dropEvent.chanceMultiplier) | ||||
return; | return; | ||||
let res = cards.getCard(looter, dropper); | |||||
let res = cards.getCard(this.folderName, looter, dropper); | |||||
if (!res) | if (!res) | ||||
return; | return; | ||||
items.push(res); | items.push(res); | ||||
}, | |||||
onBeforeGetItem: function (item, obj) { | |||||
if ((!obj.player) && (item.type !== 'Reward Card')) | |||||
return; | |||||
cards.fixCard(item); | |||||
}, | |||||
onGetCardSetReward: function (set, obj) { | |||||
let reward = cards.getReward(obj, set); | |||||
if (!reward.push) | |||||
reward = [reward]; | |||||
reward.forEach(r => obj.inventory.getItem(r, false, false, false, true)); | |||||
} | } | ||||
}; | }; |
@@ -0,0 +1,17 @@ | |||||
let itemGenerator = require('../../../../items/generator'); | |||||
module.exports = ({ level, quality, slot, perfection }, crafter) => { | |||||
const result = itemGenerator.generate({ | |||||
level, | |||||
noSpell: true, | |||||
quality, | |||||
perfection, | |||||
slot | |||||
}); | |||||
crafter.inventory.getItem(result, false, false, false, true); | |||||
const msg = `You received: ${result.name}`; | |||||
return { msg }; | |||||
}; |
@@ -0,0 +1,18 @@ | |||||
let itemGenerator = require('../../../../items/generator'); | |||||
module.exports = ({ rolls, quantity = 1 }, crafter) => { | |||||
let quantityReceived = rolls * quantity; | |||||
for (let i = 0; i < rolls; i++) { | |||||
const idol = itemGenerator.generate({ | |||||
currency: true, | |||||
quantity | |||||
}); | |||||
crafter.inventory.getItem(idol, false, false, false, true); | |||||
} | |||||
const msg = `You received ${quantityReceived} idols`; | |||||
return { msg }; | |||||
}; |
@@ -0,0 +1,14 @@ | |||||
let itemGenerator = require('../../../../items/generator'); | |||||
module.exports = ({ level }, crafter) => { | |||||
const result = itemGenerator.generate({ | |||||
level, | |||||
spell: true | |||||
}); | |||||
crafter.inventory.getItem(result, false, false, false, true); | |||||
const msg = `You received: ${result.name}`; | |||||
return { msg }; | |||||
}; |
@@ -0,0 +1,17 @@ | |||||
let itemGenerator = require('../../../../items/generator'); | |||||
module.exports = (config, crafter) => { | |||||
const slot = config.slot || ['oneHanded', 'twoHanded'][~~(Math.random() * 2)]; | |||||
const result = itemGenerator.generate({ | |||||
noSpell: true, | |||||
slot, | |||||
...config | |||||
}); | |||||
crafter.inventory.getItem(result, false, false, false, true); | |||||
const msg = `You received: ${result.name}`; | |||||
return { msg }; | |||||
}; |
@@ -0,0 +1,132 @@ | |||||
const rune = require('./craftActions/rune'); | |||||
const weapon = require('./craftActions/weapon'); | |||||
const armor = require('./craftActions/armor'); | |||||
const idol = require('./craftActions/idol'); | |||||
module.exports = [{ | |||||
name: 'Level 10 Rune', | |||||
description: '', | |||||
materials: [{ | |||||
name: 'Runecrafter\'s Toil', | |||||
quantity: 3 | |||||
}], | |||||
craftAction: rune.bind(null, { | |||||
level: 10 | |||||
}) | |||||
}, { | |||||
name: 'Legendary Level 15 Weapon', | |||||
description: '', | |||||
materials: [{ | |||||
name: 'Godly Promise', | |||||
quantity: 6 | |||||
}], | |||||
craftAction: weapon.bind(null, { | |||||
level: 15, | |||||
quality: 4 | |||||
}) | |||||
}, { | |||||
name: 'Perfect Level 10 Ring', | |||||
description: '', | |||||
materials: [{ | |||||
name: 'The Other Heirloom', | |||||
quantity: 3 | |||||
}], | |||||
craftAction: armor.bind(null, { | |||||
level: 10, | |||||
slot: 'finger', | |||||
perfection: 1, | |||||
quality: 1 | |||||
}) | |||||
}, { | |||||
name: '5 Random Idols', | |||||
description: '', | |||||
materials: [{ | |||||
name: 'Tradesman\'s Pride', | |||||
quantity: 10 | |||||
}], | |||||
craftAction: idol.bind(null, { | |||||
rolls: 5 | |||||
}) | |||||
}, { | |||||
name: 'Princess Morgawsa\'s Trident', | |||||
description: '', | |||||
materials: [{ | |||||
name: 'Benthic Incantation', | |||||
quantity: 12 | |||||
}], | |||||
craftAction: weapon.bind(null, { | |||||
name: 'Princess Morgawsa\'s Trident', | |||||
level: [18, 20], | |||||
attrRequire: 'int', | |||||
quality: 4, | |||||
slot: 'twoHanded', | |||||
sprite: [0, 0], | |||||
spritesheet: '../../../images/legendaryItems.png', | |||||
type: 'Trident', | |||||
description: 'Summoned from the ancient depths of the ocean by the Benthic Incantation.', | |||||
stats: ['elementFrostPercent', 'elementFrostPercent', 'elementFrostPercent'], | |||||
effects: [{ | |||||
type: 'freezeOnHit', | |||||
rolls: { | |||||
i_chance: [2, 5], | |||||
i_duration: [2, 4] | |||||
} | |||||
}], | |||||
spellName: 'projectile', | |||||
spellConfig: { | |||||
statType: 'int', | |||||
statMult: 1, | |||||
element: 'arcane', | |||||
auto: true, | |||||
cdMax: 7, | |||||
castTimeMax: 0, | |||||
manaCost: 0, | |||||
range: 9, | |||||
random: { | |||||
damage: [1.65, 10.81] | |||||
} | |||||
} | |||||
}) | |||||
}, { | |||||
name: 'Steelclaw\'s Bite', | |||||
description: '', | |||||
materials: [{ | |||||
name: 'Fangs of Fury', | |||||
quantity: 20 | |||||
}], | |||||
craftAction: weapon.bind(null, { | |||||
name: 'Steelclaw\'s Bite', | |||||
level: [18, 20], | |||||
attrRequire: 'dex', | |||||
quality: 4, | |||||
slot: 'oneHanded', | |||||
sprite: [1, 0], | |||||
spritesheet: '../../../images/legendaryItems.png', | |||||
type: 'Curved Dagger', | |||||
description: 'The blade seems to be made of some kind of bone and steel alloy.', | |||||
stats: ['dex', 'dex', 'addCritMultiplier', 'addCritMultiplier'], | |||||
effects: [{ | |||||
type: 'damageSelf', | |||||
properties: { | |||||
element: 'poison' | |||||
}, | |||||
rolls: { | |||||
i_percentage: [8, 22] | |||||
} | |||||
}, { | |||||
type: 'alwaysCrit', | |||||
rolls: {} | |||||
}], | |||||
spellName: 'melee', | |||||
spellConfig: { | |||||
statType: 'dex', | |||||
statMult: 1, | |||||
cdMax: 3, | |||||
castTimeMax: 0, | |||||
useWeaponRange: true, | |||||
random: { | |||||
damage: [0.88, 5.79] | |||||
} | |||||
} | |||||
}) | |||||
}]; |