Resolve "Allow UIs to register and play sounds" Closes #1473 See merge request Isleward/isleward!479tags/v0.7.0^2
@@ -11,7 +11,7 @@ require.config({ | |||
helpers: 'js/misc/helpers', | |||
particles: 'plugins/pixi.particles.min', | |||
pixi: 'https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.3/pixi.min', | |||
howler: 'https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.2/howler.core.min' | |||
howler: 'https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.3/howler.core.min' | |||
}, | |||
shim: { | |||
howler: { | |||
@@ -57,6 +57,11 @@ define([ | |||
if (this.obj.pather.path.length > 0) | |||
return; | |||
if (this.obj.bumpAnimation) | |||
return; | |||
events.emit('onObjCollideBump', this.obj); | |||
this.obj.addComponent('bumpAnimation', { | |||
deltaX: dx, | |||
deltaY: dy | |||
@@ -1,7 +1,7 @@ | |||
define([ | |||
'js/sound/sound' | |||
], function ( | |||
sound | |||
soundManager | |||
) { | |||
return { | |||
type: 'sound', | |||
@@ -10,8 +10,26 @@ define([ | |||
volume: 0, | |||
init: function () { | |||
let obj = this.obj; | |||
sound.addSound(obj.zoneId, this.sound, this.volume, obj.x, obj.y, obj.width, obj.height, obj.area); | |||
const { | |||
sound, volume, music, defaultMusic, | |||
obj: { zoneId, x, y, width, height, area } | |||
} = this; | |||
const config = { | |||
scope: zoneId, | |||
file: sound, | |||
volume, | |||
x, | |||
y, | |||
w: width, | |||
h: height, | |||
area, | |||
music, | |||
defaultMusic, | |||
loop: true | |||
}; | |||
soundManager.addSound(config); | |||
} | |||
}; | |||
}); |
@@ -77,7 +77,7 @@ define([ | |||
this.hpSpriteInner.visible = this.hpSprite.visible; | |||
}, | |||
extend: function (blueprint) { | |||
extend: function (blueprint) { | |||
let bValues = blueprint.values || {}; | |||
let values = this.values; | |||
@@ -86,7 +86,7 @@ define([ | |||
values[b] = bValues[b]; | |||
if (this.obj.self) | |||
events.emit('onGetStats', this.values); | |||
events.emit('onGetStats', this.values, blueprint); | |||
if (this.obj.has('serverId')) | |||
events.emit('onGetPartyStats', this.obj.serverId, this.values); | |||
@@ -10,7 +10,9 @@ define([ | |||
playAudio: true, | |||
qualityIndicators: 'off', | |||
unusableIndicators: 'off', | |||
rememberChatChannel: true | |||
rememberChatChannel: true, | |||
soundVolume: 100, | |||
musicVolume: 100 | |||
}; | |||
const valueChains = { | |||
@@ -54,8 +56,12 @@ define([ | |||
if (currentValue === '{unset}') | |||
return; | |||
const morphedValue = valueChains[key] ? currentValue : (currentValue === 'true'); | |||
config[key] = morphedValue; | |||
if (['true', 'false'].includes(currentValue)) | |||
config[key] = currentValue === 'true'; | |||
else if (~~currentValue === parseInt(currentValue)) | |||
config[key] = ~~currentValue; | |||
else | |||
config[key] = currentValue; | |||
}; | |||
Object.keys(config).forEach(key => loadValue(key) ); | |||
@@ -74,8 +74,7 @@ define([ | |||
numbers.init(); | |||
uiFactory.init(null, globals.clientConfig.uiList); | |||
uiFactory.build('login', 'body'); | |||
uiFactory.init(null); | |||
fnQueueTick = getQueueTick(this.update.bind(this)); | |||
fnQueueTick(); | |||
@@ -2,91 +2,210 @@ define([ | |||
'howler', | |||
'js/misc/physics', | |||
'js/system/events', | |||
'js/config' | |||
'js/config', | |||
'js/system/globals' | |||
], function ( | |||
howler, | |||
physics, | |||
events, | |||
config | |||
config, | |||
globals | |||
) { | |||
const globalVolume = 0.3; | |||
let soundVolume = config.soundVolume; | |||
let musicVolume = config.musicVolume; | |||
const globalScopes = ['ui']; | |||
const minDistance = 10; | |||
const fadeDuration = 1800; | |||
window.Howler.volume(globalVolume); | |||
return { | |||
sounds: [], | |||
muted: false, | |||
currentMusic: null, | |||
init: function () { | |||
events.on('onToggleAudio', this.onToggleAudio.bind(this)); | |||
events.on('onPlaySound', this.playSound.bind(this)); | |||
events.on('onManipulateVolume', this.onManipulateVolume.bind(this)); | |||
const { clientConfig: { sounds: loadSounds } } = globals; | |||
Object.entries(loadSounds).forEach(([ scope, soundList ]) => { | |||
soundList.forEach(({ name: soundName, file }) => { | |||
this.addSound({ | |||
name: soundName, | |||
file, | |||
scope: 'ui', | |||
autoLoad: true | |||
}); | |||
}); | |||
}); | |||
this.onToggleAudio(config.playAudio); | |||
}, | |||
unload: function (zoneId) { | |||
this.sounds.forEach(function (s) { | |||
if ((s.sound) && (s.zoneId !== zoneId)) | |||
s.sound.unload(); | |||
}); | |||
//Fired when a character rezones | |||
// 'scope' is the new zone name | |||
unload: function (newScope) { | |||
const { sounds } = this; | |||
this.sounds.spliceWhere(function (s) { | |||
return (s.zoneId !== zoneId); | |||
}); | |||
for (let i = 0; i < sounds.length; i++) { | |||
const { scope, sound } = sounds[i]; | |||
if (!globalScopes.includes(scope) && scope !== newScope) { | |||
if (sound) | |||
sound.unload(); | |||
sounds.splice(i, 1); | |||
i--; | |||
} | |||
} | |||
}, | |||
playSound: function (soundName) { | |||
const soundEntry = this.sounds.find(s => s.name === soundName); | |||
if (!soundEntry) | |||
return; | |||
const { sound } = soundEntry; | |||
sound.volume(soundVolume / 100); | |||
sound.play(); | |||
}, | |||
playSoundHelper: function (soundEntry, volume) { | |||
const { sound } = soundEntry; | |||
if (!sound) { | |||
const { file, loop } = soundEntry; | |||
soundEntry.sound = this.loadSound(file, loop, true, volume); | |||
return; | |||
} | |||
soundEntry.volume = volume; | |||
volume *= (soundVolume / 100); | |||
if (sound.playing()) { | |||
if (sound.volume() === volume) | |||
return; | |||
sound.volume(volume); | |||
} else { | |||
sound.volume(volume); | |||
sound.play(); | |||
} | |||
}, | |||
playMusicHelper: function (soundEntry) { | |||
const { sound } = soundEntry; | |||
if (!sound) { | |||
const { file, loop } = soundEntry; | |||
soundEntry.volume = musicVolume; | |||
soundEntry.sound = this.loadSound(file, loop, true, musicVolume / 100); | |||
return; | |||
} | |||
if (!sound.playing()) { | |||
soundEntry.volume = 0; | |||
sound.volume(0); | |||
sound.play(); | |||
} | |||
if (this.currentMusic === soundEntry && sound.volume() === musicVolume / 100) | |||
return; | |||
soundEntry.volume = 1; | |||
this.currentMusic = soundEntry; | |||
sound.fade(sound.volume(), (musicVolume / 100), fadeDuration); | |||
}, | |||
stopSoundHelper: function (soundEntry) { | |||
const { sound, music } = soundEntry; | |||
if (!sound || !sound.playing()) | |||
return; | |||
if (music) | |||
sound.fade(sound.volume(), 0, fadeDuration); | |||
else { | |||
sound.stop(); | |||
sound.volume(0); | |||
} | |||
}, | |||
update: function (x, y) { | |||
updateSounds: function (playerX, playerY) { | |||
this.sounds.forEach(s => { | |||
let volume; | |||
if (!s.w) { | |||
let dx = Math.abs(s.x - x); | |||
if (dx > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let dy = Math.abs(s.y - y); | |||
if (dy > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let dist = 10 - Math.max(dx, dy); | |||
dist = (dist * dist) / 100; | |||
volume = 0.3 * dist; | |||
} else if (physics.isInPolygon(x, y, s.area)) | |||
volume = 0.3; | |||
else { | |||
let distance = physics.distanceToPolygon([x, y], s.area); | |||
if (distance > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let dist = 10 - distance; | |||
dist = (dist * dist) / 100; | |||
volume = 0.3 * dist; | |||
} | |||
const { x, y, area, music, scope } = s; | |||
if (!s.sound) { | |||
//eslint-disable-next-line no-undef | |||
s.sound = new Howl({ | |||
src: ['audio/' + s.file], | |||
autoplay: true, | |||
loop: true, | |||
volume: 0 | |||
}); | |||
if (music || scope === 'ui') | |||
return; | |||
let distance = 0; | |||
if (this.muted) | |||
s.sound.mute(true); | |||
if (!area) { | |||
let dx = Math.abs(x - playerX); | |||
let dy = Math.abs(y - playerY); | |||
distance = Math.max(dx, dy); | |||
} else if (!physics.isInPolygon(playerX, playerY, area)) | |||
distance = physics.distanceToPolygon([playerX, playerY], area); | |||
if (distance > minDistance) { | |||
this.stopSoundHelper(s); | |||
return; | |||
} | |||
if (!this.muted) | |||
s.sound.volume(volume * s.volume); | |||
//Exponential fall-off | |||
const volume = s.volume * (1 - (Math.pow(distance, 2) / Math.pow(minDistance, 2))); | |||
this.playSoundHelper(s, volume); | |||
}); | |||
}, | |||
addSound: function (zoneId, file, volume, x, y, w, h, area) { | |||
if ((!area) && (w)) { | |||
updateMusic: function (playerX, playerY) { | |||
const sounds = this.sounds; | |||
const areaMusic = sounds.filter(s => s.music && s.area); | |||
const currentMusic = areaMusic.find(s => physics.isInPolygon(playerX, playerY, s.area)); | |||
const defaultMusic = sounds.find(s => s.music && s.defaultMusic); | |||
if (!currentMusic) { | |||
if (defaultMusic) | |||
this.playMusicHelper(defaultMusic); | |||
const activeMusic = sounds.filter(s => s.music && s !== defaultMusic); | |||
activeMusic.forEach(s => this.stopSoundHelper(s)); | |||
} else { | |||
if (defaultMusic) | |||
this.stopSoundHelper(defaultMusic); | |||
if (currentMusic) | |||
this.playMusicHelper(currentMusic); | |||
} | |||
}, | |||
update: function (playerX, playerY) { | |||
this.updateSounds(playerX, playerY); | |||
this.updateMusic(playerX, playerY); | |||
}, | |||
addSound: function ( | |||
{ name: soundName, scope, file, volume = 1, x, y, w, h, area, music, defaultMusic, autoLoad, loop } | |||
) { | |||
if (!area && w) { | |||
area = [ | |||
[x, y], | |||
[x + w, y], | |||
@@ -95,19 +214,40 @@ define([ | |||
]; | |||
} | |||
let sound = { | |||
file: file, | |||
x: x, | |||
y: y, | |||
w: w, | |||
h: h, | |||
volume: volume, | |||
area: area, | |||
sound: null, | |||
zoneId: zoneId | |||
let sound = null; | |||
if (autoLoad) | |||
sound = this.loadSound(file, loop); | |||
if (music) | |||
volume = 0; | |||
const soundEntry = { | |||
name: soundName, | |||
sound, | |||
scope, | |||
file, | |||
loop, | |||
x, | |||
y, | |||
volume, | |||
area, | |||
music, | |||
defaultMusic | |||
}; | |||
this.sounds.push(sound); | |||
this.sounds.push(soundEntry); | |||
}, | |||
loadSound: function (file, loop = false, autoplay = false, volume = 1) { | |||
//eslint-disable-next-line no-undef | |||
const sound = new Howl({ | |||
src: [file], | |||
volume, | |||
loop, | |||
autoplay | |||
}); | |||
return sound; | |||
}, | |||
onToggleAudio: function (isAudioOn) { | |||
@@ -124,7 +264,23 @@ define([ | |||
return; | |||
const { player: { x, y } } = window; | |||
this.update(x, y); | |||
}, | |||
onManipulateVolume: function ({ soundType, delta }) { | |||
if (soundType === 'sound') | |||
soundVolume = Math.max(0, Math.min(100, soundVolume + delta)); | |||
else if (soundType === 'music') | |||
musicVolume = Math.max(0, Math.min(100, musicVolume + delta)); | |||
const volume = soundType === 'sound' ? soundVolume : musicVolume; | |||
events.emit('onVolumeChange', { | |||
soundType, | |||
volume | |||
}); | |||
const { player: { x, y } } = window; | |||
this.update(x, y); | |||
} | |||
}; | |||
@@ -9,67 +9,35 @@ define([ | |||
globals, | |||
tosAcceptanceValid | |||
) { | |||
const startupUis = [ | |||
'inventory', | |||
'equipment', | |||
'hud', | |||
'target', | |||
'menu', | |||
'spells', | |||
'messages', | |||
'online', | |||
'mainMenu', | |||
'context', | |||
'party', | |||
'help', | |||
'dialogue', | |||
'buffs', | |||
'tooltips', | |||
'tooltipInfo', | |||
'tooltipItem', | |||
'announcements', | |||
'quests', | |||
'events', | |||
'progressBar', | |||
'stash', | |||
'talk', | |||
'trade', | |||
'overlay', | |||
'death', | |||
'leaderboard', | |||
'reputation', | |||
'mail', | |||
'wardrobe', | |||
'passives', | |||
'workbench', | |||
'middleHud', | |||
'options' | |||
]; | |||
return { | |||
uis: [], | |||
root: '', | |||
init: function (root, uiList = []) { | |||
init: function (root) { | |||
if (root) | |||
this.root = root + '/'; | |||
startupUis.push(...uiList); | |||
events.on('onEnterGame', this.onEnterGame.bind(this)); | |||
events.on('onUiKeyDown', this.onUiKeyDown.bind(this)); | |||
events.on('onResize', this.onResize.bind(this)); | |||
globals.clientConfig.uiLoginList.forEach(u => { | |||
if (u.path) | |||
this.buildModUi(u); | |||
else | |||
this.build(u); | |||
}); | |||
}, | |||
onEnterGame: function () { | |||
events.clearQueue(); | |||
startupUis.forEach(function (u) { | |||
globals.clientConfig.uiList.forEach(u => { | |||
if (u.path) | |||
this.buildModUi(u); | |||
else | |||
this.build(u); | |||
}, this); | |||
}); | |||
}, | |||
buildModUi: function (config) { | |||
@@ -95,14 +63,14 @@ define([ | |||
path = options.path + `\\${type}.js`; | |||
else | |||
path = this.root + 'ui/templates/' + type + '/' + type; | |||
require([path], this.onGetTemplate.bind(this, options)); | |||
require([path], this.onGetTemplate.bind(this, options, type)); | |||
}, | |||
onGetTemplate: function (options, template) { | |||
let ui = $.extend(true, {}, uiBase, template); | |||
onGetTemplate: function (options, type, template) { | |||
let ui = $.extend(true, { type }, uiBase, template); | |||
ui.setOptions(options); | |||
requestAnimationFrame(this.renderUi.bind(this, ui)); | |||
}, | |||
@@ -129,7 +97,7 @@ define([ | |||
return; | |||
keyEvent.consumed = true; | |||
u.hide(); | |||
u.toggle(); | |||
}); | |||
$('.uiOverlay').hide(); | |||
@@ -43,9 +43,10 @@ define([ | |||
if (hotkey) | |||
row.find('.hotkey').html(`(${hotkey})`); | |||
if (c.callback) | |||
if (c.callback) { | |||
row.on('click', this.onClick.bind(this, i, c.callback)); | |||
else | |||
row.on('click', events.emit.bind(events, 'onClickContextItem')); | |||
} else | |||
row.addClass('no-hover'); | |||
}); | |||
@@ -47,21 +47,20 @@ define([ | |||
beforeHide: function () { | |||
this.isInspecting = false; | |||
delete this.result; | |||
this.find('.itemList').hide(); | |||
this.onHoverItem(null, null, null); | |||
}, | |||
toggle: function (show) { | |||
this.shown = !this.el.is(':visible'); | |||
onAfterShow: function () { | |||
this.isInspecting = false; | |||
delete this.result; | |||
this.find('.itemList').hide(); | |||
if (this.shown) { | |||
this.show(); | |||
this.onGetStats(); | |||
this.onGetItems(); | |||
} else | |||
this.hide(); | |||
this.onGetStats(); | |||
this.onGetItems(); | |||
this.onHoverItem(null, null, null); | |||
}, | |||
@@ -22,15 +22,6 @@ define([ | |||
onKeyDown: function (key) { | |||
if (key === 'h') | |||
this.toggle(); | |||
}, | |||
toggle: function () { | |||
this.shown = !this.el.is(':visible'); | |||
if (this.shown) | |||
this.show(); | |||
else | |||
this.hide(); | |||
} | |||
}; | |||
}); |
@@ -55,6 +55,7 @@ define([ | |||
return; | |||
events.emit('onHideItemTooltip', quickItem); | |||
events.emit('onUseQuickItem', quickItem); | |||
client.request({ | |||
cpn: 'player', | |||
@@ -495,19 +495,9 @@ define([ | |||
this.build(); | |||
}, | |||
toggle: function (show) { | |||
this.shown = !this.el.is(':visible'); | |||
if (this.shown) { | |||
this.find('.split-box').hide(); | |||
this.show(); | |||
this.build(); | |||
} else { | |||
this.hide(); | |||
events.emit('onHideInventory'); | |||
events.emit('onHideContextMenu'); | |||
} | |||
onAfterShow: function () { | |||
this.find('.split-box').hide(); | |||
this.build(); | |||
this.hideTooltip(); | |||
}, | |||
@@ -521,6 +511,10 @@ define([ | |||
$('.uiSpells').css('z-index', this.oldSpellsZIndex); | |||
this.oldSpellsZIndex = null; | |||
} | |||
events.emit('onHideInventory'); | |||
events.emit('onHideContextMenu'); | |||
this.hideTooltip(); | |||
}, | |||
performItemAction: function (item, action) { | |||
@@ -167,23 +167,17 @@ define([ | |||
this.find('.btn-next, .btn-last').addClass('disabled'); | |||
}, | |||
toggle: function () { | |||
let shown = !this.el.is(':visible'); | |||
if (shown) { | |||
this.find('.prophecy[prophecy]').removeClass('selected'); | |||
let prophecies = window.player.prophecies; | |||
prophecies = prophecies ? prophecies.list : []; | |||
prophecies.forEach(function (p) { | |||
this.find('.prophecy[prophecy="' + p + '"]').addClass('selected'); | |||
}, this); | |||
onAfterShow: function () { | |||
this.find('.prophecy[prophecy]').removeClass('selected'); | |||
let prophecies = window.player.prophecies; | |||
prophecies = prophecies ? prophecies.list : []; | |||
prophecies.forEach(function (p) { | |||
this.find('.prophecy[prophecy="' + p + '"]').addClass('selected'); | |||
}, this); | |||
this.prophecyFilter = null; | |||
this.prophecyFilter = null; | |||
this.getList(); | |||
this.show(); | |||
} else | |||
this.hide(); | |||
this.getList(); | |||
} | |||
}; | |||
}); |
@@ -17,6 +17,7 @@ | |||
padding-top: 8px; | |||
margin: auto; | |||
} | |||
} | |||
.result { | |||
@@ -37,6 +38,7 @@ | |||
float: left; | |||
color: @white; | |||
} | |||
} | |||
.list { | |||
@@ -50,12 +52,14 @@ | |||
.col { | |||
color: @green; | |||
} | |||
} | |||
&.online { | |||
.col { | |||
color: @greenB; | |||
} | |||
} | |||
.col { | |||
@@ -69,7 +73,9 @@ | |||
white-space: nowrap; | |||
text-overflow: ellipsis; | |||
} | |||
} | |||
} | |||
.buttons { | |||
@@ -93,8 +99,11 @@ | |||
&:last-child { | |||
margin-right: 0px; | |||
} | |||
} | |||
} | |||
} | |||
.prophecies { | |||
@@ -113,18 +122,20 @@ | |||
.heading-text { | |||
margin: auto; | |||
} | |||
} | |||
.prophecy, .btn { | |||
.prophecy, | |||
.btn { | |||
cursor: pointer; | |||
} | |||
.prophecy { | |||
width: 100%; | |||
padding: 5px 10px; | |||
background-color: @grayD; | |||
color: @white; | |||
margin-bottom: 15px; | |||
margin-bottom: 12px; | |||
&.selected { | |||
color: @green; | |||
@@ -134,16 +145,19 @@ | |||
background-color: @grayC; | |||
} | |||
&.prophecy-mine, &.prophecy-none { | |||
&.prophecy-mine, | |||
&.prophecy-none { | |||
background-color: @grayC; | |||
&:hover { | |||
background-color: @grayB; | |||
} | |||
} | |||
} | |||
.btn { | |||
.btn-refresh { | |||
width: calc(100% - 10px); | |||
background-color: @blueC; | |||
padding: 5px 10px; | |||
@@ -154,8 +168,11 @@ | |||
&:hover { | |||
background-color: @blueB; | |||
} | |||
} | |||
} | |||
} | |||
.mobile .uiLeaderboard { | |||
@@ -21,13 +21,13 @@ | |||
<div class="heading"> | |||
<div class="heading-text">prophecies</div> | |||
</div> | |||
<div class="prophecy prophecy-none">none</div> | |||
<div class="prophecy prophecy-mine">mine</div> | |||
<div class="prophecy" prophecy="austere">austere</div> | |||
<div class="prophecy" prophecy="butcher">butcher</div> | |||
<div class="prophecy" prophecy="crushable">crushable</div> | |||
<div class="prophecy" prophecy="hardcore">hardcore</div> | |||
<div class="prophecy" prophecy="titangrip">titangrip</div> | |||
<div class="btn prophecy prophecy-none">none</div> | |||
<div class="btn prophecy prophecy-mine">mine</div> | |||
<div class="btn prophecy" prophecy="austere">austere</div> | |||
<div class="btn prophecy" prophecy="butcher">butcher</div> | |||
<div class="btn prophecy" prophecy="crushable">crushable</div> | |||
<div class="btn prophecy" prophecy="hardcore">hardcore</div> | |||
<div class="btn prophecy" prophecy="titangrip">titangrip</div> | |||
<div class="btn btn-refresh">refresh</div> | |||
</div> | |||
</div> |
@@ -64,6 +64,7 @@ define([ | |||
return; | |||
} | |||
events.emit('onSendMail'); | |||
this.hide(); | |||
}, | |||
@@ -92,14 +93,8 @@ define([ | |||
.on('mouseleave', this.hideTooltip.bind(this, itemEl, item)); | |||
}, | |||
toggle: function () { | |||
this.shown = !this.el.is(':visible'); | |||
if (this.shown) { | |||
this.show(); | |||
this.find('input').focus(); | |||
} else | |||
this.hide(); | |||
onAfterShow: function () { | |||
this.find('input').focus(); | |||
}, | |||
hideTooltip: function () { | |||
@@ -24,9 +24,10 @@ define([ | |||
modal: true, | |||
postRender: function () { | |||
this.onEvent('onToggleMainMenu', this.toggle.bind(this)); | |||
this.onEvent('onCloseOptions', this.show.bind(this)); | |||
this.onEvent('onShowMainMenu', this.show.bind(this)); | |||
this.el.find('.btnOptions').on('click', this.handler.bind(this, 'onToggleOptions')); | |||
this.el.find('.btnOptions').on('click', this.openOptions.bind(this)); | |||
this.el.find('.btnCharSelect').on('click', this.charSelect.bind(this)); | |||
this.el.find('.btnLogOut').on('click', this.logOut.bind(this)); | |||
this.el.find('.btnContinue').on('click', this.toggle.bind(this)); | |||
@@ -35,13 +36,11 @@ define([ | |||
this.onEvent('onResize', this.onResize.bind(this)); | |||
}, | |||
handler: function (e) { | |||
openOptions: function () { | |||
if (isMobile) | |||
this.el.removeClass('active'); | |||
events.emit(e); | |||
return false; | |||
events.emit('onOpenOptions'); | |||
}, | |||
patreon: function () { | |||
@@ -81,18 +80,16 @@ define([ | |||
this.el.find('.btnScreen').html('Fullscreen'); | |||
}, | |||
toggle: function () { | |||
onAfterShow: function () { | |||
this.onResize(); | |||
this.shown = !this.el.is(':visible'); | |||
events.emit('onShowOverlay', this.el); | |||
}, | |||
beforeHide: function () { | |||
this.onResize(); | |||
if (this.shown) { | |||
this.show(); | |||
events.emit('onShowOverlay', this.el); | |||
} else { | |||
this.hide(); | |||
events.emit('onHideOverlay', this.el); | |||
} | |||
events.emit('onHideOverlay', this.el); | |||
}, | |||
logOut: function () { | |||
@@ -21,7 +21,7 @@ define([ | |||
this.find('.btnOnline').on('click', this.handler.bind(this, 'onShowOnline')); | |||
this.find('.btnLeaderboard').on('click', this.handler.bind(this, 'onShowLeaderboard')); | |||
this.find('.btnReputation').on('click', this.handler.bind(this, 'onShowReputation')); | |||
this.find('.btnMainMenu').on('click', this.handler.bind(this, 'onToggleMainMenu')); | |||
this.find('.btnMainMenu').on('click', this.handler.bind(this, 'onShowMainMenu')); | |||
this.find('.btnPassives').on('click', this.handler.bind(this, 'onShowPassives')); | |||
this.onEvent('onGetPassivePoints', this.onGetPassivePoints.bind(this)); | |||
@@ -40,7 +40,7 @@ define([ | |||
this.onEvent('onToggleLastChannel', this.onToggleLastChannel.bind(this)); | |||
this | |||
.find('.filter:not(.channel):not(.btn)') | |||
.find('.filter:not(.channel)') | |||
.on('mouseover', this.onFilterHover.bind(this, true)) | |||
.on('mouseleave', this.onFilterHover.bind(this, false)) | |||
.on('click', this.onClickFilter.bind(this)); | |||
@@ -1,9 +1,9 @@ | |||
<div class="uiMessages active"> | |||
<div class="filters"> | |||
<div class="filter active" filter="info">info</div> | |||
<div class="filter active" filter="rep">reputation</div> | |||
<div class="filter active" filter="chat">players</div> | |||
<div class="filter active" filter="loot">loot</div> | |||
<div class="btn filter active" filter="info">info</div> | |||
<div class="btn filter active" filter="rep">reputation</div> | |||
<div class="btn filter active" filter="chat">players</div> | |||
<div class="btn filter active" filter="loot">loot</div> | |||
</div> | |||
<div class="list rep chat info loot"> | |||
@@ -45,14 +45,8 @@ define([ | |||
this.toggle(); | |||
}, | |||
toggle: function () { | |||
this.shown = !this.el.is(':visible'); | |||
if (this.shown) { | |||
this.show(); | |||
this.build(); | |||
} else | |||
this.hide(); | |||
onAfterShow: function () { | |||
this.build(); | |||
}, | |||
onGetConnectedPlayer: function (list) { | |||
@@ -27,7 +27,7 @@ define([ | |||
hasClose: true, | |||
postRender: function () { | |||
this.onEvent('onToggleOptions', this.toggle.bind(this)); | |||
this.onEvent('onOpenOptions', this.show.bind(this)); | |||
//Can only toggle fullscreen directly in a listener, not deferred the way jQuery does it | |||
this.find('.item.screen .name')[0].addEventListener('click', this.toggleScreen.bind(this)); | |||
@@ -36,18 +36,35 @@ define([ | |||
this.find('.item.events .name').on('click', this.toggleEvents.bind(this)); | |||
this.find('.item.quality .name').on('click', this.toggleQualityIndicators.bind(this)); | |||
this.find('.item.unusable .name').on('click', this.toggleUnusableIndicators.bind(this)); | |||
this.find('.item.audio .name').on('click', this.toggleAudio.bind(this)); | |||
this.find('.item.lastChannel .name').on('click', this.toggleLastChannel.bind(this)); | |||
this.find('.item.volume .btn').on('click', this.modifyVolume.bind(this)); | |||
this.onEvent('onResize', this.onResize.bind(this)); | |||
this.onEvent('onUiKeyDown', this.onKeyDown.bind(this)); | |||
this.onEvent('onToggleAudio', this.onToggleAudio.bind(this)); | |||
this.onEvent('onToggleNameplates', this.onToggleNameplates.bind(this)); | |||
this.onEvent('onToggleQualityIndicators', this.onToggleQualityIndicators.bind(this)); | |||
this.onEvent('onToggleUnusableIndicators', this.onToggleUnusableIndicators.bind(this)); | |||
this.onEvent('onToggleEventsVisibility', this.onToggleEventsVisibility.bind(this)); | |||
this.onEvent('onToggleQuestsVisibility', this.onToggleQuestsVisibility.bind(this)); | |||
this.onEvent('onToggleLastChannel', this.onToggleLastChannel.bind(this)); | |||
this.onEvent('onVolumeChange', this.onVolumeChange.bind(this)); | |||
this.find('.item').on('click', events.emit.bind(events, 'onClickOptionsItem')); | |||
}, | |||
modifyVolume: function (e) { | |||
const el = $(e.target); | |||
const isIncrease = el.hasClass('increase'); | |||
const delta = isIncrease ? 10 : -10; | |||
const soundType = el.parent().parent().hasClass('sound') ? 'sound' : 'music'; | |||
events.emit('onManipulateVolume', { | |||
soundType, | |||
delta | |||
}); | |||
}, | |||
toggleUnusableIndicators: function () { | |||
@@ -152,6 +169,26 @@ define([ | |||
this.find('.item.lastChannel .value').html(newValue); | |||
}, | |||
onVolumeChange: function ({ soundType, volume }) { | |||
const item = this.find(`.item.volume.${soundType}`); | |||
item.find('.value').html(volume); | |||
const tickLeftPosition = `${volume}%`; | |||
item.find('.tick').css({ left: tickLeftPosition }); | |||
const btnDecrease = item.find('.btn.decrease').removeClass('disabled'); | |||
const btnIncrease = item.find('.btn.increase').removeClass('disabled'); | |||
if (volume === 0) | |||
btnDecrease.addClass('disabled'); | |||
else if (volume === 100) | |||
btnIncrease.addClass('disabled'); | |||
const configKey = `${soundType}Volume`; | |||
config.set(configKey, volume); | |||
}, | |||
build: function () { | |||
this.onToggleNameplates(config.showNames); | |||
this.onToggleAudio(config.playAudio); | |||
@@ -160,21 +197,26 @@ define([ | |||
this.onToggleQualityIndicators(config.qualityIndicators); | |||
this.onToggleUnusableIndicators(config.unusableIndicators); | |||
this.onToggleLastChannel(config.rememberChatChannel); | |||
console.log(config); | |||
this.onVolumeChange({ | |||
soundType: 'sound', | |||
volume: config.soundVolume | |||
}); | |||
this.onVolumeChange({ | |||
soundType: 'music', | |||
volume: config.musicVolume | |||
}); | |||
}, | |||
toggle: function () { | |||
onAfterShow: function () { | |||
this.onResize(); | |||
if (!this.shown) { | |||
this.show(); | |||
this.shown = true; | |||
events.emit('onShowOverlay', this.el); | |||
events.emit('onShowOverlay', this.el); | |||
this.build(); | |||
} else { | |||
this.hide(); | |||
this.shown = false; | |||
} | |||
this.build(); | |||
}, | |||
onKeyDown: function (keyEvent) { | |||
@@ -191,7 +233,9 @@ define([ | |||
}, | |||
afterHide: function () { | |||
events.emit('onToggleMainMenu'); | |||
this.onResize(); | |||
events.emit('onCloseOptions'); | |||
} | |||
}; | |||
}); |
@@ -71,6 +71,75 @@ | |||
padding-right: 10px; | |||
} | |||
&.volume { | |||
flex-wrap: wrap; | |||
height: 60px; | |||
.name { | |||
pointer-events: none; | |||
} | |||
.name, | |||
.value { | |||
width: 50%; | |||
height: 30px; | |||
} | |||
.slider { | |||
padding: 0px 10px; | |||
width: 100%; | |||
height: 30px; | |||
display: flex; | |||
position: relative; | |||
.btn { | |||
width: 30px; | |||
margin-top: 5px; | |||
height: calc(100% - 10px); | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
color: @white; | |||
background-color: @blackA; | |||
padding-top: unset; | |||
&:first-child { | |||
margin-right: 10px; | |||
} | |||
&:last-child { | |||
margin-left: 10px; | |||
} | |||
&:hover { | |||
background-color: @grayD; | |||
} | |||
} | |||
.bar { | |||
width: 100%; | |||
background-color: @blueD; | |||
border-top: 10px solid @blackC; | |||
border-bottom: 10px solid @blackC; | |||
height: 100%; | |||
position: relative; | |||
.tick { | |||
position: absolute; | |||
width: 5px; | |||
height: 20px; | |||
top: -5px; | |||
left: 100%; | |||
background-color: @blueA; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
@@ -9,9 +9,27 @@ | |||
<div class="name">Fullscreen</div> | |||
<div class="value">Off</div> | |||
</div> | |||
<div class="item audio"> | |||
<div class="name">Audio</div> | |||
<div class="value">On</div> | |||
<div class="item volume sound"> | |||
<div class="name">Sound Volume</div> | |||
<div class="value">100</div> | |||
<div class="slider"> | |||
<div class="btn decrease">-</div> | |||
<div class="bar"> | |||
<div class="tick"></div> | |||
</div> | |||
<div class="btn increase">+</div> | |||
</div> | |||
</div> | |||
<div class="item volume music"> | |||
<div class="name">Music Volume</div> | |||
<div class="value">100</div> | |||
<div class="slider"> | |||
<div class="btn decrease">-</div> | |||
<div class="bar"> | |||
<div class="tick"></div> | |||
</div> | |||
<div class="btn increase">+</div> | |||
</div> | |||
</div> | |||
<div class="heading hud">HUD</div> | |||
<div class="item nameplates"> | |||
@@ -150,31 +150,24 @@ define([ | |||
nodes.forEach(n => this.renderers.node.call(this, n, n.pos.x, n.pos.y)); | |||
}, | |||
toggle: function (show) { | |||
this.shown = !this.el.is(':visible'); | |||
onAfterShow: function () { | |||
//Calculate midpoint | |||
let start = this.data.nodes.find(n => n.spiritStart === window.player.class); | |||
if (this.shown) { | |||
//Calculate midpoint | |||
let start = this.data.nodes.find(n => n.spiritStart === window.player.class); | |||
this.pos.x = start.pos.x * constants.gridSize; | |||
this.pos.y = start.pos.y * constants.gridSize; | |||
this.pos.x = start.pos.x * constants.gridSize; | |||
this.pos.y = start.pos.y * constants.gridSize; | |||
this.pos.x -= ~~(this.canvas.width / 2); | |||
this.pos.y -= ~~(this.canvas.height / 2); | |||
this.pos.x -= ~~(this.canvas.width / 2); | |||
this.pos.y -= ~~(this.canvas.height / 2); | |||
this.show(); | |||
this.onResize(); | |||
this.renderNodes(); | |||
} else | |||
this.hide(); | |||
this.onResize(); | |||
this.renderNodes(); | |||
events.emit('onHideTooltip', this.el[0]); | |||
this.tooltipId = null; | |||
}, | |||
beforeHide: function () { | |||
events.emit('onHideTooltip', this.el[0]); | |||
events.emit('onHideTooltip', this.el[0]); | |||
this.tooltipId = null; | |||
}, | |||
@@ -445,6 +438,26 @@ define([ | |||
else if (isMobile && this.tooltipId !== node.id) | |||
return; | |||
const canReachNode = this.data.links.some(l => { | |||
return ( | |||
( | |||
l.to.id === node.id || | |||
l.from.id === node.id | |||
) && | |||
this.data.nodes.some(n => { | |||
return ( | |||
(n.id === l.from.id && n.selected) || | |||
(n.id === l.to.id && n.selected) | |||
); | |||
}) | |||
); | |||
}); | |||
if (!canReachNode) | |||
return; | |||
events.emit('onTryTickPassiveNode', { tick: !node.selected }); | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
@@ -107,6 +107,8 @@ define([ | |||
msg: 'Quest ready for turn-in' | |||
}); | |||
} | |||
events.emit('onQuestReady', quest); | |||
} | |||
}, | |||
@@ -46,6 +46,7 @@ define([ | |||
let el = $(html).appendTo(elList); | |||
el.on('click', this.onSelectFaction.bind(this, el, l)); | |||
el.on('click', events.emit.bind(events, 'onClickButton')); | |||
}); | |||
}, | |||
@@ -93,14 +94,8 @@ define([ | |||
this.onSelectFaction(selElement, list[selElement.index() + 1]); | |||
}, | |||
toggle: function () { | |||
let shown = !this.el.is(':visible'); | |||
if (shown) { | |||
this.build(); | |||
this.show(); | |||
} else | |||
this.hide(); | |||
onAfterShow: function () { | |||
this.build(); | |||
} | |||
}; | |||
}); |
@@ -139,21 +139,20 @@ define([ | |||
this.build(); | |||
}, | |||
toggle: function () { | |||
onAfterShow: function () { | |||
if ((!this.shown) && (!window.player.stash.active)) | |||
return; | |||
this.shown = !this.el.is(':visible'); | |||
events.emit('onShowOverlay', this.el); | |||
this.build(); | |||
}, | |||
if (this.shown) { | |||
this.show(); | |||
events.emit('onShowOverlay', this.el); | |||
this.build(); | |||
} else { | |||
this.hide(); | |||
events.emit('onHideOverlay', this.el); | |||
events.emit('onHideContextMenu'); | |||
} | |||
beforeHide: function () { | |||
if ((!this.shown) && (!window.player.stash.active)) | |||
return; | |||
events.emit('onHideOverlay', this.el); | |||
events.emit('onHideContextMenu'); | |||
}, | |||
onOpenStash: function () { | |||
@@ -128,6 +128,8 @@ define([ | |||
callback: this.onServerRespond.bind(this, el) | |||
}); | |||
events.emit('onBuySellItem', this.el); | |||
let uiInventory = $('.uiInventory').data('ui'); | |||
uiInventory.hideTooltip(el, item, e); | |||
}, | |||
@@ -41,6 +41,7 @@ define([ | |||
.appendTo(container); | |||
el.on('click', this.setPreview.bind(this, l, el)); | |||
el.on('click', events.emit.bind(events, 'onClickListItem')); | |||
if (l.id === window.player.skinId) { | |||
el.addClass('current'); | |||
@@ -74,6 +74,7 @@ define([ | |||
.appendTo(container); | |||
el.on('click', this.onSelectRecipe.bind(this, el, r)); | |||
el.on('click', events.emit.bind(events, 'onClickListItem')); | |||
}, this); | |||
}, | |||
@@ -45,9 +45,16 @@ define([ | |||
if ((this.centeredX) || (this.centeredY)) | |||
this.center(this.centeredX, this.centeredY); | |||
this.registerUiEvents(); | |||
this.shown = this.el.is(':visible'); | |||
}, | |||
registerUiEvents: function () { | |||
this.find('.btn').on('click', events.emit.bind(events, 'onClickButton')); | |||
this.find('.tab').on('click', events.emit.bind(events, 'onClickTab')); | |||
}, | |||
onMouseEnter: function (enter) { | |||
events.emit('onUiHover', enter); | |||
}, | |||
@@ -99,6 +106,9 @@ define([ | |||
}, | |||
show: function () { | |||
if (this.shown) | |||
return; | |||
if (this.modal) { | |||
//Close any other open modal | |||
$('.modal').toArray().forEach(el => { | |||
@@ -119,9 +129,14 @@ define([ | |||
if ((this.centeredX) || (this.centeredY)) | |||
this.center(this.centeredX, this.centeredY); | |||
events.emit('onShowUi', this); | |||
}, | |||
hide: function () { | |||
if (!this.shown) | |||
return; | |||
if (this.beforeHide) | |||
this.beforeHide(); | |||
@@ -130,6 +145,8 @@ define([ | |||
if (this.afterHide) | |||
this.afterHide(); | |||
events.emit('onHideUi', this); | |||
}, | |||
destroy: function () { | |||
@@ -178,12 +195,12 @@ define([ | |||
}, | |||
toggle: function () { | |||
this.shown = !this.el.is(':visible'); | |||
if (this.shown) | |||
if (!this.shown) | |||
this.show(); | |||
else | |||
this.hide(); | |||
events.emit('onToggleUi', this); | |||
}, | |||
buildClose: function () { | |||
@@ -172,6 +172,7 @@ module.exports = { | |||
class: 'color-yellowB', | |||
message: '(you to ' + playerName + '): ' + messageString, | |||
type: 'chat', | |||
subType: 'privateOut', | |||
source: this.obj.name | |||
}] | |||
} | |||
@@ -184,6 +185,7 @@ module.exports = { | |||
class: 'color-yellowB', | |||
message: '(' + this.obj.name + ' to you): ' + messageString, | |||
type: 'chat', | |||
subType: 'privateIn', | |||
source: this.obj.name | |||
}] | |||
} | |||
@@ -399,7 +401,7 @@ module.exports = { | |||
//Sends a notification to yourself | |||
// arg1 = { message, className, type } | |||
notifySelf: function ({ message, className = 'color-redA', type = 'info' }) { | |||
notifySelf: function ({ message, className = 'color-redA', type = 'info', subType }) { | |||
const { obj: { id, serverId, instance: { syncer } } } = this; | |||
syncer.queue('onGetMessages', { | |||
@@ -407,7 +409,8 @@ module.exports = { | |||
messages: [{ | |||
class: className, | |||
message, | |||
type | |||
type, | |||
subType | |||
}] | |||
}, [serverId]); | |||
}, | |||
@@ -418,9 +421,10 @@ module.exports = { | |||
const { obj: { id, serverId, instance: { syncer } } } = this; | |||
messages.forEach(m => { | |||
const { className = 'color-redA', type = 'info ' } = m; | |||
const { className = 'color-redA', type = 'info', subType } = m; | |||
m.className = className; | |||
m.type = type; | |||
m.subType = subType; | |||
}); | |||
syncer.queue('onGetMessages', { | |||
@@ -1,14 +1,41 @@ | |||
const serializeProps = [ | |||
'sound', | |||
'defaultMusic', | |||
'volume', | |||
'music' | |||
]; | |||
module.exports = { | |||
type: 'sound', | |||
sound: null, | |||
volume: 0, | |||
simplified: null, | |||
buildSimplified: function () { | |||
const s = Object.fromEntries( | |||
serializeProps | |||
.map(p => { | |||
if (!this.has(p)) | |||
return null; | |||
return [p, this[p]]; | |||
}) | |||
.filter(p => !!p) | |||
); | |||
s.type = 'sound'; | |||
let file = s.sound; | |||
if (!file.includes('server')) | |||
file = 'audio/' + file; | |||
s.sound = file; | |||
this.simplified = s; | |||
}, | |||
simplify: function () { | |||
return { | |||
type: 'sound', | |||
sound: this.sound, | |||
volume: this.volume | |||
}; | |||
if (!this.simplified) | |||
this.buildSimplified(); | |||
return this.simplified; | |||
} | |||
}; |
@@ -134,6 +134,12 @@ module.exports = { | |||
} | |||
}); | |||
let msg = 'Press U to access your Shared Stash'; | |||
this.obj.instance.syncer.queue('onGetAnnouncement', { | |||
src: this.obj.id, | |||
msg: msg | |||
}, [obj.serverId]); | |||
if (this.active && this.items.length > this.maxItems) { | |||
const message = `You have more than ${this.maxItems} items in your stash. In the future, these items will be lost.`; | |||
obj.social.notifySelf({ message }); | |||
@@ -25,11 +25,52 @@ const config = { | |||
'images/skins/0010.png', | |||
'images/skins/0012.png' | |||
], | |||
uiList: [], | |||
uiLoginList: [ | |||
'login' | |||
], | |||
uiList: [ | |||
'inventory', | |||
'equipment', | |||
'hud', | |||
'target', | |||
'menu', | |||
'spells', | |||
'messages', | |||
'online', | |||
'mainMenu', | |||
'context', | |||
'party', | |||
'help', | |||
'dialogue', | |||
'buffs', | |||
'tooltips', | |||
'tooltipInfo', | |||
'tooltipItem', | |||
'announcements', | |||
'quests', | |||
'events', | |||
'progressBar', | |||
'stash', | |||
'talk', | |||
'trade', | |||
'overlay', | |||
'death', | |||
'leaderboard', | |||
'reputation', | |||
'mail', | |||
'wardrobe', | |||
'passives', | |||
'workbench', | |||
'middleHud', | |||
'options' | |||
], | |||
contextMenuActions: { | |||
player: [], | |||
npc: [] | |||
}, | |||
sounds: { | |||
ui: [] | |||
}, | |||
tos | |||
}; | |||
@@ -1296,7 +1296,7 @@ | |||
"objects":[], | |||
"opacity":1, | |||
"type":"objectgroup", | |||
"visible":false, | |||
"visible":true, | |||
"x":0, | |||
"y":0 | |||
}], | |||
@@ -1042,7 +1042,7 @@ | |||
{ | |||
"name":"cpnNotice", | |||
"type":"string", | |||
"value":"{\n\t\"msg\": \"Your Stash (U to Access)\",\n\t\"actions\": {\n\t\t\"enter\": {\n\t\t\t\"cpn\": \"stash\",\n\t\t\t\"method\": \"setActive\",\n\t\t\t\"args\": [true]\n\t\t},\n\t\t\"exit\": {\n\t\t\t\"cpn\": \"stash\",\n\t\t\t\"method\": \"setActive\",\n\t\t\t\"args\": [false]\n\t\t}\n\t}\n}" | |||
"value":"{\"actions\":{\"enter\":{\"cpn\":\"stash\",\"method\":\"setActive\",\"args\":[true]},\"exit\":{\"cpn\":\"stash\",\"method\":\"setActive\",\"args\":[false]}}}" | |||
}], | |||
"rotation":0, | |||
"type":"", | |||
@@ -1302,7 +1302,7 @@ | |||
{ | |||
"name":"cpnNotice", | |||
"type":"string", | |||
"value":"{\n\t\"msg\": \"Your Stash (U to Access)\",\n\t\"actions\": {\n\t\t\"enter\": {\n\t\t\t\"cpn\": \"stash\",\n\t\t\t\"method\": \"setActive\",\n\t\t\t\"args\": [true]\n\t\t},\n\t\t\"exit\": {\n\t\t\t\"cpn\": \"stash\",\n\t\t\t\"method\": \"setActive\",\n\t\t\t\"args\": [false]\n\t\t}\n\t}\n}" | |||
"value":"{\"actions\":{\"enter\":{\"cpn\":\"stash\",\"method\":\"setActive\",\"args\":[true]},\"exit\":{\"cpn\":\"stash\",\"method\":\"setActive\",\"args\":[false]}}}" | |||
}], | |||
"rotation":0, | |||
"type":"", | |||
@@ -4218,7 +4218,7 @@ | |||
"y":0 | |||
}], | |||
"nextlayerid":31, | |||
"nextobjectid":991, | |||
"nextobjectid":995, | |||
"orientation":"orthogonal", | |||
"properties":[ | |||
{ | |||
@@ -38,6 +38,7 @@ module.exports = { | |||
}); | |||
this.obj.syncer.setArray(true, 'quests', 'updateQuests', this.simplify(true)); | |||
this.obj.fireEvent('onQuestReady', this); | |||
}, | |||
complete: function () { | |||
@@ -61,6 +61,12 @@ module.exports = { | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
} else { | |||
player.social.notifySelf({ | |||
message: 'You have received a mail', | |||
className: 'color-greenB', | |||
subType: 'mail' | |||
}); | |||
} | |||
delete r.pos; | |||
@@ -130,6 +136,12 @@ module.exports = { | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
} else { | |||
player.social.notifySelf({ | |||
message: 'You have received a mail', | |||
className: 'color-greenB', | |||
subType: 'mail' | |||
}); | |||
} | |||
delete r.pos; | |||
@@ -84,6 +84,12 @@ module.exports = { | |||
sentMessages.push(r.msg); | |||
delete r.msg; | |||
} else { | |||
player.social.notifySelf({ | |||
message: 'You have received a mail', | |||
className: 'color-greenB', | |||
subType: 'mail' | |||
}); | |||
} | |||
inventory.getItem(r, false, false, false, true); | |||
} | |||
@@ -94,23 +94,22 @@ module.exports = { | |||
default: function (req, res) { | |||
let root = req.url.split('/')[1]; | |||
let file = req.params[0]; | |||
file = file.replace('/' + root + '/', ''); | |||
const validModPatterns = ['.png', '/ui/', '/clientComponents/', '/audio/']; | |||
const validRequest = ( | |||
root !== 'server' || | |||
( | |||
file.includes('mods/') && | |||
( | |||
file.includes('.png') || | |||
file.includes('/ui/') | |||
) | |||
validModPatterns.some(v => file.includes(v)) | |||
) | |||
); | |||
if (!validRequest) | |||
return null; | |||
res.sendFile(file, { | |||
root: '../' + root | |||
}); | |||
@@ -256,8 +256,7 @@ module.exports = { | |||
continue; | |||
let data = layer.data || layer.objects; | |||
let firstItem = data[0]; | |||
if (firstItem && firstItem.has('width')) { | |||
if (layer.objects) { | |||
let info = { | |||
map: this.name, | |||
layer: layerName, | |||