@@ -3,7 +3,58 @@ define([ | |||
], function ( | |||
) { | |||
return { | |||
showNames: false | |||
const config = { | |||
showNames: true, | |||
showQuests: 'on', | |||
showEvents: true, | |||
playAudio: true | |||
}; | |||
const valueChains = { | |||
showQuests: ['on', 'minimal', 'off'] | |||
}; | |||
const getNextValue = key => { | |||
const currentValue = config[key]; | |||
const chain = valueChains[key]; | |||
const currentIndex = chain.indexOf(currentValue); | |||
const nextValue = chain[(currentIndex + 1) % chain.length]; | |||
return nextValue; | |||
}; | |||
const getKeyName = key => { | |||
return `iwd_opt_${key.toLowerCase()}`; | |||
}; | |||
config.set = (key, value) => { | |||
config[key] = value; | |||
window.localStorage.setItem(getKeyName(key), config[key]); | |||
}; | |||
config.toggle = key => { | |||
if (valueChains[key]) | |||
config[key] = getNextValue(key); | |||
else | |||
config[key] = !config[key]; | |||
window.localStorage.setItem(getKeyName(key), config[key]); | |||
}; | |||
const loadValue = key => { | |||
const keyName = getKeyName(key); | |||
const { [keyName]: currentValue = '{unset}' } = localStorage; | |||
if (currentValue === '{unset}') | |||
return; | |||
const morphedValue = valueChains[key] ? currentValue : (currentValue === 'true'); | |||
config[key] = morphedValue; | |||
}; | |||
Object.keys(config).forEach(key => loadValue(key) ); | |||
return config; | |||
}); |
@@ -8,6 +8,7 @@ define([ | |||
'js/input', | |||
'js/system/events', | |||
'js/resources', | |||
'js/sound/sound', | |||
'ui/templates/online/online', | |||
'ui/templates/tooltips/tooltips' | |||
], function ( | |||
@@ -19,7 +20,8 @@ define([ | |||
numbers, | |||
input, | |||
events, | |||
resources | |||
resources, | |||
sound | |||
) { | |||
return { | |||
hasFocus: true, | |||
@@ -51,6 +53,8 @@ define([ | |||
$(window).on('contextmenu', this.onContextMenu.bind(this)); | |||
sound.init(); | |||
objects.init(); | |||
renderer.init(); | |||
input.init(); | |||
@@ -12,21 +12,14 @@ define([ | |||
config | |||
) { | |||
return { | |||
showNames: true, | |||
objects: [], | |||
init: function () { | |||
events.on('onKeyDown', this.onKeyDown.bind(this)); | |||
events.on('onGetObject', this.onGetObject.bind(this)); | |||
events.on('onRezone', this.onRezone.bind(this)); | |||
events.on('onChangeHoverTile', this.getLocation.bind(this)); | |||
events.on('onTilesVisible', this.onTilesVisible.bind(this)); | |||
//Get saved value for showNames, or use the value set above | |||
let showNames = window.localStorage.getItem('iwd_opt_shownames'); | |||
this.showNames = showNames ? (showNames === 'true') : this.showNames; | |||
config.showNames = this.showNames; | |||
events.on('onToggleNameplates', this.onToggleNameplates.bind(this)); | |||
}, | |||
getLocation: function (x, y) { | |||
@@ -282,7 +275,7 @@ define([ | |||
if (template.hidden !== null) { | |||
sprite.visible = !template.hidden; | |||
if (obj.nameSprite) | |||
obj.nameSprite.visible = this.showNames; | |||
obj.nameSprite.visible = config.showNames; | |||
if ((obj.stats) && (obj.stats.hpSprite)) { | |||
obj.stats.hpSprite.visible = !template.hidden; | |||
obj.stats.hpSpriteInner.visible = !template.hidden; | |||
@@ -305,7 +298,7 @@ define([ | |||
x: (obj.x * scale) + (scale / 2), | |||
y: (obj.y * scale) + scale | |||
}); | |||
obj.nameSprite.visible = this.showNames; | |||
obj.nameSprite.visible = config.showNames; | |||
} | |||
if (obj.sprite) { | |||
@@ -346,29 +339,6 @@ define([ | |||
} | |||
}, | |||
onKeyDown: function (key) { | |||
if (key === 'v') { | |||
this.showNames = !this.showNames; | |||
//Set new value in localStorage for showNames | |||
window.localStorage.setItem('iwd_opt_shownames', this.showNames); | |||
config.showNames = this.showNames; | |||
let showNames = this.showNames; | |||
let objects = this.objects; | |||
let oLen = objects.length; | |||
for (let i = 0; i < oLen; i++) { | |||
let obj = objects[i]; | |||
let ns = obj.nameSprite; | |||
if ((!ns) || (obj.dead) || ((obj.sprite) && (!obj.sprite.visible))) | |||
continue; | |||
ns.visible = showNames; | |||
} | |||
} | |||
}, | |||
onTilesVisible: function (tiles, visible) { | |||
let objects = this.objects; | |||
let oLen = objects.length; | |||
@@ -383,6 +353,19 @@ define([ | |||
o.setVisible(visible); | |||
} | |||
}, | |||
onToggleNameplates: function (show) { | |||
let objects = this.objects; | |||
let oLen = objects.length; | |||
for (let i = 0; i < oLen; i++) { | |||
let obj = objects[i]; | |||
let ns = obj.nameSprite; | |||
if ((!ns) || (obj.dead) || ((obj.sprite) && (!obj.sprite.visible))) | |||
continue; | |||
ns.visible = show; | |||
} | |||
} | |||
}; | |||
}); |
@@ -1,15 +1,23 @@ | |||
define([ | |||
'howler', | |||
'js/misc/physics' | |||
'js/misc/physics', | |||
'js/system/events', | |||
'js/config' | |||
], function ( | |||
howler, | |||
physics | |||
physics, | |||
events, | |||
config | |||
) { | |||
return { | |||
sounds: [], | |||
init: function (zone) { | |||
muted: false, | |||
init: function () { | |||
events.on('onToggleAudio', this.onToggleAudio.bind(this)); | |||
this.onToggleAudio(config.playAudio); | |||
}, | |||
unload: function (zoneId) { | |||
@@ -24,7 +32,7 @@ define([ | |||
}, | |||
update: function (x, y) { | |||
this.sounds.forEach(function (s) { | |||
this.sounds.forEach(s => { | |||
let volume; | |||
if (!s.w) { | |||
@@ -67,9 +75,13 @@ define([ | |||
loop: true, | |||
volume: 0 | |||
}); | |||
if (this.muted) | |||
s.sound.mute(true); | |||
} | |||
s.sound.volume(volume * s.volume); | |||
if (!this.muted) | |||
s.sound.volume(volume * s.volume); | |||
}); | |||
}, | |||
@@ -96,6 +108,24 @@ define([ | |||
}; | |||
this.sounds.push(sound); | |||
}, | |||
onToggleAudio: function (isAudioOn) { | |||
this.muted = !isAudioOn; | |||
this.sounds.forEach(s => { | |||
if (!s.sound) | |||
return; | |||
s.sound.mute(this.muted); | |||
}); | |||
if (!window.player) | |||
return; | |||
const { player: { x, y } } = window; | |||
this.update(x, y); | |||
} | |||
}; | |||
}); |
@@ -101,15 +101,25 @@ define([ | |||
onUiKeyDown: function (keyEvent) { | |||
if (keyEvent.key === 'esc') { | |||
this.uis.forEach(function (u) { | |||
const closed = []; | |||
this.uis.forEach(u => { | |||
if (!u.modal || !u.shown) | |||
return; | |||
keyEvent.consumed = true; | |||
u.hide(); | |||
closed.push(u); | |||
}); | |||
$('.uiOverlay').hide(); | |||
events.emit('onHideContextMenu'); | |||
closed.forEach(c => { | |||
if (c.afterHide) | |||
c.afterHide(); | |||
}); | |||
} else if (['o', 'j', 'h', 'i'].indexOf(keyEvent.key) > -1) | |||
$('.uiOverlay').hide(); | |||
}, | |||
@@ -3,13 +3,15 @@ define([ | |||
'js/system/events', | |||
'html!ui/templates/events/template', | |||
'html!ui/templates/events/templateEvent', | |||
'css!ui/templates/events/styles' | |||
'css!ui/templates/events/styles', | |||
'js/config' | |||
], function ( | |||
client, | |||
events, | |||
tpl, | |||
templateEvent, | |||
styles | |||
styles, | |||
config | |||
) { | |||
return { | |||
tpl: tpl, | |||
@@ -30,6 +32,9 @@ define([ | |||
this.onEvent('onRemoveEvent', this.onRemoveEvent.bind(this)); | |||
this.onEvent('onUpdateEvent', this.onUpdateEvent.bind(this)); | |||
this.onEvent('onCompleteEvent', this.onCompleteEvent.bind(this)); | |||
this.onEvent('onToggleEventsVisibility', this.onToggleEventsVisibility.bind(this)); | |||
this.onToggleEventsVisibility(config.showEvents); | |||
}, | |||
onRezone: function () { | |||
@@ -112,6 +117,15 @@ define([ | |||
toggleButtons: function (e) { | |||
this.el.toggleClass('active'); | |||
e.stopPropagation(); | |||
}, | |||
onToggleEventsVisibility: function (active) { | |||
this.shown = active; | |||
if (this.shown) | |||
this.show(); | |||
else | |||
this.hide(); | |||
} | |||
}; | |||
}); |
@@ -26,7 +26,6 @@ define([ | |||
postRender: function () { | |||
this.onEvent('onToggleMainMenu', this.toggle.bind(this)); | |||
//this.el.find('.btnOptions').on('click', this.openOptions.bind(this)); | |||
this.el.find('.btnOptions').on('click', this.handler.bind(this, 'onToggleOptions')); | |||
this.el.find('.btnCharSelect').on('click', this.charSelect.bind(this)); | |||
this.el.find('.btnLogOut').on('click', this.logOut.bind(this)); | |||
@@ -6,7 +6,8 @@ define([ | |||
'ui/factory', | |||
'js/objects/objects', | |||
'js/system/client', | |||
'js/sound/sound' | |||
'js/sound/sound', | |||
'js/config' | |||
], function ( | |||
events, | |||
template, | |||
@@ -15,36 +16,95 @@ define([ | |||
factory, | |||
objects, | |||
client, | |||
sound | |||
sound, | |||
config | |||
) { | |||
return { | |||
tpl: template, | |||
centered: true, | |||
modal: true, | |||
hasClose: true, | |||
postRender: function () { | |||
this.onEvent('onToggleOptions', this.toggle.bind(this)); | |||
this.onEvent('onToggleOptions', this.toggle.bind(this)); | |||
//Can only toggle fullscreen directly in a listener, not deferred the way jQuery does it | |||
this.el.find('.btnScreen')[0].addEventListener('click', this.toggleScreen.bind(this)); | |||
this.el.find('.btnNames').on('click', events.emit.bind(events, 'onKeyDown', 'v')); | |||
this.el.find('.btnQuests').on('click', events.emit.bind(events, 'onToggleQuestVisibility')); | |||
this.el.find('.btnCloseOptions').on('click', this.toggle.bind(this)); | |||
this.find('.item.screen .name')[0].addEventListener('click', this.toggleScreen.bind(this)); | |||
this.find('.item.nameplates .name').on('click', events.emit.bind(events, 'onUiKeyDown', { key: 'v' })); | |||
this.find('.item.quests .name').on('click', this.toggleQuests.bind(this)); | |||
this.find('.item.events .name').on('click', this.toggleEvents.bind(this)); | |||
this.find('.item.audio .name').on('click', this.toggleAudio.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('onToggleEventsVisibility', this.onToggleEventsVisibility.bind(this)); | |||
this.onEvent('onToggleQuestsVisibility', this.onToggleQuestsVisibility.bind(this)); | |||
}, | |||
toggleScreen: function () { | |||
this.el.find('.btnScreen').html(renderer.toggleScreen()); | |||
const state = renderer.toggleScreen(); | |||
const newValue = (state === 'Windowed') ? 'Off' : 'On'; | |||
this.find('.item.screen .value').html(newValue); | |||
}, | |||
toggleEvents: function () { | |||
config.toggle('showEvents'); | |||
events.emit('onToggleEventsVisibility', config.showEvents); | |||
}, | |||
toggleQuests: function () { | |||
config.toggle('showQuests'); | |||
events.emit('onToggleQuestsVisibility', config.showQuests); | |||
}, | |||
onToggleEventsVisibility: function (state) { | |||
const newValue = state ? 'On' : 'Off'; | |||
this.find('.item.events .value').html(newValue); | |||
}, | |||
onToggleQuestsVisibility: function (state) { | |||
const newValue = state[0].toUpperCase() + state.substr(1); | |||
this.find('.item.quests .value').html(newValue); | |||
}, | |||
onResize: function () { | |||
let isFullscreen = (window.innerHeight === screen.height); | |||
if (isFullscreen) | |||
this.el.find('.btnScreen').html('Windowed'); | |||
else | |||
this.el.find('.btnScreen').html('Fullscreen'); | |||
const newValue = isFullscreen ? 'On' : 'Off'; | |||
this.find('.item.screen .value').html(newValue); | |||
}, | |||
onToggleNameplates: function (state) { | |||
const newValue = state ? 'On' : 'Off'; | |||
this.find('.item.nameplates .value').html(newValue); | |||
}, | |||
toggleAudio: function () { | |||
config.toggle('playAudio'); | |||
events.emit('onToggleAudio', config.playAudio); | |||
}, | |||
onToggleAudio: function (isAudioOn) { | |||
const newValue = isAudioOn ? 'On' : 'Off'; | |||
this.find('.item.audio .value').html(newValue); | |||
}, | |||
build: function () { | |||
this.onToggleNameplates(config.showNames); | |||
this.onToggleAudio(config.playAudio); | |||
this.onToggleEventsVisibility(config.showEvents); | |||
this.onToggleQuestsVisibility(config.showQuests); | |||
}, | |||
toggle: function () { | |||
@@ -55,15 +115,29 @@ define([ | |||
if (this.shown) { | |||
this.show(); | |||
events.emit('onShowOverlay', this.el); | |||
this.build(); | |||
} else { | |||
this.hide(); | |||
events.emit('onHideOverlay', this.el); | |||
events.emit('onToggleMainMenu'); | |||
} | |||
}, | |||
}, | |||
onKeyDown: function (key) { | |||
if (key === 'esc') | |||
this.toggle(); | |||
onKeyDown: function (keyEvent) { | |||
const { key } = keyEvent; | |||
if (key === 'v') { | |||
config.toggle('showNames'); | |||
events.emit('onToggleNameplates', config.showNames); | |||
const newValue = config.showNames ? 'On' : 'Off'; | |||
this.find('.item.nameplates .value').html(newValue); | |||
} | |||
}, | |||
afterHide: function () { | |||
events.emit('onToggleMainMenu'); | |||
} | |||
}; | |||
}); |
@@ -2,48 +2,73 @@ | |||
.uiOptions { | |||
display: none; | |||
width: 400px; | |||
background-color: @gray; | |||
border: 4px solid @lightGray; | |||
background-color: @blackC; | |||
text-align: center; | |||
padding: 0px 16px; | |||
.btn { | |||
color: @white; | |||
width: 100%; | |||
height: 32px; | |||
background-color: @blue; | |||
margin: 16px 0px; | |||
padding-top: 8px; | |||
cursor: pointer; | |||
/*&.btnNames { | |||
display: none; | |||
}*/ | |||
&:hover { | |||
background-color: lighten(@blue, 15%); | |||
color: @black; | |||
} | |||
} | |||
.btnCloseOptions { | |||
background-color: @red; | |||
&:hover { | |||
background-color: lighten(@red, 15%); | |||
color: @black; | |||
border: 5px solid @blackB; | |||
> .heading { | |||
color: @blueA; | |||
width: 100%; | |||
height: 36px; | |||
background-color: @blackB; | |||
position: relative; | |||
.heading-text { | |||
padding-top: 8px; | |||
margin: auto; | |||
} | |||
} | |||
.bottom { | |||
padding: 10px; | |||
.list { | |||
display: flex; | |||
flex-direction: column; | |||
.item { | |||
height: 30px; | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
.name { | |||
color: @blueB; | |||
flex: 1; | |||
height: 100%; | |||
display: flex; | |||
align-items: center; | |||
padding: 0px 10px; | |||
margin-right: 10px; | |||
cursor: pointer; | |||
&:hover { | |||
color: @blueA; | |||
background-color: @blackA; | |||
} | |||
} | |||
.value { | |||
color: @white; | |||
display: flex; | |||
align-items: center; | |||
justify-content: flex-end; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.mobile .uiOptions { | |||
.btnScreen { | |||
.item.screen { | |||
display: none; | |||
} | |||
.btnNames { | |||
display: block; | |||
} | |||
} |
@@ -1,6 +1,29 @@ | |||
<div class="uiOptions"> | |||
<div class="btn btnScreen">Windowed</div> | |||
<div class="btn btnNames">Toggle Nameplates</div> | |||
<div class="btn btnQuests">Toggle Inactive Quests</div> | |||
<div class="btn btnCloseOptions">Close</div> | |||
<div class="heading"> | |||
<div class="heading-text">Options</div> | |||
</div> | |||
<div class="bottom"> | |||
<div class="list"> | |||
<div class="item screen"> | |||
<div class="name">Fullscreen</div> | |||
<div class="value">Off</div> | |||
</div> | |||
<div class="item nameplates"> | |||
<div class="name">Nameplates</div> | |||
<div class="value">On</div> | |||
</div> | |||
<div class="item quests"> | |||
<div class="name">Quests</div> | |||
<div class="value">On</div> | |||
</div> | |||
<div class="item events"> | |||
<div class="name">Events</div> | |||
<div class="value">On</div> | |||
</div> | |||
<div class="item audio"> | |||
<div class="name">Audio</div> | |||
<div class="value">On</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -3,13 +3,15 @@ define([ | |||
'js/system/events', | |||
'html!ui/templates/quests/template', | |||
'html!ui/templates/quests/templateQuest', | |||
'css!ui/templates/quests/styles' | |||
'css!ui/templates/quests/styles', | |||
'js/config' | |||
], function ( | |||
client, | |||
events, | |||
tpl, | |||
templateQuest, | |||
styles | |||
styles, | |||
config | |||
) { | |||
return { | |||
tpl: tpl, | |||
@@ -28,7 +30,9 @@ define([ | |||
this.onEvent('onObtainQuest', this.onObtainQuest.bind(this)); | |||
this.onEvent('onUpdateQuest', this.onUpdateQuest.bind(this)); | |||
this.onEvent('onCompleteQuest', this.onCompleteQuest.bind(this)); | |||
this.onEvent('onToggleQuestVisibility', this.onToggleQuestVisibility.bind(this)); | |||
this.onEvent('onToggleQuestsVisibility', this.onToggleQuestsVisibility.bind(this)); | |||
this.onToggleQuestsVisibility(config.showQuests); | |||
}, | |||
onRezone: function () { | |||
@@ -121,11 +125,17 @@ define([ | |||
e.stopPropagation(); | |||
}, | |||
onToggleQuestVisibility: function() { | |||
let inactiveQuests = this.quests.filter(f => f.quest.active === false); | |||
inactiveQuests.forEach(q => { | |||
q.el.toggle(); | |||
}) | |||
}, | |||
onToggleQuestsVisibility: function (state) { | |||
this.shown = state !== 'off'; | |||
if (this.shown) | |||
this.show(); | |||
else | |||
this.hide(); | |||
this.el.removeClass('minimal'); | |||
if (state === 'minimal') | |||
this.el.addClass('minimal'); | |||
} | |||
}; | |||
}); |
@@ -97,6 +97,13 @@ | |||
display: none; | |||
} | |||
&.minimal { | |||
.quest.disabled { | |||
display: none; | |||
} | |||
} | |||
} | |||
.mobile .uiQuests { | |||