Master See merge request Isleward/isleward!468tags/v0.6
@@ -245,4 +245,87 @@ body { | |||
} | |||
.color-tealB { | |||
color: @tealB !important;} | |||
color: @tealB !important; | |||
} | |||
[class^="ui"] .renderItem { | |||
width: 72px; | |||
height: 72px; | |||
float: left; | |||
position: relative; | |||
cursor: pointer; | |||
box-sizing: border-box; | |||
margin: 4px; | |||
background-color: @blackD; | |||
&.hover { | |||
background-color: fade(@blueA, 10%); | |||
} | |||
&.dragging { | |||
position: absolute; | |||
opacity: 0.5; | |||
pointer-events: none; | |||
background-color: transparent; | |||
.icon { | |||
filter: brightness(100%) | |||
drop-shadow(0px -4px 0px @blackD) | |||
drop-shadow(0px 4px 0px @blackD) | |||
drop-shadow(4px 0px 0px @blackD) | |||
drop-shadow(-4px 0px 0px @blackD); | |||
-moz-filter: brightness(100%) | |||
drop-shadow(0px -4px 0px @blackD) | |||
drop-shadow(0px 4px 0px @blackD) | |||
drop-shadow(4px 0px 0px @blackD) | |||
drop-shadow(-4px 0px 0px @blackD); | |||
} | |||
} | |||
.quantity { | |||
left: 6px; | |||
bottom: 3px; | |||
position: absolute; | |||
color: @white; | |||
filter: drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
-moz-filter: drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
} | |||
.icon { | |||
width: 64px; | |||
height: 64px; | |||
position: absolute; | |||
left: 4px; | |||
top: 4px; | |||
} | |||
&.eq { | |||
.quantity { | |||
color: @yellow; | |||
} | |||
} | |||
&.new { | |||
.quantity { | |||
color: @green; | |||
} | |||
} | |||
&:hover { | |||
.icon { | |||
filter: brightness(160%); | |||
-moz-filter: brightness(160%); | |||
} | |||
} | |||
} |
@@ -21,21 +21,27 @@ define([ | |||
frameDelayCd: 0, | |||
oldSheetName: null, | |||
oldCell: null, | |||
oldTexture: null, | |||
init: function (blueprint) { | |||
if (!this.obj.sprite) | |||
const { template, frameDelay, obj: { sheetName, cell, sprite } } = this; | |||
if (!sprite) | |||
return true; | |||
this.oldTexture = this.obj.sprite.texture; | |||
this.oldSheetName = sheetName; | |||
this.oldCell = cell; | |||
this.oldTexture = sprite.texture; | |||
this.frame = 0; | |||
this.frameDelayCd = 0; | |||
for (let p in this.template) | |||
this[p] = this.template[p]; | |||
for (let p in template) | |||
this[p] = template[p]; | |||
this.frameDelayCd = this.frameDelay; | |||
this.frameDelayCd = frameDelay; | |||
this.setSprite(); | |||
}, | |||
@@ -68,7 +74,21 @@ define([ | |||
}, | |||
destroy: function () { | |||
this.obj.sprite.texture = this.oldTexture; | |||
const { oldSheetName, oldCell, oldTexture, obj: { sheetName, cell, sprite } } = this; | |||
//Make sure something didn't happen while we were in animation form | |||
// that made us change sprite | |||
if (oldSheetName === sheetName && oldCell === cell) { | |||
sprite.texture = oldTexture; | |||
return; | |||
} | |||
renderer.setSprite({ | |||
sprite, | |||
cell, | |||
sheetName | |||
}); | |||
} | |||
}; | |||
}); |
@@ -38,7 +38,7 @@ define([ | |||
return; | |||
} | |||
let index = indices[this.obj.cell]; | |||
let index = indices[this.obj.cell] || 0; | |||
this.obj.addComponent('particles', { | |||
chance: chances[index], | |||
@@ -17,6 +17,7 @@ define([ | |||
init: function () { | |||
this.hookEvent('onCanvasKeyDown', this.onCanvasKeyDown.bind(this)); | |||
this.hookEvent('onMoveSpeedChange', this.onMoveSpeedChange.bind(this)); | |||
}, | |||
update: function () { | |||
@@ -31,6 +32,14 @@ define([ | |||
this.keyMove(); | |||
}, | |||
//Changes the moveCdMax variable | |||
// moveSpeed is affected when mounting and unmounting | |||
// moveSpeed: 0 | moveCdMax: 8 | |||
// moveSpeed: 200 | moveCdMax: 4 | |||
onMoveSpeedChange: function (moveSpeed) { | |||
this.moveCdMax = Math.ceil(4 + (((200 - moveSpeed) / 200) * 4)); | |||
}, | |||
onCanvasKeyDown: function (keyEvent) { | |||
if (keyEvent.key === 'esc') { | |||
client.request({ | |||
@@ -25,8 +25,14 @@ define([ | |||
sound, | |||
globals | |||
) { | |||
let fnQueueTick = null; | |||
const getQueueTick = updateMethod => { | |||
return () => requestAnimationFrame(updateMethod); | |||
}; | |||
return { | |||
hasFocus: true, | |||
lastRender: 0, | |||
msPerFrame: ~~(1000 / 60), | |||
@@ -45,11 +51,13 @@ define([ | |||
}); | |||
}, | |||
onGetClientConfig: function (config) { | |||
onGetClientConfig: async function (config) { | |||
globals.clientConfig = config; | |||
resources.init(config.resourceList); | |||
events.on('onResourcesLoaded', this.start.bind(this)); | |||
await resources.init(); | |||
events.emit('onResourcesLoaded'); | |||
this.start(); | |||
}, | |||
start: function () { | |||
@@ -69,7 +77,8 @@ define([ | |||
uiFactory.init(null, globals.clientConfig.uiList); | |||
uiFactory.build('login', 'body'); | |||
this.update(); | |||
fnQueueTick = getQueueTick(this.update.bind(this)); | |||
fnQueueTick(); | |||
$('.loader-container').remove(); | |||
}, | |||
@@ -93,7 +102,7 @@ define([ | |||
update: function () { | |||
const time = +new Date(); | |||
if (time - this.lastRender < this.msPerFrame - 1) { | |||
requestAnimationFrame(this.update.bind(this)); | |||
fnQueueTick(); | |||
return; | |||
} | |||
@@ -101,13 +110,13 @@ define([ | |||
objects.update(); | |||
renderer.update(); | |||
uiFactory.update(); | |||
numbers.update(); | |||
numbers.render(); | |||
renderer.render(); | |||
this.lastRender = time; | |||
requestAnimationFrame(this.update.bind(this)); | |||
fnQueueTick(); | |||
} | |||
}; | |||
}); |
@@ -61,7 +61,7 @@ define([ | |||
this.list.push(numberObj); | |||
}, | |||
render: function () { | |||
update: function () { | |||
let list = this.list; | |||
let lLen = list.length; | |||
@@ -6,7 +6,8 @@ define([ | |||
'js/rendering/tileOpacity', | |||
'js/rendering/particles', | |||
'js/rendering/shaders/outline', | |||
'js/rendering/spritePool' | |||
'js/rendering/spritePool', | |||
'js/system/globals' | |||
], function ( | |||
resources, | |||
events, | |||
@@ -15,7 +16,8 @@ define([ | |||
tileOpacity, | |||
particles, | |||
shaderOutline, | |||
spritePool | |||
spritePool, | |||
globals | |||
) { | |||
let pixi = PIXI; | |||
let mRandom = Math.random.bind(Math); | |||
@@ -75,6 +77,7 @@ define([ | |||
events.on('onGetMap', this.onGetMap.bind(this)); | |||
events.on('onToggleFullscreen', this.toggleScreen.bind(this)); | |||
events.on('onMoveSpeedChange', this.adaptCameraMoveSpeed.bind(this)); | |||
let zoom = isMobile ? 1 : window.devicePixelRatio; | |||
this.width = $('body').width() * zoom; | |||
@@ -91,29 +94,25 @@ define([ | |||
window.addEventListener('resize', this.onResize.bind(this)); | |||
$(this.renderer.view) | |||
.appendTo('.canvas-container'); | |||
$(this.renderer.view).appendTo('.canvas-container'); | |||
this.stage = new pixi.Container(); | |||
let layers = this.layers; | |||
Object.keys(layers).forEach(function (l) { | |||
Object.keys(layers).forEach(l => { | |||
layers[l] = new pixi.Container(); | |||
layers[l].layer = (l === 'tileSprites') ? 'tiles' : l; | |||
this.stage.addChild(layers[l]); | |||
}, this); | |||
let spriteNames = ['tiles', 'mobs', 'bosses', 'animBigObjects', 'bigObjects', 'objects', 'characters', 'attacks', 'auras', 'walls', 'ui', 'animChar', 'animMob', 'animBoss', 'white', 'ray']; | |||
resources.spriteNames.forEach(function (s) { | |||
if (s.indexOf('.png') > -1) | |||
spriteNames.push(s); | |||
}); | |||
spriteNames.forEach(function (t) { | |||
this.textures[t] = new pixi.BaseTexture(resources.sprites[t].image); | |||
const textureList = globals.clientConfig.textureList; | |||
const sprites = resources.sprites; | |||
textureList.forEach(t => { | |||
this.textures[t] = new pixi.BaseTexture(sprites[t]); | |||
this.textures[t].scaleMode = pixi.SCALE_MODES.NEAREST; | |||
}, this); | |||
}); | |||
particles.init({ | |||
r: this, | |||
@@ -643,17 +642,19 @@ define([ | |||
let deltaY = this.moveTo.y - this.pos.y; | |||
if (deltaX !== 0 || deltaY !== 0) { | |||
let moveSpeed = this.moveSpeed; | |||
let distance = Math.max(Math.abs(deltaX), Math.abs(deltaY)); | |||
let moveSpeedMax = this.moveSpeedMax; | |||
if (distance > 100) | |||
moveSpeedMax *= 1.75; | |||
if (this.moveSpeed < moveSpeedMax) | |||
this.moveSpeed += this.moveSpeedInc; | |||
let moveSpeed = this.moveSpeed; | |||
if (moveSpeedMax < 1.6) | |||
moveSpeed *= 1 + (distance / 200); | |||
let elapsed = time - this.lastTick; | |||
moveSpeed *= (elapsed / 16.67); | |||
moveSpeed *= (elapsed / 15); | |||
if (moveSpeed > distance) | |||
moveSpeed = distance; | |||
@@ -823,6 +824,20 @@ define([ | |||
obj.sprite.parent.removeChild(obj.sprite); | |||
}, | |||
//Changes the moveSpeedMax and moveSpeedInc variables | |||
// moveSpeed changes when mounting and unmounting | |||
// moveSpeed: 0 | moveSpeedMax: 1.5 | moveSpeedInc: 0.5 | |||
// moveSpeed: 200 | moveSpeedMax: 5.5 | moveSpeedInc: 0.2 | |||
// Between these values we should follow an exponential curve for moveSpeedInc since | |||
// a higher chance will proc more often, meaning the buildup in distance becomes greater | |||
adaptCameraMoveSpeed: function (moveSpeed) { | |||
const factor = Math.sqrt(moveSpeed); | |||
const maxValue = Math.sqrt(200); | |||
this.moveSpeedMax = 1.5 + ((moveSpeed / 200) * 3.5); | |||
this.moveSpeedInc = 0.2 + (((maxValue - factor) / maxValue) * 0.3); | |||
}, | |||
render: function () { | |||
if (!this.stage) | |||
return; | |||
@@ -1,66 +1,27 @@ | |||
define([ | |||
'js/system/events' | |||
'js/system/globals' | |||
], function ( | |||
events | |||
globals | |||
) { | |||
let resources = { | |||
spriteNames: [ | |||
'tiles', | |||
'walls', | |||
'mobs', | |||
'bosses', | |||
'animBigObjects', | |||
'bigObjects', | |||
'objects', | |||
'characters', | |||
'attacks', | |||
'ui', | |||
'auras', | |||
'animChar', | |||
'animMob', | |||
'animBoss', | |||
'white', | |||
'ray', | |||
'images/skins/0001.png', | |||
'images/skins/0010.png', | |||
'images/skins/0012.png' | |||
], | |||
return { | |||
sprites: {}, | |||
ready: false, | |||
init: function (list) { | |||
list.forEach(function (l) { | |||
this.spriteNames.push(l); | |||
}, this); | |||
this.spriteNames.forEach(function (s) { | |||
let sprite = { | |||
image: (new Image()), | |||
ready: false | |||
}; | |||
sprite.image.src = s.indexOf('png') > -1 ? s : 'images/' + s + '.png'; | |||
sprite.image.onload = this.onSprite.bind(this, sprite); | |||
init: async function () { | |||
const { sprites } = this; | |||
const { clientConfig: { resourceList, textureList } } = globals; | |||
this.sprites[s] = sprite; | |||
}, this); | |||
}, | |||
onSprite: function (sprite) { | |||
sprite.ready = true; | |||
const fullList = [].concat(resourceList, textureList); | |||
let readyCount = 0; | |||
for (let s in this.sprites) { | |||
if (this.sprites[s].ready) | |||
readyCount++; | |||
} | |||
return Promise.all(fullList.map(s => { | |||
return new Promise(res => { | |||
const spriteSource = s.includes('.png') ? s : `images/${s}.png`; | |||
if (readyCount === this.spriteNames.length) | |||
this.onReady(); | |||
}, | |||
onReady: function () { | |||
this.ready = true; | |||
events.emit('onResourcesLoaded'); | |||
const sprite = new Image(); | |||
sprites[s] = sprite; | |||
sprite.onload = res; | |||
sprite.src = spriteSource; | |||
}); | |||
})); | |||
} | |||
}; | |||
return resources; | |||
}); |
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "isleward_client", | |||
"version": "0.5.1", | |||
"version": "0.6.0", | |||
"description": "isleward", | |||
"dependencies": {}, | |||
"devDependencies": { | |||
@@ -32,7 +32,6 @@ define([ | |||
'events', | |||
'progressBar', | |||
'stash', | |||
'smithing', | |||
'talk', | |||
'trade', | |||
'overlay', | |||
@@ -151,7 +150,6 @@ define([ | |||
'passives', | |||
'quests', | |||
'reputation', | |||
'smithing', | |||
'stash' | |||
].map(m => 'ui/templates/' + m + '/' + m), this.afterPreload.bind(this)); | |||
}, | |||
@@ -1,5 +1,5 @@ | |||
const tplItem = ` | |||
<div class="item"> | |||
<div class="renderItem item"> | |||
<div class="icon"></div> | |||
<div class="quantity"></div> | |||
</div> | |||
@@ -20,13 +20,9 @@ | |||
text-align: center; | |||
color: @white; | |||
font-size: 18px; | |||
background-color: fade(@blackD, 10%); | |||
background-color: fade(@blackD, 15%); | |||
padding: 8px; | |||
text-shadow: 2px 2px 0 @blackD, | |||
-2px -2px 0 @blackD, | |||
2px -2px 0 @blackD, | |||
-2px 2px 0 @blackD, | |||
2px 2px 0 @blackD; | |||
text-shadow: 2px 2px 0 @blackD, -2px -2px 0 @blackD, 2px -2px 0 @blackD, -2px 2px 0 @blackD, 2px 2px 0 @blackD; | |||
animation: 0.5s ease-in-out infinite bounce; | |||
&.success { | |||
@@ -36,12 +32,24 @@ | |||
&.failure { | |||
color: @red; | |||
} | |||
} | |||
} | |||
} | |||
@keyframes bounce { | |||
0% { top: 0px; } | |||
50% { top: 4px; } | |||
100% { top: 0px ;} | |||
} | |||
0% { | |||
top: 0px; | |||
} | |||
50% { | |||
top: 4px; | |||
} | |||
100% { | |||
top: 0px; | |||
} | |||
} |
@@ -114,7 +114,6 @@ | |||
image-rendering: optimizeSpeed; | |||
image-rendering: pixelated; | |||
image-rendering: crisp-edges; | |||
background: url('../../../images/charas.png') -64px 0px; | |||
} | |||
} | |||
@@ -155,31 +155,18 @@ define([ | |||
}); | |||
}, | |||
openAugmentUi: function (item) { | |||
events.emit('onSetSmithItem', { | |||
item: item | |||
}); | |||
}, | |||
showContext: function (item, e) { | |||
let menuItems = { | |||
unequip: { | |||
text: 'unequip', | |||
callback: this.unequipItem.bind(this, item) | |||
}, | |||
augment: { | |||
text: 'craft', | |||
callback: this.openAugmentUi.bind(this, item) | |||
} | |||
} | |||
}; | |||
let config = []; | |||
config.push(menuItems.unequip); | |||
if (item.slot) | |||
config.push(menuItems.augment); | |||
events.emit('onContextMenu', config, e); | |||
e.preventDefault(); | |||
@@ -187,13 +174,17 @@ define([ | |||
}, | |||
unequipItem: function (item) { | |||
const isQuickslot = item.has('quickSlot'); | |||
const method = isQuickslot ? 'setQuickSlot' : 'unequip'; | |||
const data = isQuickslot ? { slot: item.quickSlot } : item.id; | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
cpn: 'equipment', | |||
method: 'unequip', | |||
data: item.id | |||
method, | |||
data | |||
} | |||
}); | |||
}, | |||
@@ -293,10 +293,6 @@ define([ | |||
text: 'equip', | |||
callback: this.performItemAction.bind(this, item, 'equip') | |||
}, | |||
augment: { | |||
text: 'craft', | |||
callback: this.openAugmentUi.bind(this, item) | |||
}, | |||
mail: { | |||
text: 'mail', | |||
callback: this.openMailUi.bind(this, item) | |||
@@ -336,11 +332,6 @@ define([ | |||
ctxConfig.push(menuItems.equip); | |||
if (!item.eq) | |||
ctxConfig.push(menuItems.divider); | |||
if (!item.eq) { | |||
ctxConfig.push(menuItems.augment); | |||
ctxConfig.push(menuItems.divider); | |||
} | |||
} | |||
if ((!item.eq) && (!item.active)) { | |||
@@ -354,9 +345,6 @@ define([ | |||
if ((!item.material) && (!item.noSalvage)) | |||
ctxConfig.push(menuItems.salvage); | |||
} | |||
if (!item.noDestroy) | |||
ctxConfig.push(menuItems.destroy); | |||
} | |||
if (item.quantity > 1 && !item.quest) | |||
@@ -367,6 +355,11 @@ define([ | |||
ctxConfig.push(menuItems.link); | |||
if (!item.eq && !item.active && !item.noDestroy) { | |||
ctxConfig.push(menuItems.divider); | |||
ctxConfig.push(menuItems.destroy); | |||
} | |||
if (isMobile) | |||
this.hideTooltip(null, this.hoverItem); | |||
@@ -568,12 +561,6 @@ define([ | |||
}); | |||
}, | |||
openAugmentUi: function (item) { | |||
events.emit('onSetSmithItem', { | |||
item: item | |||
}); | |||
}, | |||
openMailUi: function (item) { | |||
events.emit('onSetMailItem', { | |||
item: item | |||
@@ -11,11 +11,11 @@ | |||
</div> | |||
<div class="message"></div> | |||
</div> | |||
<div class="news" location="https://gitlab.com/Isleward/isleward/tags/v0.5.1">[ Latest Release Notes ]</div> | |||
<div class="news" location="https://gitlab.com/Isleward/isleward/tags/v0.6">[ Latest Release Notes ]</div> | |||
<div class="extra"> | |||
<div class="el btn btnPatreon" location="https://patreon.com/bigbadwaffle">Pledge on Patreon</div> | |||
<div class="el btn btnPaypal" location="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BR2CC82WUAVEA">Donate on Paypal</div> | |||
<div class="el btn btnWiki" location="http://wiki.isleward.com/Main_Page">Access the Wiki</div> | |||
</div> | |||
<div class="version" location="https://gitlab.com/Isleward/isleward/tags/v0.5.1">v0.5.1</div> | |||
<div class="version" location="https://gitlab.com/Isleward/isleward/tags/v0.6">v0.6</div> | |||
</div> |
@@ -15,7 +15,6 @@ define([ | |||
this.find('.btnCollapse').on('click', this.toggleButtons.bind(this)); | |||
} | |||
this.find('.btnSmithing').on('click', this.handler.bind(this, 'onShowSmithing')); | |||
this.find('.btnHelp').on('click', this.handler.bind(this, 'onShowHelp')); | |||
this.find('.btnInventory').on('click', this.handler.bind(this, 'onShowInventory')); | |||
this.find('.btnEquipment').on('click', this.handler.bind(this, 'onShowEquipment')); | |||
@@ -1,5 +1,4 @@ | |||
@import "../../../css/colors.less"; | |||
@pad: 8px; | |||
@btnSize: 64px; | |||
@@ -7,8 +6,7 @@ | |||
position: absolute; | |||
right: 10px; | |||
bottom: 10px; | |||
width: ((@btnSize * 5) + (@pad * 12)); | |||
width: ((@btnSize * 4) + (@pad * 10)); | |||
height: ((@btnSize * 2) + (@pad * 2)); | |||
padding: @pad; | |||
background-color: fade(@darkGray, 90%); | |||
@@ -17,9 +15,8 @@ | |||
width: @btnSize; | |||
height: @btnSize; | |||
float: left; | |||
margin: 0px 8px; | |||
margin: 0px @pad; | |||
float: left; | |||
cursor: pointer; | |||
position: relative; | |||
@@ -40,10 +37,6 @@ | |||
display: none; | |||
} | |||
&.btnInventory { | |||
margin: 0px 8px 0px 45px; | |||
} | |||
&.btnInventory .icon { | |||
background: url('../../../images/uiIcons.png') 0px 0px; | |||
} | |||
@@ -57,7 +50,6 @@ | |||
} | |||
&.btnPassives { | |||
width: 65px; | |||
position: relative; | |||
.points { | |||
@@ -67,12 +59,12 @@ | |||
bottom: 23px; | |||
position: absolute; | |||
color: @white; | |||
filter: | |||
drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
filter: drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
} | |||
} | |||
&.btnPassives .icon { | |||
@@ -98,7 +90,9 @@ | |||
&.btnMainMenu .icon { | |||
background: url('../../../images/uiIcons.png') 0px -64px; | |||
} | |||
} | |||
} | |||
.mobile .uiMenu { | |||
@@ -157,6 +151,9 @@ | |||
height: 100%; | |||
background: url('../../../images/uiIcons.png') -448px 0px; | |||
} | |||
} | |||
} | |||
} |
@@ -5,9 +5,6 @@ | |||
<div class="btnEquipment"> | |||
<div class="icon"></div> | |||
</div> | |||
<div class="btnSmithing"> | |||
<div class="icon"></div> | |||
</div> | |||
<div class="btnPassives"> | |||
<div class="icon"></div> | |||
<div class="points"></div> | |||
@@ -14,11 +14,6 @@ define([ | |||
this.onEvent('onGetSelfCasting', this.onGetCasting.bind(this)); | |||
if (isMobile) { | |||
this.onEvent('onEnterGatherNode', this.toggleGatherButton.bind(this, true)); | |||
this.onEvent('onExitGatherNode', this.toggleGatherButton.bind(this, false)); | |||
this.onEvent('onRespawn', this.toggleGatherButton.bind(this, false)); | |||
this.onEvent('onShowProgress', this.toggleGatherButton.bind(this, false)); | |||
this.onEvent('onGetServerActions', this.onGetServerActions.bind(this)); | |||
this.find('.btnGather').on('click', this.gather.bind(this)); | |||
@@ -38,12 +33,6 @@ define([ | |||
} | |||
}, | |||
toggleGatherButton: function (show) { | |||
let btn = this.find('.btnGather').hide(); | |||
if (show) | |||
btn.show(); | |||
}, | |||
gather: function () { | |||
let btn = this.find('.btnGather'); | |||
let action = btn.data('action'); | |||
@@ -1,343 +0,0 @@ | |||
define([ | |||
'js/system/events', | |||
'js/system/client', | |||
'html!ui/templates/smithing/template', | |||
'css!ui/templates/smithing/styles', | |||
'html!/ui/templates/smithing/templateItem', | |||
'js/misc/statTranslations' | |||
], function ( | |||
events, | |||
client, | |||
template, | |||
styles, | |||
templateItem, | |||
statTranslations | |||
) { | |||
return { | |||
tpl: template, | |||
centered: true, | |||
modal: true, | |||
hasClose: true, | |||
eventCloseInv: null, | |||
eventClickInv: null, | |||
hoverItem: null, | |||
item: null, | |||
waiting: false, | |||
action: 'augment', | |||
postRender: function () { | |||
this.onEvent('onShowSmithing', this.toggle.bind(this)); | |||
this.onEvent('onKeyDown', this.onKey.bind(this, true)); | |||
this.onEvent('onKeyUp', this.onKey.bind(this, false)); | |||
this.find('.item-picker').on('click', this.openInventory.bind(this)); | |||
this.find('.actionButton').on('click', this.smith.bind(this)); | |||
//If we don't listen to these events, they'll be queued | |||
this.onEvent('onHideInventory', () => {}); | |||
this.onEvent('beforeInventoryClickItem', () => {}); | |||
this.onEvent('onGetItems', this.onGetItems.bind(this)); | |||
this.onEvent('onSetSmithItem', this.onHideInventory.bind(this)); | |||
this.find('.col-btn').on('click', this.clickAction.bind(this)); | |||
}, | |||
clickAction: function (e) { | |||
let el = $(e.target); | |||
this.find('.col-btn').removeClass('selected'); | |||
let action = el.attr('action'); | |||
let changed = (action !== this.action); | |||
this.action = action; | |||
el.addClass('selected'); | |||
if (this.item && changed) | |||
this.getMaterials(this.item); | |||
}, | |||
smith: function () { | |||
this.setDisabled(true); | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
cpn: 'inventory', | |||
method: 'enchantItem', | |||
data: { | |||
itemId: this.item.id, | |||
action: this.action | |||
} | |||
}, | |||
callback: this.onSmith.bind(this, this.item) | |||
}); | |||
}, | |||
onSmith: function (item, result) { | |||
this.setDisabled(false); | |||
let msg = { | |||
msg: 'Item Enhancement Succeeded', | |||
type: 'success', | |||
zIndex: 9999999, | |||
top: 100 | |||
}; | |||
if (this.action === 'reroll') | |||
msg.msg = 'Item Reroll Succeeded'; | |||
else if (this.action === 'relevel') | |||
msg.msg = 'Item Relevel Succeeded'; | |||
else if (this.action === 'reslot') | |||
msg.msg = 'Item Reslot Succeeded'; | |||
result.addStatMsgs.forEach(a => { | |||
let statName = statTranslations.translate(a.stat); | |||
msg.msg += `<br />${(a.value > 0) ? '+' : ''}${a.value} ${statName}`; | |||
}); | |||
events.emit('onGetAnnouncement', msg); | |||
if (result.item) | |||
this.item = result.item; | |||
this.getMaterials(this.item); | |||
let augment = this.find('[action="augment"]').addClass('disabled'); | |||
if ((result.item.power || 0) < 3) | |||
augment.removeClass('disabled'); | |||
else if (this.action === 'augment') | |||
this.find('[action="reroll"]').click(); | |||
}, | |||
openInventory: function () { | |||
this.waiting = true; | |||
this.eventCloseInv = this.onEvent('onHideInventory', this.onHideInventory.bind(this)); | |||
this.eventClickInv = this.onEvent('beforeInventoryClickItem', this.onHideInventory.bind(this)); | |||
events.emit('onShowInventory'); | |||
}, | |||
onHideInventory: function (msg) { | |||
if (msg) | |||
msg.success = false; | |||
this.waiting = false; | |||
if (!msg || !msg.item) { | |||
this.offEvent(this.eventCloseInv); | |||
this.offEvent(this.eventClickInv); | |||
return; | |||
} else if (!msg.item.slot || msg.item.noAugment) { | |||
let resultMsg = { | |||
msg: 'Incorrect Item Type', | |||
type: 'failure', | |||
zIndex: 9999999, | |||
top: 180 | |||
}; | |||
events.emit('onGetAnnouncement', resultMsg); | |||
return; | |||
} | |||
this.find('.selected').removeClass('selected'); | |||
this.find('[action="augment"]').addClass('selected'); | |||
this.action = 'augment'; | |||
let augment = this.find('[action="augment"]').addClass('disabled'); | |||
if ((msg.item.power || 0) < 3) | |||
augment.removeClass('disabled'); | |||
let reforge = this.find('[action="reforge"]').addClass('disabled'); | |||
if (msg.item.spell) | |||
reforge.removeClass('disabled'); | |||
let reslot = this.find('[action="reslot"]').addClass('disabled'); | |||
if (!msg.item.effects && msg.item.slot !== 'tool') | |||
reslot.removeClass('disabled'); | |||
let relevel = this.find('[action="relevel"]').addClass('disabled'); | |||
if (msg.item.slot !== 'tool') | |||
relevel.removeClass('disabled'); | |||
this.offEvent(this.eventClickInv); | |||
$('.uiInventory').data('ui').hide(); | |||
this.show(); | |||
this.el.show(); | |||
this.shown = true; | |||
msg.success = false; | |||
if (!msg || !msg.item || !msg.item.slot) | |||
return; | |||
this.item = msg.item; | |||
this.getMaterials(msg.item); | |||
}, | |||
getMaterials: function (item) { | |||
this.setDisabled(true); | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
cpn: 'inventory', | |||
method: 'getEnchantMaterials', | |||
data: { | |||
itemId: item.id, | |||
action: this.action | |||
} | |||
}, | |||
callback: this.onGetMaterials.bind(this, item) | |||
}); | |||
}, | |||
onGetMaterials: function (item, result) { | |||
this.find('.item').remove(); | |||
this.drawItem(this.find('.item-picker'), item); | |||
this.find('.actionButton').removeClass('disabled').addClass('disabled'); | |||
if (result.materials) { | |||
let material = result.materials[0]; | |||
if (material) { | |||
let hasMaterials = window.player.inventory.items.find(i => i.name === material.name); | |||
if (hasMaterials) { | |||
material.quantityText = hasMaterials.quantity + '/' + material.quantity; | |||
hasMaterials = hasMaterials.quantity >= material.quantity; | |||
} else { | |||
if (!material.quantityText) | |||
material.quantityText = ''; | |||
material.quantityText += '0/' + material.quantity; | |||
} | |||
if (hasMaterials) | |||
this.find('.actionButton').removeClass('disabled'); | |||
this.drawItem(this.find('.material'), material, !hasMaterials); | |||
} | |||
} | |||
this.setDisabled(false); | |||
}, | |||
onGetItems: function (items) { | |||
let elMaterial = this.find('.material .item'); | |||
if (!elMaterial.length) | |||
return; | |||
let itemMaterial = elMaterial.data('item'); | |||
let elQuantity = elMaterial.find('.quantity'); | |||
let invMaterial = items.find(i => i.name === itemMaterial.name) || { quantity: 0 }; | |||
let currentText = elQuantity.html().split('/'); | |||
let newText = invMaterial.quantity + '/' + currentText[1]; | |||
elQuantity.html(newText); | |||
let elButton = this.find('.actionButton').removeClass('disabled'); | |||
if (invMaterial.quantity < currentText[1]) { | |||
elButton.addClass('disabled'); | |||
elQuantity.addClass('red'); | |||
} else { | |||
elButton.removeClass('disabled'); | |||
elQuantity.removeClass('red'); | |||
} | |||
}, | |||
drawItem: function (container, item, redQuantity) { | |||
container.find('.icon').hide(); | |||
let imgX = -item.sprite[0] * 64; | |||
let imgY = -item.sprite[1] * 64; | |||
let spritesheet = item.spritesheet || '../../../images/items.png'; | |||
if (item.material) | |||
spritesheet = '../../../images/materials.png'; | |||
else if (item.quest) | |||
spritesheet = '../../../images/questItems.png'; | |||
else if (item.type === 'consumable') | |||
spritesheet = '../../../images/consumables.png'; | |||
let el = $(templateItem) | |||
.appendTo(container); | |||
el | |||
.data('item', item) | |||
.on('mousemove', this.onHover.bind(this, el, item)) | |||
.on('mouseleave', this.hideTooltip.bind(this, el, item)) | |||
.find('.icon') | |||
.css('background', 'url(' + spritesheet + ') ' + imgX + 'px ' + imgY + 'px'); | |||
if (item.quantity) { | |||
let quantityText = item.quantityText; | |||
el.find('.quantity').html(quantityText); | |||
if (redQuantity) | |||
el.find('.quantity').addClass('red'); | |||
} | |||
}, | |||
onHover: function (el, item, e) { | |||
if (item) | |||
this.hoverItem = item; | |||
else | |||
item = this.hoverItem; | |||
let ttPos = null; | |||
if (el) { | |||
ttPos = { | |||
x: ~~(e.clientX + 32), | |||
y: ~~(e.clientY) | |||
}; | |||
} | |||
events.emit('onShowItemTooltip', item, ttPos, true); | |||
}, | |||
hideTooltip: function (el, item, e) { | |||
events.emit('onHideItemTooltip', this.hoverItem); | |||
this.hoverItem = null; | |||
}, | |||
beforeHide: function () { | |||
if (this.waiting) | |||
return; | |||
this.item = null; | |||
this.offEvent(this.eventCloseInv); | |||
this.offEvent(this.eventClickInv); | |||
}, | |||
toggle: function () { | |||
this.shown = !this.el.is(':visible'); | |||
if (this.shown) { | |||
this.find('.item').remove(); | |||
this.find('.icon').show(); | |||
this.find('.actionButton').removeClass('disabled').addClass('disabled'); | |||
this.show(); | |||
} else | |||
this.hide(); | |||
}, | |||
onKey: function (isDown, key) { | |||
if (isDown && key === 'm') | |||
this.toggle(); | |||
else if (key === 'shift' && this.hoverItem) | |||
this.onHover(); | |||
} | |||
}; | |||
}); |
@@ -1,186 +0,0 @@ | |||
@import "../../../css/colors.less"; | |||
.uiSmithing { | |||
display: none; | |||
background-color: @blackB; | |||
border: 5px solid @blackB; | |||
text-align: center; | |||
> .heading { | |||
color: @blueA; | |||
width: 100%; | |||
height: 36px; | |||
background-color: @blackB; | |||
.heading-text { | |||
padding-top: 8px; | |||
margin: auto; | |||
} | |||
} | |||
.bottom { | |||
height: 170px; | |||
background-color: @blackC; | |||
padding: 10px; | |||
} | |||
.col { | |||
float: left; | |||
margin-right: 10px; | |||
&:last-child { | |||
margin-right: 0px; | |||
} | |||
.heading { | |||
width: 80px; | |||
height: 16px; | |||
color: @white; | |||
text-align: center; | |||
margin-bottom: 10px; | |||
} | |||
.content { | |||
width: 80px; | |||
height: 80px; | |||
background-color: @blackD; | |||
&.chance { | |||
padding-top: 32px; | |||
color: @white; | |||
text-align: center; | |||
} | |||
&.item-picker, | |||
&.actionButton { | |||
cursor: pointer; | |||
&:hover { | |||
background-color: @blackC; | |||
} | |||
} | |||
&.item-picker { | |||
> .icon { | |||
margin: 8px; | |||
display: inline-block; | |||
width: 64px; | |||
height: 64px; | |||
background: url('../../../images/uiIcons.png') -256px -64px; | |||
} | |||
} | |||
&.actionButton { | |||
padding: 8px; | |||
.icon { | |||
width: 64px; | |||
height: 64px; | |||
background: url('../../../images/uiIcons.png') -192px -64px; | |||
} | |||
} | |||
.item { | |||
width: 100%; | |||
height: 100%; | |||
float: left; | |||
position: relative; | |||
cursor: pointer; | |||
box-sizing: border-box; | |||
.quantity { | |||
left: 6px; | |||
bottom: 3px; | |||
position: absolute; | |||
color: @white; | |||
filter: drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
-moz-filter: drop-shadow(0px -2px 0px @blackD) | |||
drop-shadow(0px 2px 0px @blackD) | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
&.red { | |||
color: @red; | |||
} | |||
} | |||
.icon { | |||
width: 64px; | |||
height: 64px; | |||
position: absolute; | |||
left: 8px; | |||
top: 8px; | |||
filter: brightness(100%) | |||
drop-shadow(0px -4px 0px @blackD) | |||
drop-shadow(0px 4px 0px @blackD) | |||
drop-shadow(4px 0px 0px @blackD) | |||
drop-shadow(-4px 0px 0px @blackD); | |||
-moz-filter: brightness(100%) | |||
drop-shadow(0px -4px 0px @blackD) | |||
drop-shadow(0px 4px 0px @blackD) | |||
drop-shadow(4px 0px 0px @blackD) | |||
drop-shadow(-4px 0px 0px @blackD); | |||
} | |||
} | |||
} | |||
&:first-child { | |||
.heading { | |||
width: 190px; | |||
} | |||
.content { | |||
width: 190px; | |||
background-color: transparent; | |||
.col-btn { | |||
height: calc((100% - 10px) / 2); | |||
width: 100%; | |||
color: #f2f5f5; | |||
text-align: center; | |||
padding-top: 10px; | |||
background-color: @blackB; | |||
margin-bottom: 10px; | |||
cursor: pointer; | |||
&.selected { | |||
color: @orangeA; | |||
} | |||
&:hover { | |||
background-color: @blackA; | |||
} | |||
&.col-half { | |||
width: calc((100% - 10px) / 2); | |||
float: left; | |||
&:nth-child(2n + 1) { | |||
margin-right: 10px; | |||
} | |||
} | |||
&:not(.col-half) { | |||
clear: both; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,34 +0,0 @@ | |||
<div class="uiSmithing"> | |||
<div class="heading"> | |||
<div class="heading-text">craft item</div> | |||
</div> | |||
<div class="bottom"> | |||
<div class="col"> | |||
<div class="heading">action</div> | |||
<div class="content"> | |||
<div class="col-btn col-half selected" action="augment">augment</div> | |||
<div class="col-btn col-half" action="scour">scour</div> | |||
<div class="col-btn col-half" action="reroll">reroll</div> | |||
<div class="col-btn col-half" action="relevel">relevel</div> | |||
<div class="col-btn col-half" action="reslot">reslot</div> | |||
<div class="col-btn col-half" action="reforge">reforge</div> | |||
</div> | |||
</div> | |||
<div class="col"> | |||
<div class="heading">item</div> | |||
<div class="content item-picker"> | |||
<div class="icon"></div> | |||
</div> | |||
</div> | |||
<div class="col"> | |||
<div class="heading">material</div> | |||
<div class="content material"></div> | |||
</div> | |||
<div class="col"> | |||
<div class="heading"></div> | |||
<div class="content actionButton disabled"> | |||
<div class="icon"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -1,4 +0,0 @@ | |||
<div class="item"> | |||
<div class="icon"></div> | |||
<div class="quantity"></div> | |||
</div> |
@@ -2,17 +2,20 @@ | |||
.uiWorkbench { | |||
display: none; | |||
width: 720px; | |||
height: 385px; | |||
border: 5px solid fade(@blackB, 90%); | |||
text-align: center; | |||
width: 827px; | |||
height: 447px; | |||
border: 5px solid @blackB; | |||
color: @white; | |||
position: relative; | |||
z-index: 2; | |||
> .heading { | |||
color: @blueA; | |||
> .heading, | |||
> .itemPicker > .heading { | |||
color: @orangeA; | |||
width: 100%; | |||
height: 36px; | |||
background-color: fade(@blackB, 90%); | |||
background-color: @blackB; | |||
text-align: center; | |||
.heading-text { | |||
padding-top: 8px; | |||
@@ -21,14 +24,15 @@ | |||
} | |||
.bottom { | |||
background-color: fade(@blackC, 90%); | |||
> .bottom { | |||
background-color: @blackC; | |||
height: calc(100% - 36px); | |||
width: 100%; | |||
.heading { | |||
color: @blueB; | |||
margin-bottom: 10px; | |||
text-align: center; | |||
} | |||
.left, | |||
@@ -44,14 +48,18 @@ | |||
.list { | |||
height: calc(100% - 25px); | |||
overflow-y: auto; | |||
display: flex; | |||
flex-direction: column; | |||
.item { | |||
width: 100%; | |||
padding: 5px 0px; | |||
padding: 5px 10px; | |||
cursor: pointer; | |||
color: @grayB; | |||
&.selected { | |||
background-color: @blackB; | |||
color: @white; | |||
} | |||
&:hover { | |||
@@ -66,6 +74,9 @@ | |||
.right { | |||
width: calc(100% - 300px); | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: space-between; | |||
> * { | |||
width: 100%; | |||
@@ -73,17 +84,24 @@ | |||
.info { | |||
height: calc(100% - 100px - 35px); | |||
flex: 1; | |||
.title { | |||
color: @orangeA; | |||
color: @blueB; | |||
padding-bottom: 10px; | |||
text-align: center; | |||
} | |||
.description { | |||
color: @grayB; | |||
text-align: justify; | |||
} | |||
} | |||
.materialList { | |||
height: 100px; | |||
visibility: hidden; | |||
margin-bottom: 20px; | |||
.material { | |||
&.need { | |||
@@ -94,6 +112,24 @@ | |||
} | |||
.needItems { | |||
display: none; | |||
margin-bottom: 20px; | |||
flex-direction: column; | |||
.title { | |||
color: @blueB; | |||
padding-bottom: 10px; | |||
text-align: center; | |||
} | |||
.list { | |||
display: flex; | |||
justify-content: space-around; | |||
} | |||
} | |||
.buttons { | |||
height: 40px; | |||
@@ -123,6 +159,24 @@ | |||
} | |||
> .itemPicker { | |||
display: none; | |||
position: absolute; | |||
left: 0px; | |||
top: 0px; | |||
width: 100%; | |||
height: 100%; | |||
background-color: @blackC; | |||
flex-direction: column; | |||
.list { | |||
display: flex; | |||
flex-wrap: wrap; | |||
overflow-y: auto; | |||
} | |||
} | |||
} | |||
.mobile .uiWorkbench { | |||
@@ -1,6 +1,6 @@ | |||
<div class="uiWorkbench"> | |||
<div class="heading"> | |||
<div class="heading-text">Workbench</div> | |||
<div class="mainHeading heading-text">Workbench</div> | |||
</div> | |||
<div class="bottom"> | |||
<div class="left"> | |||
@@ -15,6 +15,10 @@ | |||
<div class="title"></div> | |||
<div class="description"></div> | |||
</div> | |||
<div class="needItems"> | |||
<div class="title">Pick Items</div> | |||
<div class="list"></div> | |||
</div> | |||
<div class="materialList"> | |||
<div class="heading">Requires:</div> | |||
</div> | |||
@@ -24,4 +28,12 @@ | |||
</div> | |||
</div> | |||
</div> | |||
<div class="itemPicker"> | |||
<div class="heading"> | |||
<div class="heading-text"></div> | |||
</div> | |||
<div class="list"> | |||
</div> | |||
</div> | |||
</div> |
@@ -2,12 +2,16 @@ define([ | |||
'js/system/events', | |||
'js/system/client', | |||
'html!ui/templates/workbench/template', | |||
'css!ui/templates/workbench/styles' | |||
'css!ui/templates/workbench/styles', | |||
'ui/shared/renderItem', | |||
'js/misc/statTranslations' | |||
], function ( | |||
events, | |||
client, | |||
template, | |||
styles | |||
styles, | |||
renderItem, | |||
statTranslations | |||
) { | |||
return { | |||
tpl: template, | |||
@@ -22,9 +26,18 @@ define([ | |||
recipes: null, | |||
currentRecipe: null, | |||
selectedNeedItems: null, | |||
hoverItem: null, | |||
hoverEl: null, | |||
postRender: function () { | |||
this.onEvent('onOpenWorkbench', this.onOpenWorkbench.bind(this)); | |||
this.onEvent('onCloseWorkbench', this.hide.bind(this)); | |||
this.onEvent('onGetItems', this.onGetItems.bind(this)); | |||
this.onEvent('onKeyDown', this.onKeyDown.bind(this)); | |||
this.onEvent('onKeyUp', this.onKeyUp.bind(this)); | |||
this.on('.btnCraft', 'click', this.craft.bind(this)); | |||
this.on('.btnCancel', 'click', this.hide.bind(this)); | |||
@@ -32,17 +45,29 @@ define([ | |||
onOpenWorkbench: function (msg) { | |||
this.workbenchId = msg.workbenchId; | |||
this.find('.heading-text').html(msg.name); | |||
this.find('.mainHeading').html(msg.name); | |||
this.find('.itemPicker').hide(); | |||
this.find('.needItems').hide(); | |||
this.renderRecipes(msg.recipes); | |||
this.show(); | |||
}, | |||
//Redraw items if they change | |||
onGetItems: function (items) { | |||
if (!this.currentRecipe) | |||
return; | |||
const { currentRecipe: { needItems } } = this; | |||
this.buildNeedItemBoxes(needItems, true); | |||
}, | |||
renderRecipes: function (recipes) { | |||
this.recipes = recipes; | |||
let container = this.find('.list').empty(); | |||
let container = this.find('.left .list').empty(); | |||
recipes.forEach(function (r) { | |||
let el = $('<div class="item">' + r + '</div>') | |||
@@ -64,18 +89,20 @@ define([ | |||
cpn: 'workbench', | |||
method: 'getRecipe', | |||
data: { | |||
name: recipeName | |||
name: recipeName | |||
} | |||
}, | |||
callback: this.onGetRecipe.bind(this) | |||
callback: this.onGetRecipe.bind(this, false) | |||
}); | |||
}, | |||
onGetRecipe: function (recipe) { | |||
onGetRecipe: function (persistNeedItems, recipe) { | |||
const { name: recipeName, description, materials, needItems } = recipe; | |||
this.currentRecipe = recipe; | |||
this.find('.title').html(recipe.name); | |||
this.find('.description').html(recipe.description); | |||
this.find('.info .title').html(recipeName); | |||
this.find('.description').html(description); | |||
this.find('.materialList .material').remove(); | |||
@@ -84,13 +111,16 @@ define([ | |||
visibility: 'visible' | |||
}); | |||
let canCraft = true; | |||
let canCraft = !!materials.length; | |||
materials.forEach(m => { | |||
const { needQuantity, nameLike, name: materialName, haveQuantity, noHaveEnough } = m; | |||
recipe.materials.forEach(function (m) { | |||
let el = $('<div class="material">' + m.quantity + 'x ' + (m.nameLike || m.name) + '</div>') | |||
const materialText = `${needQuantity}x ${(nameLike || materialName)} (${haveQuantity})`; | |||
let el = $(`<div class="material">${materialText}</div>`) | |||
.appendTo(container); | |||
if (m.need) { | |||
if (noHaveEnough) { | |||
canCraft = false; | |||
el.addClass('need'); | |||
} | |||
@@ -103,10 +133,138 @@ define([ | |||
this.find('.btnCraft') | |||
.addClass('disabled'); | |||
} | |||
//If there are no materials, the selected items aren't valid | |||
this.find('.materialList').show(); | |||
if (!materials.length) { | |||
this.find('.materialList').hide(); | |||
persistNeedItems = false; | |||
} | |||
this.buildNeedItemBoxes(needItems, persistNeedItems); | |||
}, | |||
buildNeedItemBoxes: function (needItems = [], persistNeedItems) { | |||
if (!persistNeedItems) { | |||
this.selectedNeedItems = new Array(needItems.length); | |||
this.selectedNeedItems.fill(null); | |||
} | |||
const container = this.find('.needItems').hide(); | |||
const list = container.find('.list').empty(); | |||
if (!needItems.length) | |||
return; | |||
container.css({ display: 'flex' }); | |||
needItems.forEach((n, i) => this.buildNeedItemBox(list, n, i)); | |||
}, | |||
buildNeedItemBox: function (container, needItem, needItemIndex) { | |||
const item = this.selectedNeedItems[needItemIndex]; | |||
const el = renderItem(container, item); | |||
el | |||
.on('mousemove', this.toggleTooltip.bind(this, true, el, needItem, item)) | |||
.on('mouseleave', this.toggleTooltip.bind(this, false, el, needItem, item)) | |||
.on('click', this.toggleItemPicker.bind(this, true, needItem, needItemIndex)); | |||
}, | |||
toggleItemPicker: function (show, needItem, needItemIndex) { | |||
const container = this.find('.itemPicker').hide(); | |||
if (!show) | |||
return; | |||
const { allowedItemIds } = needItem; | |||
container | |||
.css({ display: 'flex' }) | |||
.find('.heading-text').html(needItem.info); | |||
const list = container.find('.list').empty(); | |||
const items = window.player.inventory.items | |||
.filter(item => { | |||
const isValidItem = allowedItemIds.find(f => f === item.id); | |||
return isValidItem; | |||
}); | |||
items.forEach(item => { | |||
const el = renderItem(list, item); | |||
el | |||
.on('click', this.onSelectItem.bind(this, item, needItemIndex)) | |||
.on('mousemove', this.toggleTooltip.bind(this, true, el, null, item)) | |||
.on('mouseleave', this.toggleTooltip.bind(this, false, el, null, item)); | |||
}); | |||
}, | |||
onSelectItem: function (item, needItemIndex) { | |||
this.selectedNeedItems[needItemIndex] = item; | |||
const { currentRecipe: { needItems } } = this; | |||
this.buildNeedItemBoxes(needItems, true); | |||
const allItemsSelected = this.selectedNeedItems.every(i => !!i); | |||
if (allItemsSelected && this.currentRecipe.dynamicMaterials) { | |||
const pickedItemIds = this.selectedNeedItems.map(i => i.id); | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
targetId: this.workbenchId, | |||
cpn: 'workbench', | |||
method: 'getRecipe', | |||
data: { | |||
name: this.currentRecipe.name, | |||
pickedItemIds | |||
} | |||
}, | |||
callback: this.onGetRecipe.bind(this, true) | |||
}); | |||
} | |||
this.find('.itemPicker').hide(); | |||
}, | |||
toggleTooltip: function (show, el, needItem, item, e) { | |||
if (item) { | |||
this.hoverItem = show ? item : null; | |||
this.hoverEl = show ? el : null; | |||
} | |||
let pos = null; | |||
if (e) { | |||
const { clientX, clientY } = e; | |||
pos = { | |||
x: clientX + 25, | |||
y: clientY | |||
}; | |||
} | |||
if (item) { | |||
if (show) | |||
events.emit('onShowItemTooltip', item, pos, true); | |||
else | |||
events.emit('onHideItemTooltip', item); | |||
return; | |||
} | |||
if (show) | |||
events.emit('onShowTooltip', needItem.info, el[0], pos); | |||
else | |||
events.emit('onHideTooltip', el[0]); | |||
}, | |||
craft: function () { | |||
let selectedRecipe = this.find('.list .item.selected').html(); | |||
const selectedRecipe = this.find('.left .list .item.selected').html(); | |||
const pickedItemIds = this.selectedNeedItems | |||
.map(item => item.id); | |||
client.request({ | |||
cpn: 'player', | |||
@@ -116,15 +274,32 @@ define([ | |||
cpn: 'workbench', | |||
method: 'craft', | |||
data: { | |||
name: selectedRecipe | |||
name: selectedRecipe, | |||
pickedItemIds | |||
} | |||
}, | |||
callback: this.onCraft.bind(this) | |||
}); | |||
}, | |||
onCraft: function (recipe) { | |||
this.onGetRecipe(recipe); | |||
onCraft: function ({ recipe, resultMsg }) { | |||
this.onGetRecipe(true, recipe); | |||
if (resultMsg) { | |||
const { msg: baseMsg, addStatMsgs = [] } = resultMsg; | |||
let msg = baseMsg; | |||
addStatMsgs.forEach(a => { | |||
const statName = statTranslations.translate(a.stat); | |||
msg += `<br />${(a.value > 0) ? '+' : ''}${a.value} ${statName}`; | |||
}); | |||
events.emit('onGetAnnouncement', { | |||
msg, | |||
top: 150 | |||
}); | |||
} | |||
}, | |||
onAfterShow: function () { | |||
@@ -133,7 +308,7 @@ define([ | |||
clear: function () { | |||
this.find('.left .list .selected').removeClass('selected'); | |||
this.find('.title').html(''); | |||
this.find('.info .title').html(''); | |||
this.find('.description').html(''); | |||
this.find('.materialList .material').remove(); | |||
this.find('.materialList') | |||
@@ -141,6 +316,16 @@ define([ | |||
visibility: 'hidden' | |||
}); | |||
this.find('.btnCraft').addClass('disabled'); | |||
}, | |||
onKeyDown: function (key) { | |||
if (key === 'shift' && this.hoverItem) | |||
this.toggleTooltip(true, this.hoverEl, null, this.hoverItem); | |||
}, | |||
onKeyUp: function (key) { | |||
if (key === 'shift' && this.hoverItem) | |||
this.toggleTooltip(true, this.hoverEl, null, this.hoverItem); | |||
} | |||
}; | |||
}); |
@@ -14,13 +14,11 @@ module.exports = { | |||
}, | |||
getComponentFolder: function () { | |||
let files = fileLister.getFolder('./components/'); | |||
files = files.filter(w => ( | |||
(w.indexOf('components') === -1) && | |||
(w.indexOf('cpnBase') === -1) && | |||
(w.indexOf('projectile') === -1) | |||
)); | |||
let fLen = files.length; | |||
const ignoreFiles = ['components.js', 'componentBase.js']; | |||
const files = fileLister.getFolder('./components/') | |||
.filter(f => !ignoreFiles.includes(f)); | |||
const fLen = files.length; | |||
for (let i = 0; i < fLen; i++) | |||
this.getComponentFile(`./${files[i]}`); | |||
@@ -119,21 +119,15 @@ module.exports = { | |||
if (this.autoClose) | |||
this.autoCloseCd = this.autoClose; | |||
let key = obj.inventory.items.find(i => ((i.keyId === this.key) || (i.keyId === 'world'))); | |||
let key = obj.inventory.items.find(i => (i.keyId === this.key || i.keyId === 'world')); | |||
if (!key) | |||
return; | |||
if (((key.singleUse) || (this.destroyKey)) && (key.keyId !== 'world')) { | |||
if ((key.singleUse || this.destroyKey) && key.keyId !== 'world') { | |||
obj.inventory.destroyItem(key.id, 1); | |||
obj.instance.syncer.queue('onGetMessages', { | |||
id: obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'The ' + key.name + ' disintegrates on use', | |||
type: 'info' | |||
}] | |||
}, [obj.serverId]); | |||
const message = `The ${key.name} disintegrates on use`; | |||
obj.social.notifySelf({ message }); | |||
} | |||
} | |||
@@ -89,14 +89,8 @@ module.exports = { | |||
}; | |||
obj.fireEvent('beforeEquipItem', equipMsg); | |||
if (!equipMsg.success) { | |||
obj.instance.syncer.queue('onGetMessages', { | |||
id: obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: equipMsg.msg || 'you cannot equip that item', | |||
type: 'info' | |||
}] | |||
}, [obj.serverId]); | |||
const message = equipMsg.msg || 'you cannot equip that item'; | |||
obj.social.notifySelf({ message }); | |||
return; | |||
} | |||
@@ -154,14 +148,8 @@ module.exports = { | |||
if (!item) | |||
return; | |||
else if (!ignoreSpaceCheck && !inventory.hasSpace()) { | |||
obj.instance.syncer.queue('onGetMessages', { | |||
id: obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'You do not have room in your inventory to unequip that item', | |||
type: 'info' | |||
}] | |||
}, [obj.serverId]); | |||
const message = 'You do not have room in your inventory to unequip that item'; | |||
obj.social.notifySelf({ message }); | |||
return; | |||
} | |||
@@ -277,14 +265,10 @@ module.exports = { | |||
level: `Your level is too low to equip your ${item.name}` | |||
})[errors[0]]; | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: message, | |||
type: 'rep' | |||
}] | |||
}, [this.obj.serverId]); | |||
this.obj.social.notifySelf({ | |||
message, | |||
type: 'rep' | |||
}); | |||
} | |||
}, this); | |||
}, | |||
@@ -308,14 +292,11 @@ module.exports = { | |||
if (findFaction.tier > tier) { | |||
this.unequip(itemId); | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'You unequip your ' + item.name + ' as it zaps you.', | |||
type: 'rep' | |||
}] | |||
}, [this.obj.serverId]); | |||
const message = `You unequip your ${item.name} as it zaps you.`; | |||
this.obj.social.notifySelf({ | |||
message, | |||
type: 'rep' | |||
}); | |||
} | |||
}, this); | |||
}, | |||
@@ -161,14 +161,8 @@ module.exports = { | |||
result = requestedBy.reputation.canEquipItem(item); | |||
if (!result) { | |||
requestedBy.instance.syncer.queue('onGetMessages', { | |||
id: requestedBy.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'your reputation is too low to buy that item', | |||
type: 'info' | |||
}] | |||
}, [requestedBy.serverId]); | |||
const message = 'your reputation is too low to buy that item'; | |||
requestedBy.social.notifySelf({ message }); | |||
} | |||
return result; | |||
@@ -187,6 +187,7 @@ module.exports = { | |||
this.sendAnnouncement('The school has been depleted'); | |||
this.nodes.spliceWhere(n => (n === gathering)); | |||
this.updateServerActions(false); | |||
} | |||
this.gathering = null; | |||
@@ -201,36 +202,33 @@ module.exports = { | |||
}, | |||
enter: function (node) { | |||
const { obj } = this; | |||
let gatherResult = extend({ | |||
nodeName: node.name | |||
}); | |||
this.obj.instance.eventEmitter.emitNoSticky('beforeEnterPool', gatherResult, this.obj); | |||
obj.instance.eventEmitter.emitNoSticky('beforeEnterPool', gatherResult, obj); | |||
let nodeType = node.resourceNode.nodeType; | |||
let msg = `Press G to $ (${gatherResult.nodeName})`; | |||
msg = msg.replace('$', { | |||
herb: 'gather', | |||
fish: 'fish for' | |||
}[nodeType]); | |||
if (nodeType === 'fish') { | |||
if (!this.obj.equipment.eq.has('tool')) | |||
msg = 'You need a fishing rod to fish'; | |||
if (!obj.equipment.eq.has('tool')) { | |||
this.sendAnnouncement('You need a fishing rod to fish'); | |||
return; | |||
} | |||
} | |||
this.sendAnnouncement(msg); | |||
this.updateServerActions(true); | |||
process.send({ | |||
method: 'events', | |||
data: { | |||
onEnterGatherNode: [{ | |||
obj: { | |||
id: node.id | |||
}, | |||
to: [this.obj.serverId] | |||
}] | |||
} | |||
}); | |||
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); | |||
@@ -240,17 +238,7 @@ module.exports = { | |||
if (!this.nodes.includes(node)) | |||
return; | |||
process.send({ | |||
method: 'events', | |||
data: { | |||
onExitGatherNode: [{ | |||
obj: { | |||
id: node.id | |||
}, | |||
to: [this.obj.serverId] | |||
}] | |||
} | |||
}); | |||
this.updateServerActions(false); | |||
this.nodes.spliceWhere(n => (n === node)); | |||
}, | |||
@@ -269,6 +257,20 @@ module.exports = { | |||
}); | |||
}, | |||
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); | |||
@@ -1,6 +1,5 @@ | |||
let generator = require('../items/generator'); | |||
let salvager = require('../items/salvager'); | |||
let enchanter = require('../items/enchanter'); | |||
let classes = require('../config/spirits'); | |||
let mtx = require('../mtx/mtx'); | |||
let factions = require('../config/factions'); | |||
@@ -10,8 +9,6 @@ const events = require('../misc/events'); | |||
const { isItemStackable } = require('./inventory/helpers'); | |||
const transactions = require('../security/transactions'); | |||
const { applyItemStats } = require('./equipment/helpers'); | |||
const getItem = require('./inventory/getItem'); | |||
const dropBag = require('./inventory/dropBag'); | |||
const useItem = require('./inventory/useItem'); | |||
@@ -151,45 +148,6 @@ module.exports = { | |||
} | |||
}, | |||
enchantItem: function (msg) { | |||
const { itemId, action } = msg; | |||
const item = this.findItem(itemId); | |||
if (!item) | |||
return; | |||
const { eq, slot, power, noAugment } = item; | |||
if (!slot || noAugment || (action === 'scour' && !power)) { | |||
this.resolveCallback(msg); | |||
return; | |||
} | |||
const obj = this.obj; | |||
if (eq) { | |||
applyItemStats(obj, item, false); | |||
enchanter.enchant(obj, item, msg); | |||
applyItemStats(obj, item, true); | |||
if (item.slot !== slot) | |||
obj.equipment.unequip(itemId); | |||
else | |||
obj.spellbook.calcDps(); | |||
} else | |||
enchanter.enchant(obj, item, msg); | |||
obj.equipment.unequipAttrRqrGear(); | |||
}, | |||
getEnchantMaterials: function (msg) { | |||
let result = []; | |||
let item = this.findItem(msg.itemId); | |||
if ((item) && (item.slot)) | |||
result = enchanter.getEnchantMaterials(item, msg.action); | |||
this.resolveCallback(msg, result); | |||
}, | |||
learnAbility: function (itemId, runeSlot) { | |||
if (itemId.has('itemId')) { | |||
let msg = itemId; | |||
@@ -215,14 +173,8 @@ module.exports = { | |||
}; | |||
this.obj.fireEvent('beforeLearnAbility', learnMsg); | |||
if (!learnMsg.success) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: learnMsg.msg || 'you cannot learn that ability', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
const message = learnMsg.msg || 'you cannot learn that ability'; | |||
this.obj.social.notifySelf({ message }); | |||
return; | |||
} | |||
@@ -365,15 +317,12 @@ module.exports = { | |||
this.getItem(material, true, false, false, true); | |||
messages.push({ | |||
class: 'q' + material.quality, | |||
className: 'q' + material.quality, | |||
message: 'salvage (' + material.name + ' x' + material.quantity + ')' | |||
}); | |||
} | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: messages | |||
}, [this.obj.serverId]); | |||
this.obj.social.notifySelfArray(messages); | |||
}, | |||
destroyItem: function (id, amount, force) { | |||
@@ -515,8 +464,11 @@ module.exports = { | |||
try { | |||
let effectModule = require('../' + effectUrl); | |||
e.events = effectModule.events; | |||
e.text = effectModule.events.onGetText(item, e); | |||
} catch (error) {} | |||
if (effectModule.events.onGetText) | |||
e.text = effectModule.events.onGetText(item, e); | |||
} catch (error) { | |||
_.log(`Effect not found: ${e.type}`); | |||
} | |||
} | |||
}); | |||
} | |||
@@ -623,7 +575,7 @@ module.exports = { | |||
let item = generator.generate({ | |||
type: classes.weapons[this.obj.class], | |||
quality: 0, | |||
spellQuality: 'basic' | |||
spellQuality: 0 | |||
}); | |||
item.worth = 0; | |||
item.eq = true; | |||
@@ -642,7 +594,7 @@ module.exports = { | |||
if (!hasSpell) { | |||
let item = generator.generate({ | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
spellName: spellName | |||
}); | |||
item.worth = 0; | |||
@@ -805,13 +757,6 @@ module.exports = { | |||
}, | |||
notifyNoBagSpace: function (message = 'Your bags are too full to loot any more items') { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message, | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
this.obj.social.notifySelf({ message }); | |||
} | |||
}; |
@@ -40,6 +40,7 @@ module.exports = async (cpnInv, itemId) => { | |||
let result = {}; | |||
obj.instance.eventEmitter.emit('onBeforeUseItem', obj, item, result); | |||
obj.fireEvent('onBeforeUseItem', item, result); | |||
if (item.recipe) { | |||
const didLearn = await learnRecipe(obj, item); | |||
@@ -68,14 +69,7 @@ module.exports = async (cpnInv, itemId) => { | |||
effectEvent.call(obj, effectResult, item, effect); | |||
if (!effectResult.success) { | |||
obj.instance.syncer.queue('onGetMessages', { | |||
id: obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: effectResult.errorMessage, | |||
type: 'info' | |||
}] | |||
}, [obj.serverId]); | |||
obj.social.notifySelf({ message: effectResult.errorMessage }); | |||
return; | |||
} | |||
@@ -41,6 +41,9 @@ module.exports = { | |||
if (blueprint.patrol) | |||
this.patrol = blueprint.patrol; | |||
if (blueprint.maxChaseDistance) | |||
this.maxChaseDistance = blueprint.maxChaseDistance; | |||
}, | |||
update: function () { | |||
@@ -121,14 +121,11 @@ module.exports = { | |||
if (gain < 0) | |||
action = 'lost'; | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: (action === 'gained') ? 'color-greenB' : 'color-redA', | |||
message: 'you ' + action + ' ' + Math.abs(gain) + ' reputation with ' + blueprint.name, | |||
type: 'rep' | |||
}] | |||
}, [this.obj.serverId]); | |||
this.obj.social.notifySelf({ | |||
className: (action === 'gained') ? 'color-greenB' : 'color-redA', | |||
message: 'you ' + action + ' ' + Math.abs(gain) + ' reputation with ' + blueprint.name, | |||
type: 'rep' | |||
}); | |||
if (faction.tier !== oldTier) { | |||
this.sendMessage(blueprint.tiers[faction.tier].name, blueprint.name, (faction.tier > oldTier)); | |||
@@ -139,14 +136,11 @@ module.exports = { | |||
}, | |||
sendMessage: function (tierName, factionName, didIncrease) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: didIncrease ? 'color-greenB' : 'color-redA', | |||
message: 'you are now ' + tierName + ' with ' + factionName, | |||
type: 'rep' | |||
}] | |||
}, [this.obj.serverId]); | |||
this.obj.social.notifySelf({ | |||
className: didIncrease ? 'color-greenB' : 'color-redA', | |||
message: 'you are now ' + tierName + ' with ' + factionName, | |||
type: 'rep' | |||
}); | |||
}, | |||
discoverFaction (factionId) { | |||
@@ -167,14 +161,11 @@ module.exports = { | |||
let tier = blueprint.tiers[this.calculateTier(factionId)].name.toLowerCase(); | |||
if (!blueprint.noGainRep) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'q4', | |||
message: 'you are now ' + tier + ' with ' + blueprint.name, | |||
type: 'rep' | |||
}] | |||
}, [this.obj.serverId]); | |||
this.obj.social.notifySelf({ | |||
className: 'q4', | |||
message: 'you are now ' + tier + ' with ' + blueprint.name, | |||
type: 'rep' | |||
}); | |||
} | |||
this.syncFaction(factionId, true); | |||
@@ -613,6 +613,10 @@ module.exports = { | |||
this.stopCasting(null, true); | |||
}, | |||
onBeforeUseItem: function () { | |||
this.stopCasting(null, true); | |||
}, | |||
clearQueue: function () { | |||
this.stopCasting(null, true); | |||
}, | |||
@@ -69,14 +69,9 @@ module.exports = { | |||
else if (this.items.length >= this.maxItems) { | |||
let isStackable = this.items.some(stashedItem => item.name === stashedItem.name && (isItemStackable(stashedItem))); | |||
if (!isStackable) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'You do not have room in your stash to deposit that item', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
const message = 'You do not have room in your stash to deposit that item'; | |||
this.obj.social.notifySelf({ message }); | |||
return; | |||
} | |||
} | |||
@@ -109,14 +104,8 @@ module.exports = { | |||
if (!item) | |||
return; | |||
else if (!this.obj.inventory.hasSpace(item)) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'You do not have room in your inventory to withdraw that item', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
const message = 'You do not have room in your inventory to withdraw that item'; | |||
this.obj.social.notifySelf({ message }); | |||
return; | |||
} | |||
@@ -146,14 +135,8 @@ module.exports = { | |||
}); | |||
if (this.active && this.items.length > this.maxItems) { | |||
obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: `You have more than ${this.maxItems} items in your stash. In the next version (v0.3.1) you will lose all items that put you over the limit`, | |||
type: 'info' | |||
}] | |||
}, [obj.serverId]); | |||
const message = `You have more than ${this.maxItems} items in your stash. In the future, these items will be lost.`; | |||
obj.social.notifySelf({ message }); | |||
} | |||
}, | |||
@@ -103,10 +103,15 @@ module.exports = { | |||
return; | |||
obj.skinId = msg.skinId; | |||
obj.cell = skins.getCell(obj.skinId); | |||
obj.sheetName = skins.getSpritesheet(obj.skinId); | |||
obj.fireEvent('onBeforeSkinChange', { | |||
newSkinId: obj.skinId, | |||
newCell: obj.cell, | |||
newSheetName: obj.sheetName | |||
}); | |||
let syncer = obj.syncer; | |||
syncer.set(false, null, 'cell', obj.cell); | |||
syncer.set(false, null, 'sheetName', obj.sheetName); | |||
@@ -1,13 +1,18 @@ | |||
const recipes = require('../config/recipes/recipes'); | |||
const generator = require('../items/generator'); | |||
const buildRecipe = require('./workbench/buildRecipe'); | |||
const craft = require('./workbench/craft'); | |||
module.exports = { | |||
type: 'workbench', | |||
craftType: null, | |||
noticeMessage: null, | |||
init: function (blueprint) { | |||
this.craftType = blueprint.type; | |||
this.noticeMessage = blueprint.noticeMessage; | |||
this.obj.instance.objects.buildObjects([{ | |||
properties: { | |||
@@ -55,7 +60,7 @@ module.exports = { | |||
if (!obj.player) | |||
return; | |||
let msg = `Press U to access the ${this.obj.name}`; | |||
let msg = `Press U to ${this.noticeMessage || `access the ${this.obj.name}`}`; | |||
obj.syncer.setArray(true, 'serverActions', 'addActions', { | |||
key: 'u', | |||
@@ -98,93 +103,21 @@ module.exports = { | |||
}, [obj.serverId]); | |||
}, | |||
buildRecipe: function (crafter, recipeName) { | |||
let recipe = recipes.getRecipe(this.craftType, recipeName); | |||
if (!recipe) | |||
return; | |||
const items = crafter.inventory.items; | |||
let sendRecipe = extend({}, recipe); | |||
(sendRecipe.materials || []).forEach(function (m) { | |||
m.need = !items.some(i => ( | |||
( | |||
i.name === m.name || | |||
i.name.indexOf(m.nameLike) > -1 | |||
) && | |||
( | |||
m.quantity === 1 || | |||
i.quantity >= m.quantity | |||
) | |||
)); | |||
}); | |||
return sendRecipe; | |||
}, | |||
getRecipe: function (msg) { | |||
let obj = this.obj.instance.objects.objects.find(o => o.serverId === msg.sourceId); | |||
if ((!obj) || (!obj.player)) | |||
return; | |||
const sendRecipe = this.buildRecipe(obj, msg.name); | |||
const sendRecipe = buildRecipe(this.craftType, obj, msg); | |||
this.resolveCallback(msg, sendRecipe); | |||
}, | |||
craft: function (msg) { | |||
let obj = this.obj.instance.objects.objects.find(o => o.serverId === msg.sourceId); | |||
if ((!obj) || (!obj.player)) | |||
return; | |||
let recipe = recipes.getRecipe(this.craftType, msg.name); | |||
if (!recipe) | |||
return; | |||
const items = obj.inventory.items; | |||
let canCraft = recipe.materials.every(m => (items.some(i => ( | |||
( | |||
i.name === m.name || | |||
i.name.indexOf(m.nameLike) > -1 | |||
) && | |||
( | |||
m.quantity === 1 || | |||
i.quantity >= m.quantity | |||
) | |||
)))); | |||
if (!canCraft) | |||
return; | |||
recipe.materials.forEach(m => { | |||
let findItem = obj.inventory.items.find(f => ( | |||
f.name === m.name || | |||
f.name.indexOf(m.nameLike) > -1 | |||
)); | |||
obj.inventory.destroyItem(findItem.id, m.quantity); | |||
}); | |||
let outputItems = recipe.item ? [ recipe.item ] : recipe.items; | |||
outputItems.forEach(itemBpt => { | |||
let item = null; | |||
if (itemBpt.generate) | |||
item = generator.generate(itemBpt); | |||
else | |||
item = extend({}, itemBpt); | |||
if (item.description) | |||
item.description += `<br /><br />(Crafted by ${obj.name})`; | |||
else | |||
item.description = `<br /><br />(Crafted by ${obj.name})`; | |||
const quantity = item.quantity; | |||
if (quantity && quantity.push) | |||
item.quantity = quantity[0] + ~~(Math.random() * (quantity[1] - quantity[0])); | |||
obj.inventory.getItem(item); | |||
}); | |||
const result = craft(this, msg); | |||
this.resolveCallback(msg, this.buildRecipe(obj, msg.name)); | |||
if (result) | |||
this.resolveCallback(msg, result); | |||
}, | |||
resolveCallback: function (msg, result) { | |||
@@ -0,0 +1,49 @@ | |||
const buildPickedItems = require('./buildPickedItems'); | |||
module.exports = (crafter, recipe, msg) => { | |||
const { inventory: { items } } = crafter; | |||
const { materialGenerator, materials, needItems = [] } = recipe; | |||
const { pickedItemIds = [] } = msg; | |||
const pickedItems = buildPickedItems(crafter, recipe, msg); | |||
const allPickedItemsSet = ( | |||
pickedItemIds.length === needItems.length && | |||
!pickedItems.some(i => !i) | |||
); | |||
if (!allPickedItemsSet) | |||
return []; | |||
let useMaterials = materials; | |||
if (materialGenerator) | |||
useMaterials = materialGenerator(crafter, pickedItems); | |||
const result = useMaterials.map(m => { | |||
const { name, nameLike, quantity } = m; | |||
const haveMaterial = items.find(i => ( | |||
i.name === name || | |||
i.name.includes(nameLike) | |||
)); | |||
const id = haveMaterial ? haveMaterial.id : null; | |||
const haveQuantity = haveMaterial ? (haveMaterial.quantity || 1) : 0; | |||
const needQuantity = quantity; | |||
const noHaveEnough = haveQuantity < needQuantity; | |||
const material = { | |||
id, | |||
name, | |||
nameLike, | |||
haveQuantity, | |||
needQuantity, | |||
noHaveEnough | |||
}; | |||
return material; | |||
}); | |||
return result; | |||
}; |
@@ -0,0 +1,29 @@ | |||
module.exports = ({ inventory: { items } }, { needItems }) => { | |||
if (!needItems) | |||
return null; | |||
const result = needItems.map(n => { | |||
const { info, withProps = [], withoutProps = [], checks = [] } = n; | |||
const allowedItemIds = items | |||
.filter(item => { | |||
const isValidItem = ( | |||
withProps.every(p => item.has(p)) && | |||
withoutProps.every(p => !item.has(p)) && | |||
checks.every(c => c(item)) | |||
); | |||
return isValidItem; | |||
}) | |||
.map(item => item.id); | |||
const needItem = { | |||
info, | |||
allowedItemIds | |||
}; | |||
return needItem; | |||
}); | |||
return result; | |||
}; |
@@ -0,0 +1,19 @@ | |||
const buildNeedItems = require('./buildNeedItems'); | |||
module.exports = (crafter, recipe, { pickedItemIds = [] }) => { | |||
const needItems = buildNeedItems(crafter, recipe); | |||
const { inventory: { items } } = crafter; | |||
const result = pickedItemIds.map((pickedId, i) => { | |||
const item = items.find(f => f.id === pickedId); | |||
const isItemValid = needItems[i].allowedItemIds.includes(item.id); | |||
if (!isItemValid) | |||
return null; | |||
return item; | |||
}); | |||
return result; | |||
}; |
@@ -0,0 +1,30 @@ | |||
const recipes = require('../../config/recipes/recipes'); | |||
const buildMaterials = require('./buildMaterials'); | |||
const buildNeedItems = require('./buildNeedItems'); | |||
const buildBase = (crafter, { name, description }) => { | |||
return { | |||
name, | |||
description | |||
}; | |||
}; | |||
module.exports = (craftType, crafter, msg) => { | |||
const recipe = recipes.getRecipe(craftType, msg.name); | |||
if (!recipe) | |||
return; | |||
const result = buildBase(crafter, recipe); | |||
const needItems = buildNeedItems(crafter, recipe); | |||
if (needItems) | |||
result.needItems = needItems; | |||
if (recipe.materialGenerator || recipe.needItems) | |||
result.dynamicMaterials = true; | |||
result.materials = buildMaterials(crafter, recipe, msg); | |||
return result; | |||
}; |
@@ -0,0 +1,97 @@ | |||
const recipes = require('../../config/recipes/recipes'); | |||
const generator = require('../../items/generator'); | |||
const { applyItemStats } = require('../equipment/helpers'); | |||
const buildRecipe = require('../workbench/buildRecipe'); | |||
const buildMaterials = require('../workbench/buildMaterials'); | |||
const buildPickedItems = require('../workbench/buildPickedItems'); | |||
module.exports = (cpnWorkbench, msg) => { | |||
const { craftType, obj: { instance: { objects: { objects } } } } = cpnWorkbench; | |||
const { name: recipeName, sourceId } = msg; | |||
const crafter = objects.find(o => o.serverId === sourceId); | |||
if (!crafter || !crafter.player) | |||
return null; | |||
const recipe = recipes.getRecipe(craftType, recipeName); | |||
if (!recipe) | |||
return null; | |||
const { needItems = [] } = recipe; | |||
const { syncer, inventory, equipment, spellbook } = crafter; | |||
const materials = buildMaterials(crafter, recipe, msg); | |||
const pickedItems = buildPickedItems(crafter, recipe, msg); | |||
const canCraft = ( | |||
!materials.some(m => m.noHaveEnough) && | |||
pickedItems.length === needItems.length && | |||
!pickedItems.some(i => !i) | |||
); | |||
if (!canCraft) | |||
return null; | |||
materials.forEach(m => inventory.destroyItem(m.id, m.needQuantity)); | |||
let resultMsg = null; | |||
if (recipe.craftAction) { | |||
pickedItems.forEach(p => { | |||
if (p.eq) | |||
applyItemStats(crafter, p, false); | |||
}); | |||
const oldSlots = pickedItems.map(p => p.slot); | |||
resultMsg = recipe.craftAction(crafter, pickedItems); | |||
pickedItems.forEach((p, i) => { | |||
if (!p.eq) { | |||
pickedItems.forEach(item => syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item))); | |||
return; | |||
} | |||
applyItemStats(crafter, p, true); | |||
if (p.slot !== oldSlots[i]) | |||
equipment.unequip(p.id); | |||
spellbook.calcDps(); | |||
pickedItems.forEach(item => syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item))); | |||
}); | |||
equipment.unequipAttrRqrGear(); | |||
} | |||
if (recipe.item || recipe.items) { | |||
const outputItems = recipe.item ? [ recipe.item ] : recipe.items; | |||
outputItems.forEach(itemBpt => { | |||
let item = null; | |||
if (itemBpt.generate) | |||
item = generator.generate(itemBpt); | |||
else | |||
item = extend({}, itemBpt); | |||
if (item.description) | |||
item.description += `<br /><br />(Crafted by ${crafter.name})`; | |||
else | |||
item.description = `<br /><br />(Crafted by ${crafter.name})`; | |||
const quantity = item.quantity; | |||
if (quantity && quantity.push) | |||
item.quantity = quantity[0] + ~~(Math.random() * (quantity[1] - quantity[0])); | |||
crafter.inventory.getItem(item); | |||
}); | |||
} | |||
const result = { | |||
resultMsg, | |||
recipe: buildRecipe(craftType, crafter, msg) | |||
}; | |||
return result; | |||
}; |
@@ -4,6 +4,27 @@ const tos = require('./tos'); | |||
const config = { | |||
logoPath: null, | |||
resourceList: [], | |||
textureList: [ | |||
'tiles', | |||
'walls', | |||
'mobs', | |||
'bosses', | |||
'animBigObjects', | |||
'bigObjects', | |||
'objects', | |||
'characters', | |||
'attacks', | |||
'ui', | |||
'auras', | |||
'animChar', | |||
'animMob', | |||
'animBoss', | |||
'white', | |||
'ray', | |||
'images/skins/0001.png', | |||
'images/skins/0010.png', | |||
'images/skins/0012.png' | |||
], | |||
uiList: [], | |||
contextMenuActions: { | |||
player: [], | |||
@@ -21,6 +42,7 @@ module.exports = { | |||
events.emit('onBeforeGetUiList', config.uiList); | |||
events.emit('onBeforeGetContextMenuActions', config.contextMenuActions); | |||
events.emit('onBeforeGetTermsOfService', config.tos); | |||
events.emit('onBeforeGetTextureList', config.textureList); | |||
}, | |||
getClientConfig: function (msg) { | |||
@@ -179,66 +179,8 @@ module.exports = { | |||
vikar: { | |||
1: { | |||
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: [] | |||
}], | |||
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' | |||
}] | |||
} | |||
}, | |||
@@ -18,14 +18,6 @@ module.exports = { | |||
type: 'fish', | |||
quantity: [6, 12] | |||
}, | |||
vikardoor: { | |||
properties: { | |||
cpnDoor: { | |||
locked: true, | |||
key: 'vikar' | |||
} | |||
} | |||
}, | |||
shopestrid: { | |||
properties: { | |||
cpnNotice: { | |||
@@ -523,6 +515,61 @@ module.exports = { | |||
type: 'cooking' | |||
} | |||
} | |||
}, | |||
'enchanting shrine': { | |||
components: { | |||
cpnParticles: { | |||
simplify: function () { | |||
return { | |||
type: 'particles', | |||
blueprint: { | |||
color: { | |||
start: ['48edff', 'fc66f7'], | |||
end: ['393268', '42548d'] | |||
}, | |||
scale: { | |||
start: { | |||
min: 2, | |||
max: 10 | |||
}, | |||
end: { | |||
min: 0, | |||
max: 2 | |||
} | |||
}, | |||
speed: { | |||
start: { | |||
min: 4, | |||
max: 16 | |||
}, | |||
end: { | |||
min: 2, | |||
max: 8 | |||
} | |||
}, | |||
lifetime: { | |||
min: 1, | |||
max: 4 | |||
}, | |||
randomScale: true, | |||
randomSpeed: true, | |||
chance: 0.2, | |||
randomColor: true, | |||
spawnType: 'rect', | |||
spawnRect: { | |||
x: -15, | |||
y: -28, | |||
w: 30, | |||
h: 8 | |||
} | |||
} | |||
}; | |||
} | |||
}, | |||
cpnWorkbench: { | |||
type: 'enchanting' | |||
} | |||
} | |||
} | |||
}, | |||
mobs: { | |||
@@ -592,6 +639,8 @@ module.exports = { | |||
}, | |||
thumper: { | |||
level: 5, | |||
cron: '0 * * * *', | |||
regular: { | |||
hpMult: 3, | |||
dmgMult: 3, | |||
@@ -805,56 +854,56 @@ module.exports = { | |||
extra: [{ | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'magic missile', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'ice spear', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'smite', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'consecrate', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'slash', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'charge', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'flurry', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'smokebomb', | |||
worth: 3 | |||
@@ -957,6 +1006,116 @@ module.exports = { | |||
} | |||
} | |||
} | |||
}, | |||
sundfehr: { | |||
level: 9, | |||
walkDistance: 0, | |||
cron: '0 */2 * * *', | |||
regular: { | |||
hpMult: 10, | |||
dmgMult: 1, | |||
drops: { | |||
chance: 100, | |||
rolls: 3, | |||
magicFind: [2000] | |||
} | |||
}, | |||
rare: { | |||
chance: 0 | |||
}, | |||
spells: [{ | |||
type: 'warnBlast', | |||
range: 8, | |||
delay: 9, | |||
damage: 0.8, | |||
statMult: 1, | |||
cdMax: 7, | |||
targetRandom: true, | |||
particles: { | |||
color: { | |||
start: ['c0c3cf', '929398'], | |||
end: ['929398', 'c0c3cf'] | |||
}, | |||
spawnType: 'circle', | |||
spawnCircle: { | |||
x: 0, | |||
y: 0, | |||
r: 12 | |||
}, | |||
randomColor: true, | |||
chance: 0.03 | |||
} | |||
}, { | |||
type: 'projectile', | |||
damage: 0.4, | |||
statMult: 1, | |||
cdMax: 5, | |||
targetRandom: true, | |||
row: 2, | |||
col: 4 | |||
}], | |||
components: { | |||
cpnParticles: { | |||
simplify: function () { | |||
return { | |||
type: 'particles', | |||
blueprint: { | |||
color: { | |||
start: ['fc66f7', '802343'], | |||
end: ['393268', 'de43ae'] | |||
}, | |||
scale: { | |||
start: { | |||
min: 10, | |||
max: 18 | |||
}, | |||
end: { | |||
min: 4, | |||
max: 8 | |||
} | |||
}, | |||
speed: { | |||
start: { | |||
min: 6, | |||
max: 12 | |||
}, | |||
end: { | |||
min: 2, | |||
max: 4 | |||
} | |||
}, | |||
lifetime: { | |||
min: 5, | |||
max: 12 | |||
}, | |||
alpha: { | |||
start: 0.25, | |||
end: 0 | |||
}, | |||
randomScale: true, | |||
randomSpeed: true, | |||
chance: 0.06, | |||
randomColor: true, | |||
spawnType: 'rect', | |||
blendMode: 'add', | |||
spawnRect: { | |||
x: -24, | |||
y: -24, | |||
w: 48, | |||
h: 48 | |||
} | |||
} | |||
}; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}; |
@@ -1,4 +1,12 @@ | |||
{ "backgroundcolor":"#32222e", | |||
"compressionlevel":-1, | |||
"editorsettings": | |||
{ | |||
"export": | |||
{ | |||
"target":"." | |||
} | |||
}, | |||
"height":120, | |||
"infinite":false, | |||
"layers":[ | |||
@@ -2043,7 +2051,7 @@ | |||
"type":"", | |||
"visible":true, | |||
"width":8, | |||
"x":568, | |||
"x":528, | |||
"y":736 | |||
}, | |||
{ | |||
@@ -2175,8 +2183,8 @@ | |||
"type":"", | |||
"visible":true, | |||
"width":8, | |||
"x":480, | |||
"y":744 | |||
"x":464, | |||
"y":752 | |||
}, | |||
{ | |||
"gid":273, | |||
@@ -2307,7 +2315,7 @@ | |||
"type":"", | |||
"visible":true, | |||
"width":8, | |||
"x":536, | |||
"x":520, | |||
"y":808 | |||
}, | |||
{ | |||
@@ -2319,8 +2327,20 @@ | |||
"type":"", | |||
"visible":true, | |||
"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, | |||
"type":"objectgroup", | |||
@@ -2329,7 +2349,7 @@ | |||
"y":0 | |||
}], | |||
"nextlayerid":60, | |||
"nextobjectid":1291, | |||
"nextobjectid":1292, | |||
"orientation":"orthogonal", | |||
"properties":[ | |||
{ | |||
@@ -2338,7 +2358,7 @@ | |||
"value":"[{\"x\":97,\"y\":87}]" | |||
}], | |||
"renderorder":"right-down", | |||
"tiledversion":"1.2.5", | |||
"tiledversion":"1.3.3", | |||
"tileheight":8, | |||
"tilesets":[ | |||
{ | |||
@@ -15,13 +15,11 @@ module.exports = { | |||
this.obj.syncer.setArray(true, 'quests', 'obtainQuests', this.simplify(true)); | |||
if (!hideMessage) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-yellowB', | |||
message: 'quest obtained (' + this.name + ')' | |||
}] | |||
}, [this.obj.serverId]); | |||
const message = `Quest obtained (${this.name})`; | |||
this.obj.social.notifySelf({ | |||
message, | |||
className: 'color-yellowB' | |||
}); | |||
} | |||
return true; | |||
@@ -33,13 +31,11 @@ module.exports = { | |||
if (this.oReady) | |||
this.oReady(); | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-yellowB', | |||
message: 'quest ready for turn-in (' + this.name + ')' | |||
}] | |||
}, [this.obj.serverId]); | |||
const message = `Quest ready for turn-in (${this.name})`; | |||
this.obj.social.notifySelf({ | |||
message, | |||
className: 'color-yellowB' | |||
}); | |||
this.obj.syncer.setArray(true, 'quests', 'updateQuests', this.simplify(true)); | |||
}, | |||
@@ -48,27 +44,23 @@ module.exports = { | |||
if (this.oComplete) | |||
this.oComplete(); | |||
let obj = this.obj; | |||
const obj = this.obj; | |||
this.obj.instance.eventEmitter.emitNoSticky('beforeCompleteAutoquest', this, obj); | |||
obj.instance.eventEmitter.emitNoSticky('beforeCompleteAutoquest', this, obj); | |||
obj.instance.syncer.queue('onGetMessages', { | |||
id: obj.id, | |||
messages: [{ | |||
class: 'color-yellowB', | |||
message: 'quest completed (' + this.name + ')' | |||
}] | |||
}, [obj.serverId]); | |||
const message = `Quest completed (${this.name})`; | |||
obj.social.notifySelf({ | |||
message, | |||
className: 'color-yellowB' | |||
}); | |||
obj.syncer.setArray(true, 'quests', 'completeQuests', this.id); | |||
this.obj.instance.eventEmitter.emit('onCompleteQuest', this); | |||
obj.instance.eventEmitter.emit('onCompleteQuest', this); | |||
this.rewards.forEach(function (r) { | |||
this.obj.inventory.getItem(r); | |||
}, this); | |||
this.rewards.forEach(reward => obj.inventory.getItem(reward)); | |||
this.obj.stats.getXp(this.xp || 10, this.obj, this); | |||
obj.stats.getXp(this.xp || 10, obj, this); | |||
}, | |||
simplify: function (self) { | |||
@@ -0,0 +1,94 @@ | |||
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 | |||
] | |||
}]; |
@@ -0,0 +1,17 @@ | |||
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; | |||
}; |
@@ -0,0 +1,17 @@ | |||
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; | |||
}; |
@@ -0,0 +1,20 @@ | |||
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 }; | |||
}; |
@@ -0,0 +1,20 @@ | |||
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 }; | |||
}; |
@@ -0,0 +1,58 @@ | |||
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' }; | |||
}; |
@@ -0,0 +1,36 @@ | |||
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 }; | |||
}; |
@@ -0,0 +1,31 @@ | |||
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,17 +3,13 @@ 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 | |||
] | |||
alchemy: [ ...recipesAlchemy ], | |||
cooking: [ ...recipesCooking ], | |||
etching: [ ...recipesEtching ], | |||
enchanting: [ ...recipesEnchanting ] | |||
}; | |||
module.exports = { | |||
@@ -22,7 +18,11 @@ module.exports = { | |||
}, | |||
getList: function (type, unlocked) { | |||
return (recipes[type] || []) | |||
const useRecipes = recipes[type]; | |||
if (!useRecipes) | |||
return []; | |||
return useRecipes | |||
.filter(r => { | |||
let hasUnlocked = (r.default !== false); | |||
if (!hasUnlocked) | |||
@@ -82,14 +82,8 @@ module.exports = { | |||
}, | |||
sendMessage: function (player, msg) { | |||
msg = 'Only certain roles can ' + msg + ' at the moment'; | |||
player.instance.syncer.queue('onGetMessages', { | |||
id: player.id, | |||
messages: { | |||
class: 'color-redA', | |||
message: msg | |||
} | |||
}, [player.serverId]); | |||
const message = `Only certain roles can ${msg} at the moment`; | |||
player.social.notifySelf({ message }); | |||
} | |||
}; |
@@ -1,5 +1,5 @@ | |||
module.exports = { | |||
version: '0.5.1', | |||
version: '0.6', | |||
port: 4000, | |||
startupMessage: 'Server: ready', | |||
defaultZone: 'fjolarok', | |||
@@ -9,6 +9,7 @@ module.exports = { | |||
range: 9, | |||
speed: 150, | |||
statMult: 1, | |||
damage: 1, | |||
row: 3, | |||
@@ -280,6 +280,9 @@ module.exports = { | |||
noMitigate: noMitigate | |||
}; | |||
if (this.obj.mob) | |||
config.noCrit = true; | |||
this.obj.fireEvent('onBeforeCalculateDamage', config); | |||
if (this.percentDamage) | |||
@@ -1,245 +0,0 @@ | |||
let generatorStats = require('./generators/stats'); | |||
let generatorSlots = require('./generators/slots'); | |||
let generatorTypes = require('./generators/types'); | |||
let generatorSpells = require('./generators/spellbook'); | |||
let salvager = require('./salvager'); | |||
let configCurrencies = require('./config/currencies'); | |||
let configSlots = require('./config/slots'); | |||
let generator = require('./generator'); | |||
const reroll = (item, msg) => { | |||
const enchantedStats = item.enchantedStats; | |||
const implicitStats = item.implicitStats; | |||
delete item.enchantedStats; | |||
delete item.implicitStats; | |||
delete msg.addStatMsgs; | |||
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; | |||
}; | |||
const relevel = 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 reslot = (item, msg) => { | |||
if (item.effects || item.slot === 'tool') | |||
return; | |||
if (item.originalLevel) | |||
item.level = item.originalLevel; | |||
delete item.enchantedStats; | |||
delete msg.addStatMsgs; | |||
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 reforge = 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 scour = (item, result) => { | |||
if (!item.power) | |||
return; | |||
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; | |||
}; | |||
const augment = (item, inventory, result, msg) => { | |||
let newPower = (item.power || 0) + 1; | |||
if (newPower > 3) { | |||
inventory.resolveCallback(msg); | |||
return; | |||
} | |||
item.power = newPower; | |||
generatorStats.generate(item, { | |||
statCount: 1 | |||
}, result); | |||
}; | |||
module.exports = { | |||
enchant: function (obj, item, msg) { | |||
let inventory = obj.inventory; | |||
let config = this.getEnchantMaterials(item, msg.action); | |||
let success = true; | |||
config.materials.forEach(function (m) { | |||
let hasMaterial = inventory.items.find(i => i.name === m.name); | |||
if (hasMaterial) | |||
hasMaterial = hasMaterial.quantity >= m.quantity; | |||
if (!hasMaterial) | |||
success = false; | |||
}); | |||
if (!success) { | |||
inventory.resolveCallback(msg); | |||
return; | |||
} | |||
let result = { | |||
item: item, | |||
addStatMsgs: [] | |||
}; | |||
config.materials.forEach(function (m) { | |||
let invMaterial = inventory.items.find(i => i.name === m.name); | |||
inventory.destroyItem(invMaterial.id, m.quantity); | |||
}); | |||
if (msg.action === 'reroll') | |||
reroll(item, msg); | |||
else if (msg.action === 'relevel') | |||
relevel(item); | |||
else if (msg.action === 'reslot') | |||
reslot(item, msg); | |||
else if (msg.action === 'reforge') | |||
reforge(item); | |||
else if (msg.action === 'scour') | |||
scour(item, result); | |||
else | |||
augment(item, inventory, result, msg); | |||
obj.syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item)); | |||
inventory.resolveCallback(msg, result); | |||
}, | |||
getEnchantMaterials: function (item, action) { | |||
let result = null; | |||
if (action === 'reroll') | |||
result = [configCurrencies.getCurrencyFromAction('reroll')]; | |||
else if (action === 'relevel') | |||
result = [configCurrencies.getCurrencyFromAction('relevel')]; | |||
else if (action === 'reslot') | |||
result = [configCurrencies.getCurrencyFromAction('reslot')]; | |||
else if (action === 'reforge') | |||
result = [configCurrencies.getCurrencyFromAction('reforge')]; | |||
else if (action === 'scour') | |||
result = [configCurrencies.getCurrencyFromAction('scour')]; | |||
else { | |||
let powerLevel = item.power || 0; | |||
let mult = null; | |||
if (powerLevel < 3) | |||
mult = [5, 10, 20][powerLevel]; | |||
else | |||
return; | |||
result = salvager.salvage(item, true); | |||
result.forEach(r => { | |||
r.quantity = Math.max(1, ~~(r.quantity * mult)); | |||
}); | |||
} | |||
return { | |||
materials: result | |||
}; | |||
} | |||
}; |
@@ -14,7 +14,7 @@ let g13 = require('./generators/recipeBook'); | |||
let generators = [g1, g2, g3, g4, g5, g6, g11, g12, g7]; | |||
let materialGenerators = [g6, g8]; | |||
let spellGenerators = [g1, g9, g7]; | |||
let spellGenerators = [g1, g2, g9, g7]; | |||
let currencyGenerators = [g10, g8]; | |||
let recipeGenerators = [g6, g13]; | |||
@@ -76,6 +76,7 @@ module.exports = { | |||
item.noDrop = blueprint.noDrop || null; | |||
item.noSalvage = blueprint.noSalvage || null; | |||
item.noDestroy = blueprint.noDestroy || null; | |||
item.quality = blueprint.quality || 0; | |||
materialGenerators.forEach(g => g.generate(item, blueprint)); | |||
} else if (blueprint.type === 'mtx') { | |||
item = extend({}, blueprint); | |||
@@ -2,6 +2,46 @@ let spells = require('../../config/spells'); | |||
let spellsConfig = require('../../config/spellsConfig'); | |||
let configTypes = require('../config/types'); | |||
const qualityGenerator = require('./quality'); | |||
const qualityCount = qualityGenerator.qualities.length; | |||
const buildRolls = (item, blueprint, { random: spellProperties, negativeStats = [] }, quality) => { | |||
//We randomise the order so a random property gets to 'pick first' | |||
// otherwise it's easier for earlier properties to use more of the valuePool | |||
const propKeys = Object | |||
.keys(spellProperties) | |||
.sort((a, b) => Math.random() - Math.random()); | |||
const propCount = propKeys.length; | |||
const maxRoll = (quality + 1) / qualityCount; | |||
const minSum = (quality / qualityCount) * propCount; | |||
let runningTotal = 0; | |||
const result = {}; | |||
for (let i = 0; i < propCount; i++) { | |||
const minRoll = Math.max(0, minSum - runningTotal - ((propCount - (i + 1)) * maxRoll)); | |||
let roll = minRoll + (Math.random() * (maxRoll - minRoll)); | |||
runningTotal += roll; | |||
const prop = propKeys[i]; | |||
const isNegative = negativeStats.includes(prop); | |||
if (isNegative) | |||
roll = 1 - roll; | |||
const scaledRoll = roll * (item.level / consts.maxLevel); | |||
result[prop] = scaledRoll; | |||
} | |||
return result; | |||
}; | |||
module.exports = { | |||
generate: function (item, blueprint) { | |||
blueprint = blueprint || {}; | |||
@@ -55,40 +95,46 @@ module.exports = { | |||
extend(spell, typeConfig.spellConfig); | |||
} | |||
let propertyPerfection = []; | |||
//If the item has a slot, we need to generate a new quality for the rune | |||
let quality = item.quality; | |||
if (item.slot) { | |||
const tempItem = {}; | |||
let randomProperties = spell.random || {}; | |||
let negativeStats = spell.negativeStats || []; | |||
for (let r in randomProperties) { | |||
let negativeStat = (negativeStats.indexOf(r) > -1); | |||
let range = randomProperties[r]; | |||
const tempBlueprint = extend(blueprint); | |||
delete tempBlueprint.quality; | |||
tempBlueprint.quality = blueprint.spellQuality; | |||
let max = Math.min(consts.maxLevel, item.level) / consts.maxLevel; | |||
qualityGenerator.generate(tempItem, tempBlueprint); | |||
let roll = random.expNorm(0, max); | |||
if (spellQuality === 'basic') | |||
roll = 0; | |||
else if (spellQuality === 'mid') | |||
roll = 0.5; | |||
quality = tempItem.quality; | |||
item.spell.quality = quality; | |||
} | |||
const rolls = buildRolls(item, blueprint, spell, quality); | |||
Object.entries(spell.random || {}).forEach(entry => { | |||
const [ property, range ] = entry; | |||
const roll = rolls[property]; | |||
item.spell.rolls[property] = roll; | |||
item.spell.rolls[r] = roll; | |||
const isInt = property.indexOf('i_') === 0; | |||
let useProperty = property; | |||
const minRange = range[0]; | |||
const maxRange = range[1]; | |||
let int = r.indexOf('i_') === 0; | |||
let val = range[0] + ((range[1] - range[0]) * roll); | |||
let val = minRange + ((maxRange - minRange) * roll); | |||
if (int) { | |||
val = ~~val; | |||
r = r.replace('i_', ''); | |||
if (isInt) { | |||
useProperty = property.substr(2); | |||
val = Math.round(val); | |||
} else | |||
val = ~~(val * 100) / 100; | |||
item.spell.values[r] = val; | |||
val = Math.max(range[0], Math.min(range[1], val)); | |||
if (negativeStat) | |||
propertyPerfection.push(1 - roll); | |||
else | |||
propertyPerfection.push(roll); | |||
} | |||
item.spell.values[useProperty] = val; | |||
}); | |||
if (blueprint.spellProperties) { | |||
item.spell.properties = {}; | |||
@@ -100,12 +146,5 @@ module.exports = { | |||
item.spell.properties = item.spell.properties || {}; | |||
item.spell.properties.range = item.range; | |||
} | |||
let per = propertyPerfection.reduce((p, n) => p + n, 0); | |||
let perfection = ~~((per / propertyPerfection.length) * 4); | |||
if (!item.slot) | |||
item.quality = perfection; | |||
else | |||
item.spell.quality = perfection; | |||
} | |||
}; |
@@ -54,14 +54,10 @@ module.exports = { | |||
} | |||
} else { | |||
if ((r.msg) && (!sentMessages.some(s => (s === r.msg)))) { | |||
player.instance.syncer.queue('onGetMessages', { | |||
id: player.id, | |||
messages: [{ | |||
class: 'color-greenB', | |||
message: r.msg, | |||
type: 'info' | |||
}] | |||
}, [player.serverId]); | |||
player.social.notifySelf({ | |||
message: r.msg, | |||
className: 'color-greenB' | |||
}); | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
@@ -125,14 +121,10 @@ module.exports = { | |||
} | |||
} else { | |||
if ((r.msg) && (!sentMessages.some(s => (s === r.msg)))) { | |||
player.instance.syncer.queue('onGetMessages', { | |||
id: player.id, | |||
messages: [{ | |||
class: 'color-greenB', | |||
message: r.msg, | |||
type: 'info' | |||
}] | |||
}, [player.serverId]); | |||
player.social.notifySelf({ | |||
message: r.msg, | |||
className: 'color-greenB' | |||
}); | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
@@ -77,14 +77,10 @@ module.exports = { | |||
} | |||
} else { | |||
if ((r.msg) && (!sentMessages.some(s => (s === r.msg)))) { | |||
player.instance.syncer.queue('onGetMessages', { | |||
id: player.id, | |||
messages: [{ | |||
class: 'color-greenB', | |||
message: r.msg, | |||
type: 'info' | |||
}] | |||
}, [player.serverId]); | |||
player.social.notifySelf({ | |||
message: r.msg, | |||
className: 'color-greenB' | |||
}); | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
@@ -13,7 +13,7 @@ module.exports = { | |||
this.events.on('onBeforeGetSpellsInfo', this.beforeGetSpellsInfo.bind(this)); | |||
this.events.on('onBeforeGetSpellsConfig', this.beforeGetSpellsConfig.bind(this)); | |||
this.events.on('onBeforeGetSpellTemplate', this.beforeGetSpellTemplate.bind(this)); | |||
this.events.on('onBeforeGetResourceList', this.beforeGetResourceList.bind(this)); | |||
this.events.on('onBeforeGetClientConfig', this.onBeforeGetClientConfig.bind(this)); | |||
this.events.on('onBeforeGetAnimations', this.beforeGetAnimations.bind(this)); | |||
this.events.on('onAfterGetZone', this.onAfterGetZone.bind(this)); | |||
}, | |||
@@ -25,14 +25,14 @@ module.exports = { | |||
let newRunes = [{ | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'harvest life', | |||
worth: 3 | |||
}, { | |||
generate: true, | |||
spell: true, | |||
spellQuality: 'basic', | |||
spellQuality: 0, | |||
infinite: true, | |||
spellName: 'summon skeleton', | |||
worth: 3 | |||
@@ -97,10 +97,11 @@ module.exports = { | |||
}; | |||
}, | |||
beforeGetResourceList: function (list) { | |||
list.push(`${this.folderName}/images/inGameSprite.png`); | |||
list.push(`${this.folderName}/images/abilityIcons.png`); | |||
list.push(`${this.folderName}/images/mobs.png`); | |||
onBeforeGetClientConfig: function ({ resourceList, textureList }) { | |||
resourceList.push(`${this.folderName}/images/abilityIcons.png`); | |||
textureList.push(`${this.folderName}/images/inGameSprite.png`); | |||
textureList.push(`${this.folderName}/images/mobs.png`); | |||
}, | |||
beforeGetSpellTemplate: function (spell) { | |||
@@ -1,57 +1,37 @@ | |||
let itemGenerator = require('../../items/generator'); | |||
let config = { | |||
'Runecrafter\'s Toil': { | |||
chance: 0.025, | |||
reward: 'Level 10 Rune', | |||
setSize: 3, | |||
mobLevel: [3, 100] | |||
mobLevel: [8, 12] | |||
}, | |||
'Godly Promise': { | |||
chance: 0.01, | |||
reward: 'Level 15 Legendary Weapon', | |||
setSize: 6, | |||
zone: 'sewer' | |||
}, | |||
'The Other Heirloom': { | |||
chance: 0.02, | |||
reward: 'Perfect Level 10 Ring', | |||
setSize: 3, | |||
mobName: 'flamingo' | |||
}, | |||
'Benthic Incantation': { | |||
chance: 0.015, | |||
reward: 'Princess Morgawsa\'s Trident', | |||
setSize: 12, | |||
zone: 'estuary' | |||
}, | |||
'Fangs of Fury': { | |||
chance: 0.05, | |||
reward: 'Steelclaw\'s Bite', | |||
setSize: 20, | |||
mobName: 'stinktooth' | |||
}, | |||
'Tradesman\'s Pride': { | |||
chance: 0.007, | |||
reward: 'Five Random Idols', | |||
setSize: 10 | |||
reward: 'Five Random Idols' | |||
} | |||
}; | |||
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 mobLevel = mob.stats.values.level; | |||
@@ -96,147 +76,14 @@ module.exports = { | |||
let builtCard = { | |||
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, | |||
sprite: pick.sprite || [0, 0], | |||
quantity: 1, | |||
quality: pick.quality || 1, | |||
setSize: pick.setSize | |||
quality: pick.quality || 1 | |||
}; | |||
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 = { | |||
name: 'Feature: Cards', | |||
extraScripts: [ | |||
'cards' | |||
], | |||
init: function () { | |||
cards.init(); | |||
this.events.on('onBeforeGetClientConfig', this.onBeforeGetClientConfig.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) { | |||
@@ -27,25 +61,10 @@ module.exports = { | |||
if (Math.random() >= dropEvent.chanceMultiplier) | |||
return; | |||
let res = cards.getCard(looter, dropper); | |||
let res = cards.getCard(this.folderName, looter, dropper); | |||
if (!res) | |||
return; | |||
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 = (config, crafter) => { | |||
const result = itemGenerator.generate({ | |||
...config, | |||
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,155 @@ | |||
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, | |||
magicFind: 900 | |||
}) | |||
}, { | |||
name: 'Level 15 Rune', | |||
description: '', | |||
materials: [{ | |||
name: 'Runecrafter\'s Toil', | |||
quantity: 10 | |||
}], | |||
craftAction: rune.bind(null, { | |||
level: 15, | |||
magicFind: 1400 | |||
}) | |||
}, { | |||
name: 'Level 20 Rune', | |||
description: '', | |||
materials: [{ | |||
name: 'Runecrafter\'s Toil', | |||
quantity: 30 | |||
}], | |||
craftAction: rune.bind(null, { | |||
level: 20, | |||
magicFind: 1900 | |||
}) | |||
}, { | |||
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] | |||
} | |||
} | |||
}) | |||
}]; |
@@ -1,52 +0,0 @@ | |||
module.exports = { | |||
type: 'mounted', | |||
oldCell: null, | |||
oldSheetName: null, | |||
init: function () { | |||
let obj = this.obj; | |||
this.oldCell = obj.cell; | |||
this.oldSheetName = obj.sheetName; | |||
obj.cell = this.cell; | |||
obj.sheetName = this.sheetName; | |||
let syncer = obj.syncer; | |||
syncer.set(false, null, 'cell', obj.cell); | |||
syncer.set(false, null, 'sheetName', obj.sheetName); | |||
}, | |||
simplify: function () { | |||
return { | |||
type: 'mounted', | |||
ttl: this.ttl | |||
}; | |||
}, | |||
destroy: function () { | |||
let obj = this.obj; | |||
obj.cell = this.oldCell; | |||
obj.sheetName = this.oldSheetName; | |||
let syncer = obj.syncer; | |||
syncer.set(false, null, 'cell', obj.cell); | |||
syncer.set(false, null, 'sheetName', obj.sheetName); | |||
}, | |||
events: { | |||
onBeforeTryMove: function (moveEvent) { | |||
moveEvent.sprintChance = 200; | |||
}, | |||
beforeCastSpell: function (castEvent) { | |||
this.destroyed = true; | |||
}, | |||
beforeTakeDamage: function (dmgEvent) { | |||
this.destroyed = true; | |||
} | |||
} | |||
}; |
@@ -1,66 +0,0 @@ | |||
/* | |||
Example of a mount: | |||
{ | |||
name: 'Brown Horse\'s Reins', | |||
type: 'mount', | |||
quality: 2, | |||
noDrop: true, | |||
noSalvage: true, | |||
cdMax: 10, | |||
sprite: [0, 9], | |||
spritesheet: 'images/questItems.png', | |||
useText: 'mount', | |||
description: 'Stout, dependable and at least faster than you', | |||
effects: [{ | |||
type: 'mounted', | |||
rolls: { | |||
speed: 150, | |||
cell: 0, | |||
sheetName: 'mobs' | |||
} | |||
}] | |||
} | |||
*/ | |||
module.exports = { | |||
name: 'Feature: Mounts', | |||
init: function () { | |||
this.events.on('onBeforeUseItem', this.onBeforeUseItem.bind(this)); | |||
this.events.on('onBeforeGetEffect', this.onBeforeGetEffect.bind(this)); | |||
}, | |||
onBeforeUseItem: function (obj, item, result) { | |||
if (item.type !== 'mount') | |||
return; | |||
let syncer = obj.syncer; | |||
let currentEffect = obj.effects.removeEffectByName('mounted', true); | |||
if (currentEffect) { | |||
let currentItem = currentEffect.source; | |||
currentItem.useText = 'mount'; | |||
currentItem.cdMax = 0; | |||
syncer.setArray(true, 'inventory', 'getItems', currentItem); | |||
if (currentItem === item) | |||
return; | |||
} | |||
let effectOptions = extend({ type: 'mounted', | |||
ttl: -1 | |||
}, item.effects[0].rolls); | |||
let builtEffect = obj.effects.addEffect(effectOptions); | |||
builtEffect.source = item; | |||
item.useText = 'unmount'; | |||
syncer.setArray(true, 'inventory', 'getItems', item); | |||
}, | |||
onBeforeGetEffect: function (result) { | |||
if (result.type.toLowerCase() === 'mounted') | |||
result.url = `${this.relativeFolderName}/effects/effectMounted.js`; | |||
} | |||
}; |
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "isleward_server", | |||
"version": "0.5.1", | |||
"version": "0.6.0", | |||
"description": "isleward", | |||
"dependencies": { | |||
"bcrypt-nodejs": "0.0.3", | |||
@@ -10,7 +10,7 @@ const routerConfig = { | |||
dialogue: ['talk'], | |||
gatherer: ['gather'], | |||
quests: ['complete'], | |||
inventory: ['combineStacks', 'splitStack', 'activateMtx', 'useItem', 'moveItem', 'enchantItem', 'getEnchantMaterials', 'learnAbility', 'unlearnAbility', 'dropItem', 'destroyItem', 'salvageItem', 'stashItem', 'mailItem', 'sortInventory'], | |||
inventory: ['combineStacks', 'splitStack', 'activateMtx', 'useItem', 'moveItem', 'learnAbility', 'unlearnAbility', 'dropItem', 'destroyItem', 'salvageItem', 'stashItem', 'mailItem', 'sortInventory'], | |||
equipment: ['equip', 'unequip', 'setQuickSlot', 'useQuickSlot', 'inspect'], | |||
stash: ['withdraw', 'open'], | |||
trade: ['buySell'], | |||
@@ -261,7 +261,8 @@ module.exports = { | |||
let info = { | |||
map: this.name, | |||
layer: layerName, | |||
objects: data | |||
objects: data, | |||
mapScale | |||
}; | |||
events.emit('onAfterGetLayerObjects', info); | |||
} | |||
@@ -352,7 +353,7 @@ module.exports = { | |||
if (layerName.indexOf('walls') > -1) | |||
this.collisionMap[x][y] = 1; | |||
else if (sheetName.toLowerCase().indexOf('tiles') > -1) { | |||
else if (layerName === 'tiles' && sheetName === 'tiles') { | |||
//Check for water and water-like tiles | |||
if ([6, 7, 54, 55, 62, 63, 154, 189, 190, 192, 193, 194, 195, 196, 197].indexOf(cell) > -1) | |||
this.collisionMap[x][y] = 1; | |||
@@ -376,8 +377,8 @@ module.exports = { | |||
let blueprint = { | |||
clientObj: clientObj, | |||
sheetName: cellInfo.sheetName, | |||
cell: cellInfo.cell - 1, | |||
sheetName: cell.has('sheetName') ? cell.sheetName : cellInfo.sheetName, | |||
cell: cell.has('cell') ? cell.cell : cellInfo.cell - 1, | |||
x: cell.x / mapScale, | |||
y: (cell.y / mapScale) - 1, | |||
name: name, | |||
@@ -18,6 +18,7 @@ let recipes = require('../config/recipes/recipes'); | |||
let itemTypes = require('../items/config/types'); | |||
let mapList = require('../config/maps/mapList'); | |||
let sheets = require('../security/sheets'); | |||
let itemEffects = require('../items/itemEffects'); | |||
let onCpnsReady = function () { | |||
factions.init(); | |||
@@ -31,6 +32,7 @@ let onCpnsReady = function () { | |||
mapList.init(); | |||
recipes.init(); | |||
sheets.init(); | |||
itemEffects.init(); | |||
process.send({ | |||
method: 'onReady' | |||