Compare commits
3 commits
33257e367b
...
9cb3c1e1d9
Author | SHA1 | Date | |
---|---|---|---|
flash | 9cb3c1e1d9 | ||
flash | 66aea64da1 | ||
flash | f82785a9cb |
|
@ -4,6 +4,8 @@
|
||||||
@include controls/msgbox.css;
|
@include controls/msgbox.css;
|
||||||
@include controls/views.css;
|
@include controls/views.css;
|
||||||
|
|
||||||
|
@include sound/sndtest.css;
|
||||||
|
|
||||||
@include baka.css;
|
@include baka.css;
|
||||||
@include ping.css;
|
@include ping.css;
|
||||||
@include chat.css;
|
@include chat.css;
|
||||||
|
|
80
src/mami.css/sound/sndtest.css
Normal file
80
src/mami.css/sound/sndtest.css
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
.sndtest {
|
||||||
|
color: #000;
|
||||||
|
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
color: #fff;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
.sndtest button {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sndtest-view {
|
||||||
|
margin: 2px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.sndtest-view button {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
background: #f55;
|
||||||
|
color: #fff;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
border-bottom: #f00;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sndtest-controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sndtest-library {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
.sndtest-library button {
|
||||||
|
border: 1px solid #222;
|
||||||
|
border-radius: 0;
|
||||||
|
background: #111;
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sndtest-playing {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
gap: 2px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sndtest-player {
|
||||||
|
display: flex;
|
||||||
|
background: #111;
|
||||||
|
border: 1px solid #222;
|
||||||
|
padding: 4px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.sndtest-player button {
|
||||||
|
border: 1px solid #333;
|
||||||
|
border-radius: 0;
|
||||||
|
background: #222;
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
.sndtest-player-details {
|
||||||
|
min-width: 500px;
|
||||||
|
}
|
||||||
|
.sndtest-player-title {
|
||||||
|
font-size: 1.4em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
|
@ -27,16 +27,6 @@ const MamiViewsControl = function(options) {
|
||||||
return element;
|
return element;
|
||||||
};
|
};
|
||||||
|
|
||||||
const doTransition = async (transition, ctx) => {
|
|
||||||
if(transition === undefined)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(typeof transition !== 'function')
|
|
||||||
return;
|
|
||||||
|
|
||||||
await transition(ctx);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateZIncides = () => {
|
const updateZIncides = () => {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for(const view of views)
|
for(const view of views)
|
||||||
|
@ -73,12 +63,18 @@ const MamiViewsControl = function(options) {
|
||||||
if(typeof prevElemInfo.onViewBackground === 'function')
|
if(typeof prevElemInfo.onViewBackground === 'function')
|
||||||
await prevElemInfo.onViewBackground();
|
await prevElemInfo.onViewBackground();
|
||||||
|
|
||||||
await doTransition(transition, {
|
if(transition !== false) {
|
||||||
toInfo: elementInfo,
|
if(typeof transition !== 'function' && typeof elementInfo.getViewTransition === 'function')
|
||||||
toElem: element,
|
transition = elementInfo.getViewTransition('push');
|
||||||
fromInfo: prevElemInfo,
|
|
||||||
fromElem: prevElem,
|
if(typeof transition === 'function')
|
||||||
});
|
await transition({
|
||||||
|
toInfo: elementInfo,
|
||||||
|
toElem: element,
|
||||||
|
fromInfo: prevElemInfo,
|
||||||
|
fromElem: prevElem,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,12 +96,18 @@ const MamiViewsControl = function(options) {
|
||||||
if(typeof nextElemInfo.onViewForeground === 'function')
|
if(typeof nextElemInfo.onViewForeground === 'function')
|
||||||
await nextElemInfo.onViewForeground();
|
await nextElemInfo.onViewForeground();
|
||||||
|
|
||||||
await doTransition(transition, {
|
if(transition !== false) {
|
||||||
toInfo: nextElemInfo,
|
if(typeof transition !== 'function' && typeof elementInfo.getViewTransition === 'function')
|
||||||
toElem: nextElem,
|
transition = elementInfo.getViewTransition('pop');
|
||||||
fromInfo: elementInfo,
|
|
||||||
fromElem: element,
|
if(typeof transition === 'function')
|
||||||
});
|
await transition({
|
||||||
|
toInfo: nextElemInfo,
|
||||||
|
toElem: nextElem,
|
||||||
|
fromInfo: elementInfo,
|
||||||
|
fromElem: element,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof elementInfo.onViewBackground === 'function')
|
if(typeof elementInfo.onViewBackground === 'function')
|
||||||
|
|
|
@ -11,6 +11,7 @@ const MamiSettingsScoped = function(settings, prefix) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
define: name => settings.define(prefix + name),
|
define: name => settings.define(prefix + name),
|
||||||
|
defined: name => settings.defined(prefix + name),
|
||||||
info: name => settings.info(prefix + name),
|
info: name => settings.info(prefix + name),
|
||||||
names: () => {
|
names: () => {
|
||||||
const filtered = [];
|
const filtered = [];
|
||||||
|
|
|
@ -209,6 +209,7 @@ const MamiSettings = function(storageOrPrefix, eventTarget) {
|
||||||
|
|
||||||
const pub = {
|
const pub = {
|
||||||
define: name => new settingBlueprint(name),
|
define: name => new settingBlueprint(name),
|
||||||
|
defined: name => settings.has(name),
|
||||||
info: name => getSetting(name),
|
info: name => getSetting(name),
|
||||||
names: () => Array.from(settings.keys()),
|
names: () => Array.from(settings.keys()),
|
||||||
has: name => {
|
has: name => {
|
||||||
|
|
|
@ -121,7 +121,7 @@ const MamiSockChatHandlers = function(ctx, client, setLoadingOverlay, sockChatRe
|
||||||
if(dumpEvents) console.log('session:fail', ev.detail);
|
if(dumpEvents) console.log('session:fail', ev.detail);
|
||||||
|
|
||||||
if(ev.detail.baka !== undefined) {
|
if(ev.detail.baka !== undefined) {
|
||||||
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(ctx.views);
|
ctx.views.push(new MamiForceDisconnectNotice(ev.detail.baka));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ const MamiSockChatHandlers = function(ctx, client, setLoadingOverlay, sockChatRe
|
||||||
handlers['session:term'] = ev => {
|
handlers['session:term'] = ev => {
|
||||||
if(dumpEvents) console.log('session:term', ev.detail);
|
if(dumpEvents) console.log('session:term', ev.detail);
|
||||||
|
|
||||||
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(ctx.views);
|
ctx.views.push(new MamiForceDisconnectNotice(ev.detail.baka));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,33 +8,27 @@ const MamiSoundContext = function() {
|
||||||
const manager = new MamiSoundManager(audioCtx);
|
const manager = new MamiSoundManager(audioCtx);
|
||||||
const library = new MamiSoundLibrary(manager);
|
const library = new MamiSoundLibrary(manager);
|
||||||
const packs = new MamiSoundPacks;
|
const packs = new MamiSoundPacks;
|
||||||
|
|
||||||
let pack = new MamiSoundPack;
|
let pack = new MamiSoundPack;
|
||||||
|
|
||||||
const pub = {};
|
return {
|
||||||
|
get audio() { return audioCtx; },
|
||||||
|
get manager() { return manager; },
|
||||||
|
get library() { return library; },
|
||||||
|
get packs() { return packs; },
|
||||||
|
|
||||||
Object.defineProperties(pub, {
|
get pack() { return pack; },
|
||||||
audio: { value: audioCtx, enumerable: true },
|
set pack(value) {
|
||||||
manager: { value: manager, enumerable: true },
|
if(typeof value !== 'object' || typeof value.getEventSound !== 'function')
|
||||||
library: { value: library, enumerable: true },
|
throw 'value is not a valid soundpack';
|
||||||
packs: { value: packs, enumerable: true },
|
pack = value;
|
||||||
|
|
||||||
pack: {
|
|
||||||
get: () => pack,
|
|
||||||
set: value => {
|
|
||||||
if(typeof value !== 'object' || typeof value.getEventSound !== 'function')
|
|
||||||
throw 'value is not a valid soundpack';
|
|
||||||
pack = value;
|
|
||||||
},
|
|
||||||
enumerable: true,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ready: { get: audioCtx.isReady, enumerable: true },
|
get ready() { return audioCtx.isReady; },
|
||||||
volume: { get: audioCtx.getVolume, set: audioCtx.setVolume, enumerable: true },
|
get volume() { return audioCtx.getVolume(); },
|
||||||
muted: { get: audioCtx.isMuted, set: audioCtx.setMuted, enumerable: true },
|
set volume(value) { audioCtx.setVolume(value); },
|
||||||
});
|
get muted() { return audioCtx.isMuted; },
|
||||||
|
set muted(value) { audioCtx.setMuted(value); },
|
||||||
|
|
||||||
pub.reset = audioCtx.reset;
|
reset: audioCtx.reset,
|
||||||
|
};
|
||||||
return Object.freeze(pub);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,8 +32,6 @@ const MamiSoundLibrary = function(soundMgr) {
|
||||||
throw 'soundInfo must contain a name field';
|
throw 'soundInfo must contain a name field';
|
||||||
if(typeof soundInfo.sources !== 'object')
|
if(typeof soundInfo.sources !== 'object')
|
||||||
throw 'soundInfo must contain a sources field';
|
throw 'soundInfo must contain a sources field';
|
||||||
if(sounds.has(soundInfo.name))
|
|
||||||
throw 'a sound with that name has already been registered';
|
|
||||||
|
|
||||||
let sources = {},
|
let sources = {},
|
||||||
sCount = 0;
|
sCount = 0;
|
||||||
|
|
|
@ -71,8 +71,6 @@ const MamiSoundPacks = function() {
|
||||||
throw 'packInfo must contain a name field';
|
throw 'packInfo must contain a name field';
|
||||||
if(typeof packInfo.events !== 'object')
|
if(typeof packInfo.events !== 'object')
|
||||||
throw 'packInfo must contain a events field';
|
throw 'packInfo must contain a events field';
|
||||||
if(packs.has(packInfo.name))
|
|
||||||
throw 'a pack with that name has already been registered';
|
|
||||||
|
|
||||||
const events = new Map;
|
const events = new Map;
|
||||||
for(const eventName in packInfo.events) {
|
for(const eventName in packInfo.events) {
|
||||||
|
|
194
src/mami.js/sound/sndtest.jsx
Normal file
194
src/mami.js/sound/sndtest.jsx
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
#include awaitable.js
|
||||||
|
|
||||||
|
const MamiSoundTest = function(settings, audio, manager, library, clickPos) {
|
||||||
|
if(!settings.defined('soundRate'))
|
||||||
|
settings.define('soundRate').default(1.0).min(0.001).max(2.0).virtual().create();
|
||||||
|
if(!settings.defined('soundDetune'))
|
||||||
|
settings.define('soundDetune').default(0).min(-1200).max(1200).virtual().create();
|
||||||
|
if(!settings.defined('soundLoopStart'))
|
||||||
|
settings.define('soundLoopStart').default(0).min(0).virtual().create();
|
||||||
|
if(!settings.defined('soundLoopEnd'))
|
||||||
|
settings.define('soundLoopEnd').default(0).min(0).virtual().create();
|
||||||
|
if(!settings.defined('soundReverse'))
|
||||||
|
settings.define('soundReverse').default(false).virtual().create();
|
||||||
|
|
||||||
|
const hasClickPos = Array.isArray(clickPos) && clickPos.length > 1;
|
||||||
|
const volumeSetting = settings.info('soundVolume');
|
||||||
|
const rateSetting = settings.info('soundRate');
|
||||||
|
const detuneSetting = settings.info('soundDetune');
|
||||||
|
const loopStartSetting = settings.info('soundLoopStart');
|
||||||
|
const loopEndSetting = settings.info('soundLoopEnd');
|
||||||
|
const sources = [];
|
||||||
|
|
||||||
|
let libraryButtons;
|
||||||
|
let nowPlaying;
|
||||||
|
let searchBox, volumeSlider, rateSlider, detuneSlider;
|
||||||
|
let loopStartBox, loopEndBox, reverseBox;
|
||||||
|
const container = <div class="sndtest">
|
||||||
|
<div class="sndtest-view">
|
||||||
|
<button onclick={() => { mami.views.pop(); }}>Exit</button>
|
||||||
|
</div>
|
||||||
|
<div class="sndtest-controls">
|
||||||
|
<label class="sndtest-control">
|
||||||
|
<div class="sndtest-control-name">Search</div>
|
||||||
|
{searchBox = <input type="text" placeholder="type to filter"/>}
|
||||||
|
</label>
|
||||||
|
<label class="sndtest-control">
|
||||||
|
<div class="sndtest-control-name">Volume</div>
|
||||||
|
{volumeSlider = <input type="range" min={volumeSetting.min} max={volumeSetting.max} onchange={() => { settings.set('soundVolume', volumeSlider.value); }} ondblclick={() => { settings.delete('soundVolume'); }}/>}
|
||||||
|
</label>
|
||||||
|
<label class="sndtest-control">
|
||||||
|
<div class="sndtest-control-name">Rate</div>
|
||||||
|
{rateSlider = <input type="range" min={rateSetting.min * 1000} max={rateSetting.max * 1000} onchange={() => { settings.set('soundRate', rateSlider.value / 1000); }} ondblclick={() => { settings.delete('soundRate'); }}/>}
|
||||||
|
</label>
|
||||||
|
<label class="sndtest-control">
|
||||||
|
<div class="sndtest-control-name">Detune</div>
|
||||||
|
{detuneSlider = <input type="range" min={detuneSetting.min} max={detuneSetting.max} onchange={() => { settings.set('soundDetune', detuneSlider.value); }} ondblclick={() => { settings.delete('soundDetune'); }}/>}
|
||||||
|
</label>
|
||||||
|
<label class="sndtest-control">
|
||||||
|
<div class="sndtest-control-name">Loop start</div>
|
||||||
|
{loopStartBox = <input type="number" step="0.00001" min={loopStartSetting.min} onchange={() => { settings.set('soundLoopStart', loopStartBox.value); }} ondblclick={() => { settings.delete('soundLoopStart'); }}/>}
|
||||||
|
</label>
|
||||||
|
<label class="sndtest-control">
|
||||||
|
<div class="sndtest-control-name">Loop end</div>
|
||||||
|
{loopEndBox = <input type="number" step="0.00001" min={loopEndSetting.min} onchange={() => { settings.set('soundLoopEnd', loopEndBox.value); }} ondblclick={() => { settings.delete('soundLoopEnd'); }}/>}
|
||||||
|
</label>
|
||||||
|
<label class="sndtest-control">
|
||||||
|
<div class="sndtest-control-name">Reverse</div>
|
||||||
|
{reverseBox = <input type="checkbox" onchange={() => { settings.set('soundReverse', reverseBox.checked); }}/>}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{libraryButtons = <div class="sndtest-library"/>}
|
||||||
|
{nowPlaying = <div class="sndtest-playing"/>}
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
settings.watch('soundVolume', ev => {
|
||||||
|
volumeSlider.value = ev.detail.value;
|
||||||
|
});
|
||||||
|
settings.watch('soundRate', ev => {
|
||||||
|
rateSlider.value = ev.detail.value * 1000;
|
||||||
|
|
||||||
|
for(const source of sources)
|
||||||
|
source.setRate(ev.detail.value);
|
||||||
|
});
|
||||||
|
settings.watch('soundDetune', ev => {
|
||||||
|
detuneSlider.value = ev.detail.value;
|
||||||
|
|
||||||
|
for(const source of sources)
|
||||||
|
source.setDetune(ev.detail.value);
|
||||||
|
});
|
||||||
|
settings.watch('soundLoopStart', ev => {
|
||||||
|
loopStartBox.value = ev.detail.value;
|
||||||
|
});
|
||||||
|
settings.watch('soundLoopEnd', ev => {
|
||||||
|
loopEndBox.value = ev.detail.value;
|
||||||
|
});
|
||||||
|
settings.watch('soundReverse', ev => {
|
||||||
|
reverseBox.checked = ev.detail.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const startPlay = async info => {
|
||||||
|
let controls, state, name;
|
||||||
|
const player = <div class="sndtest-player">
|
||||||
|
<div class="sndtest-player-details">
|
||||||
|
<div class="sndtest-player-title">{info.getTitle()}</div>
|
||||||
|
{name = <div class="sndtest-player-name">{info.getName()}</div>}
|
||||||
|
</div>
|
||||||
|
{controls = <div class="sndtest-player-controls"/>}
|
||||||
|
{state = <div class="sndtest-player-state"/>}
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
nowPlaying.appendChild(player);
|
||||||
|
|
||||||
|
let buffer, source;
|
||||||
|
try {
|
||||||
|
state.textContent = 'Loading...';
|
||||||
|
buffer = await manager.loadBuffer(info.getSources());
|
||||||
|
name.textContent += ` (${buffer.duration})`;
|
||||||
|
|
||||||
|
source = audio.createSource(buffer, settings.get('soundReverse'));
|
||||||
|
sources.push(source);
|
||||||
|
|
||||||
|
state.textContent = 'Configuring...';
|
||||||
|
const rate = settings.get('soundRate');
|
||||||
|
source.setRate(rate);
|
||||||
|
|
||||||
|
const detune = settings.get('soundDetune');
|
||||||
|
source.setDetune(detune);
|
||||||
|
|
||||||
|
const loopStart = settings.get('soundLoopStart');
|
||||||
|
const loopEnd = settings.get('soundLoopEnd');
|
||||||
|
source.setLoop(loopEnd > 0, loopStart, loopEnd);
|
||||||
|
|
||||||
|
controls.appendChild(<button onclick={() => source.stop()}>Stop</button>);
|
||||||
|
|
||||||
|
state.textContent = 'Playing...';
|
||||||
|
await source.play();
|
||||||
|
|
||||||
|
state.textContent = 'Finished.';
|
||||||
|
} catch(ex) {
|
||||||
|
console.error(ex);
|
||||||
|
state.textContent = `Error: ${ex}`;
|
||||||
|
} finally {
|
||||||
|
$ari(sources, source);
|
||||||
|
await MamiSleep(2000);
|
||||||
|
nowPlaying.removeChild(player);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const names = library.names();
|
||||||
|
for(const name of names) {
|
||||||
|
const info = library.info(name);
|
||||||
|
libraryButtons.appendChild(<button onclick={() => { startPlay(info); }} data-search={`${info.getTitle().toLowerCase()} ${info.getName().toLowerCase()}`}>{info.getTitle()} ({info.getName()})</button>);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchBox.addEventListener('change', () => {
|
||||||
|
const str = searchBox.value.trim().toLowerCase();
|
||||||
|
for(const button of libraryButtons.children)
|
||||||
|
button.classList.toggle('hidden', !button.dataset.search.includes(str));
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
getElement: () => container,
|
||||||
|
onViewPop: async () => {
|
||||||
|
for(const source of sources)
|
||||||
|
source.stop();
|
||||||
|
},
|
||||||
|
getViewTransition: mode => {
|
||||||
|
if(!hasClickPos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(mode === 'push')
|
||||||
|
return ctx => MamiAnimate({
|
||||||
|
async: true,
|
||||||
|
duration: 1500,
|
||||||
|
easing: 'inQuad',
|
||||||
|
start: () => {
|
||||||
|
library.play('mario:keyhole');
|
||||||
|
ctx.toElem.style.transform = 'scale(0) translate(25%, 25%)';
|
||||||
|
ctx.toElem.style.transformOrigin = `${clickPos[0]}px ${clickPos[1]}px`;
|
||||||
|
},
|
||||||
|
update: (t, rt) => ctx.toElem.style.transform = `scale(${t}) translate(${25 * (1 - rt)}%, ${25 * (1 - rt)}%)`,
|
||||||
|
end: () => {
|
||||||
|
ctx.toElem.style.transform = null;
|
||||||
|
ctx.toElem.style.transformOrigin = null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if(mode === 'pop')
|
||||||
|
return ctx => MamiAnimate({
|
||||||
|
async: true,
|
||||||
|
duration: 1000,
|
||||||
|
easing: 'outQuad',
|
||||||
|
start: () => {
|
||||||
|
ctx.fromElem.style.transformOrigin = `${clickPos[0]}px ${clickPos[1]}px`;
|
||||||
|
},
|
||||||
|
update: (t, rt) => ctx.fromElem.style.transform = `scale(${1 - t}) rotate(${-1080 * t}deg) translate(${50 * rt}%, ${50 * rt}%)`,
|
||||||
|
end: () => {
|
||||||
|
ctx.fromElem.style.transform = null;
|
||||||
|
ctx.fromElem.style.transformOrigin = null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
|
@ -47,61 +47,64 @@ const MamiForceDisconnectNotice = function(banInfo) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onViewPop: async () => {
|
onViewPop: async () => {
|
||||||
bgmSrc?.stop();
|
try {
|
||||||
|
bgmSrc?.stop();
|
||||||
|
} catch(ex) {}
|
||||||
bgmSrc = sfxBuf = undefined;
|
bgmSrc = sfxBuf = undefined;
|
||||||
},
|
},
|
||||||
pushOn: async views => {
|
getViewTransition: mode => {
|
||||||
await views.push(pub, ctx => MamiAnimate({
|
if(mode === 'push')
|
||||||
async: true,
|
return ctx => MamiAnimate({
|
||||||
duration: (sfxBuf?.duration ?? 1.4) * 1000,
|
async: true,
|
||||||
start: () => {
|
duration: (sfxBuf?.duration ?? 1.4) * 1000,
|
||||||
if(sfxBuf !== undefined)
|
start: () => {
|
||||||
mami.sound.audio.createSource(sfxBuf).play();
|
if(sfxBuf !== undefined)
|
||||||
|
mami.sound.audio.createSource(sfxBuf).play();
|
||||||
|
|
||||||
ctx.toElem.style.top = '-100%';
|
ctx.toElem.style.top = '-100%';
|
||||||
},
|
},
|
||||||
update: t => {
|
update: t => {
|
||||||
const tOutBounce = MamiEasings.outBounce(t);
|
const tOutBounce = MamiEasings.outBounce(t);
|
||||||
ctx.toElem.style.top = `${-100 + (tOutBounce * 100)}%`;
|
ctx.toElem.style.top = `${-100 + (tOutBounce * 100)}%`;
|
||||||
|
|
||||||
const tOutExpo = MamiEasings.outExpo(t);
|
const tOutExpo = MamiEasings.outExpo(t);
|
||||||
ctx.fromElem.style.transform = `scale(${1 - (1 * tOutExpo)}) rotate(${rotate * tOutExpo}deg)`;
|
ctx.fromElem.style.transform = `scale(${1 - (1 * tOutExpo)}) rotate(${rotate * tOutExpo}deg)`;
|
||||||
ctx.fromElem.style.filter = `grayscale(${tOutExpo * 100}%)`;
|
ctx.fromElem.style.filter = `grayscale(${tOutExpo * 100}%)`;
|
||||||
},
|
},
|
||||||
end: () => {
|
end: () => {
|
||||||
bgmSrc?.play();
|
bgmSrc?.play();
|
||||||
ctx.toElem.style.top = null;
|
ctx.toElem.style.top = null;
|
||||||
ctx.fromElem.style.transform = null;
|
ctx.fromElem.style.transform = null;
|
||||||
ctx.fromElem.style.filter = null;
|
ctx.fromElem.style.filter = null;
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
},
|
|
||||||
popOff: async views => {
|
|
||||||
await views.pop(ctx => MamiAnimate({
|
|
||||||
async: true,
|
|
||||||
duration: (sfxBuf?.duration ?? 1.4) * 1000,
|
|
||||||
start: () => {
|
|
||||||
bgmSrc?.stop();
|
|
||||||
if(sfxBuf !== undefined)
|
|
||||||
mami.sound.audio.createSource(sfxBuf, true).play();
|
|
||||||
|
|
||||||
ctx.toElem.style.transform = `scale(1) rotate(${rotate}deg)`;
|
if(mode === 'pop')
|
||||||
ctx.toElem.style.filter = 'grayscale(100%)';
|
return ctx => MamiAnimate({
|
||||||
},
|
async: true,
|
||||||
update: t => {
|
duration: (sfxBuf?.duration ?? 1.4) * 1000,
|
||||||
const tOutBounce = MamiEasings.inBounce(t);
|
start: () => {
|
||||||
ctx.fromElem.style.top = `${tOutBounce * -100}%`;
|
bgmSrc?.stop();
|
||||||
|
if(sfxBuf !== undefined)
|
||||||
|
mami.sound.audio.createSource(sfxBuf, true).play();
|
||||||
|
|
||||||
const tOutExpo = MamiEasings.inExpo(t);
|
ctx.toElem.style.transform = `scale(1) rotate(${rotate}deg)`;
|
||||||
ctx.toElem.style.transform = `scale(${1 * tOutExpo}) rotate(${rotate - (rotate * tOutExpo)}deg)`;
|
ctx.toElem.style.filter = 'grayscale(100%)';
|
||||||
ctx.toElem.style.filter = `grayscale(${100 - (tOutExpo * 100)}%)`;
|
},
|
||||||
},
|
update: t => {
|
||||||
end: () => {
|
const tOutBounce = MamiEasings.inBounce(t);
|
||||||
ctx.fromElem.style.top = null;
|
ctx.fromElem.style.top = `${tOutBounce * -100}%`;
|
||||||
ctx.toElem.style.transform = null;
|
|
||||||
ctx.toElem.style.filter = null;
|
const tOutExpo = MamiEasings.inExpo(t);
|
||||||
},
|
ctx.toElem.style.transform = `scale(${1 * tOutExpo}) rotate(${rotate - (rotate * tOutExpo)}deg)`;
|
||||||
}));
|
ctx.toElem.style.filter = `grayscale(${100 - (tOutExpo * 100)}%)`;
|
||||||
|
},
|
||||||
|
end: () => {
|
||||||
|
ctx.fromElem.style.top = null;
|
||||||
|
ctx.toElem.style.transform = null;
|
||||||
|
ctx.toElem.style.filter = null;
|
||||||
|
},
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include emotes.js
|
#include emotes.js
|
||||||
#include utility.js
|
#include utility.js
|
||||||
#include settings/backup.js
|
#include settings/backup.js
|
||||||
|
#include sound/sndtest.jsx
|
||||||
#include ui/baka.jsx
|
#include ui/baka.jsx
|
||||||
#include ui/emotes.js
|
#include ui/emotes.js
|
||||||
#include ui/menus.js
|
#include ui/menus.js
|
||||||
|
@ -270,49 +271,17 @@ Umi.UI.Settings = (function() {
|
||||||
title: 'Messages to keep on clear',
|
title: 'Messages to keep on clear',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
},
|
},
|
||||||
{
|
],
|
||||||
title: 'Reload emoticons',
|
},
|
||||||
type: 'button',
|
{
|
||||||
invoke: button => {
|
name: 'actions',
|
||||||
const emotes = futami.get('emotes');
|
title: 'Actions',
|
||||||
setTimeout(() => {
|
items: [
|
||||||
button.disabled = true;
|
|
||||||
|
|
||||||
futami.getJson('emotes', true)
|
|
||||||
.then(emotes => {
|
|
||||||
MamiEmotes.clear();
|
|
||||||
MamiEmotes.loadLegacy(emotes);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
Umi.UI.Emoticons.Init();
|
|
||||||
button.disabled = false;
|
|
||||||
});
|
|
||||||
}, 200);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Reload joke triggers',
|
|
||||||
type: 'button',
|
|
||||||
invoke: button => {
|
|
||||||
button.disabled = true;
|
|
||||||
|
|
||||||
const triggers = mami.textTriggers;
|
|
||||||
triggers.clearTriggers();
|
|
||||||
|
|
||||||
if(mami.settings.get('playJokeSounds'))
|
|
||||||
futami.getJson('texttriggers', true)
|
|
||||||
.then(trigInfos => triggers.addTriggers(trigInfos))
|
|
||||||
.finally(() => button.disabled = false);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Open compatibility client',
|
title: 'Open compatibility client',
|
||||||
type: 'button',
|
type: 'button',
|
||||||
invoke: () => {
|
invoke: () => {
|
||||||
const meow = $e('a', { href: window.AMI_URL, target: '_blank', style: { display: 'none' } });
|
window.open(window.AMI_URL, '_blank', 'noopener');
|
||||||
document.body.appendChild(meow);
|
|
||||||
meow.click();
|
|
||||||
$r(meow);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -337,6 +306,66 @@ Umi.UI.Settings = (function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Reload emoticons',
|
||||||
|
type: 'button',
|
||||||
|
invoke: async button => {
|
||||||
|
const textOrig = button.value;
|
||||||
|
|
||||||
|
button.disabled = true;
|
||||||
|
button.value = 'Reloading emoticons...';
|
||||||
|
try {
|
||||||
|
const emotes = await futami.getJson('emotes', true);
|
||||||
|
MamiEmotes.clear();
|
||||||
|
MamiEmotes.loadLegacy(emotes);
|
||||||
|
} finally {
|
||||||
|
Umi.UI.Emoticons.Init();
|
||||||
|
button.value = textOrig;
|
||||||
|
button.disabled = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Reload sound library',
|
||||||
|
type: 'button',
|
||||||
|
invoke: async button => {
|
||||||
|
const textOrig = button.value;
|
||||||
|
|
||||||
|
button.disabled = true;
|
||||||
|
button.value = 'Reloading sound library...';
|
||||||
|
try {
|
||||||
|
const sounds = await futami.getJson('sounds2');
|
||||||
|
if(Array.isArray(sounds.library))
|
||||||
|
mami.sound.library.register(sounds.library, true);
|
||||||
|
|
||||||
|
if(Array.isArray(sounds.packs)) {
|
||||||
|
mami.sound.packs.register(sounds.packs, true);
|
||||||
|
mami.settings.touch('soundPack', true);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
button.value = textOrig;
|
||||||
|
button.disabled = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Reload joke triggers',
|
||||||
|
type: 'button',
|
||||||
|
invoke: async button => {
|
||||||
|
const textOrig = button.value;
|
||||||
|
|
||||||
|
button.disabled = true;
|
||||||
|
button.value = 'Reloading joke triggers...';
|
||||||
|
try {
|
||||||
|
const triggers = await futami.getJson('texttriggers', true);
|
||||||
|
mami.textTriggers.clearTriggers();
|
||||||
|
mami.textTriggers.addTriggers(triggers)
|
||||||
|
} finally {
|
||||||
|
button.value = textOrig;
|
||||||
|
button.disabled = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -409,10 +438,9 @@ Umi.UI.Settings = (function() {
|
||||||
type: 'button',
|
type: 'button',
|
||||||
invoke: async button => {
|
invoke: async button => {
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
const notice = new MamiForceDisconnectNotice({ perma: true, type: 'ban' });
|
await mami.views.push(new MamiForceDisconnectNotice({ perma: true, type: 'ban' }));
|
||||||
await notice.pushOn(mami.views);
|
|
||||||
await MamiSleep(5000);
|
await MamiSleep(5000);
|
||||||
await notice.popOff(mami.views);
|
await mami.views.pop();
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -421,14 +449,29 @@ Umi.UI.Settings = (function() {
|
||||||
type: 'button',
|
type: 'button',
|
||||||
invoke: async button => {
|
invoke: async button => {
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
await (new MamiYouAreAnIdiot()).pushOn(mami.views);
|
await mami.views.push(new MamiYouAreAnIdiot(mami.sound.library, mami.views));
|
||||||
|
button.disabled = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Sound Test',
|
||||||
|
type: 'button',
|
||||||
|
invoke: async (button, ev) => {
|
||||||
|
button.disabled = true;
|
||||||
|
await mami.views.push(new MamiSoundTest(
|
||||||
|
mami.settings,
|
||||||
|
mami.sound.audio,
|
||||||
|
mami.sound.manager,
|
||||||
|
mami.sound.library,
|
||||||
|
[ev.clientX, ev.clientY],
|
||||||
|
));
|
||||||
button.disabled = false;
|
button.disabled = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Reset audio context',
|
title: 'Reset audio context',
|
||||||
type: 'button',
|
type: 'button',
|
||||||
invoke: async () => {
|
invoke: () => {
|
||||||
mami.sound.reset();
|
mami.sound.reset();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -469,15 +512,15 @@ Umi.UI.Settings = (function() {
|
||||||
updateSelectOptions();
|
updateSelectOptions();
|
||||||
} else if(display.type === 'button') {
|
} else if(display.type === 'button') {
|
||||||
input.value = display.title;
|
input.value = display.title;
|
||||||
input.addEventListener('click', () => {
|
input.addEventListener('click', ev => {
|
||||||
if(display.confirm !== undefined)
|
if(display.confirm !== undefined)
|
||||||
mami.msgbox.show({
|
mami.msgbox.show({
|
||||||
body: display.confirm,
|
body: display.confirm,
|
||||||
yes: { primary: false },
|
yes: { primary: false },
|
||||||
no: { primary: true },
|
no: { primary: true },
|
||||||
}).then(() => { display.invoke(input); }).catch(() => {});
|
}).then(() => { display.invoke(input, ev); }).catch(() => {});
|
||||||
else
|
else
|
||||||
display.invoke(input);
|
display.invoke(input, ev);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#include animate.js
|
#include animate.js
|
||||||
|
|
||||||
const MamiYouAreAnIdiot = function() {
|
const MamiYouAreAnIdiot = function(sndLibrary, views) {
|
||||||
const html = <div class="youare">
|
const html = <div class="youare">
|
||||||
<div class="youare-content">
|
<div class="youare-content">
|
||||||
<div class="youare-text">
|
<div class="youare-text" title="Double click to dismiss!">
|
||||||
<div class="youare-big">you are an idiot</div>
|
<div class="youare-big">you are an idiot</div>
|
||||||
<div class="youare-small">!</div>
|
<div class="youare-small">!</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="youare-smiles">
|
<div class="youare-smiles" title="Double click to dismiss!">
|
||||||
<div class="youare-smile">☺</div>
|
<div class="youare-smile">☺</div>
|
||||||
<div class="youare-smile">☺</div>
|
<div class="youare-smile">☺</div>
|
||||||
<div class="youare-smile">☺</div>
|
<div class="youare-smile">☺</div>
|
||||||
|
@ -15,13 +15,16 @@ const MamiYouAreAnIdiot = function() {
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
|
if(views !== undefined)
|
||||||
|
html.addEventListener('dblclick', () => { views.pop(); });
|
||||||
|
|
||||||
let soundSrc;
|
let soundSrc;
|
||||||
|
|
||||||
const pub = {
|
const pub = {
|
||||||
getElement: () => html,
|
getElement: () => html,
|
||||||
onViewPush: async () => {
|
onViewPush: async () => {
|
||||||
try {
|
try {
|
||||||
soundSrc = await mami.sound.library.loadSource('misc:youare');
|
soundSrc = await sndLibrary.loadSource('misc:youare');
|
||||||
soundSrc.setMuted(true);
|
soundSrc.setMuted(true);
|
||||||
soundSrc.setLoop(true, 0.21, 5);
|
soundSrc.setLoop(true, 0.21, 5);
|
||||||
soundSrc.play();
|
soundSrc.play();
|
||||||
|
@ -42,14 +45,17 @@ const MamiYouAreAnIdiot = function() {
|
||||||
soundSrc.stop();
|
soundSrc.stop();
|
||||||
soundSrc = undefined;
|
soundSrc = undefined;
|
||||||
},
|
},
|
||||||
pushOn: async views => views.push(pub, ctx => MamiAnimate({
|
getViewTransition: mode => {
|
||||||
async: true,
|
if(mode === 'push')
|
||||||
duration: 1500,
|
return ctx => MamiAnimate({
|
||||||
easing: 'outBounce',
|
async: true,
|
||||||
start: () => ctx.toElem.style.top = '-100%',
|
duration: 1500,
|
||||||
update: t => ctx.toElem.style.top = `${-100 + (t * 100)}%`,
|
easing: 'outBounce',
|
||||||
end: () => ctx.toElem.style.top = null,
|
start: () => ctx.toElem.style.top = '-100%',
|
||||||
})),
|
update: t => ctx.toElem.style.top = `${-100 + (t * 100)}%`,
|
||||||
|
end: () => ctx.toElem.style.top = null,
|
||||||
|
});
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return pub;
|
return pub;
|
||||||
|
|
Loading…
Reference in a new issue