From 5b5f3d83c2dfb826e52fbb20694c45f0a6753753 Mon Sep 17 00:00:00 2001 From: firebingo Date: Thu, 19 Apr 2018 14:01:48 -0700 Subject: [PATCH] Fix scaling breaking text container when app container was smaller than text container. Audio and volume controls work. Support for shake command. Text scrolling buttons. --- .gitignore | 1 + Css/main.css | 34 +++++++++-- Images/next_icon.png | Bin 0 -> 33196 bytes Js/Audio.js | 81 ++++++++++++++++++++++++-- Js/Common.js | 20 ++++++- Js/Main.js | 46 ++++++++++++++- Js/Player.js | 132 ++++++++++++++++++++++++++++++++++++------- Js/TextFunctions.js | 75 ++++++++++++++++++------ Js/UtageParse.js | 6 +- Player.html | 25 ++++++-- 10 files changed, 363 insertions(+), 57 deletions(-) create mode 100644 Images/next_icon.png diff --git a/.gitignore b/.gitignore index ceb37e6..c4b39bc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /XDUData / web.config +/Js/Typed diff --git a/Css/main.css b/Css/main.css index fd90aaa..a618643 100644 --- a/Css/main.css +++ b/Css/main.css @@ -41,11 +41,15 @@ .centered { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; } -#app-container { position: relative; width: 1334px; height: 750px; } +.hidden { opacity: 0; } + +.shown { opacity: 0; } + +#app-container { position: relative; width: 1334px; height: 750px; display: flex; justify-content: center; align-items: center; } #parent-container { display: flex; flex-direction: column; align-items: center; } -#text-container { position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: auto; height: 750px; width: 1334px; font-family: 'FOT-RodinNTLGPro'; } +#text-container { position: absolute; margin: auto; height: 750px; width: 1334px; font-family: 'FOT-RodinNTLGPro'; } #text-container #title { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 20px; transition: opacity 0.3s; } @@ -59,10 +63,32 @@ #dialog-box #character { position: absolute; top: -5px; left: 70px; font-size: 30px; } -#dialog-box #dialog { overflow: hidden; position: absolute; padding: 0 30px 0 70px; margin-top: 60px; box-sizing: border-box; height: 120px; width: 100%; font-size: 30px; line-height: 60px; } +#dialog-box #dialog { overflow: hidden; position: absolute; padding: 0 30px 0 70px; margin-top: 60px; box-sizing: border-box; height: 120px; width: 100%; font-size: 28px; font-weight: normal; line-height: 68px; } + +#dialog #dialog-inner { max-width: 1125px; } + +#dialog b { font-weight: bold; } #dialog-box #ui-buttons { right: 20px; top: -50px; position: absolute; } #dialog-box .ui-button { position: relative; height: 85px; } -#other-controls-container { display: flex; width: 100; justify-content: center; } \ No newline at end of file +#dialog #dialog-controls { position: fixed; right: 0; display: flex; height: 135px; align-items: center; } + +#dialog-controls #dialog-next { margin-right: 37px; } + +#dialog-next img { height: 80px; } + +#dialog-controls #dialog-scroll { display: flex; flex-direction: column; height: 80px; margin-right: 30px; justify-content: space-between; } + +#dialog-scroll #dialog-scroll-up { transform: scale(1, -1); } + +#dialog-scroll img { height: 35px; } + +#other-controls-container { display: flex; width: 100; justify-content: center; } + +#select-mission { max-width: 300px; } + +#volume-control { display: flex; margin-right: 10px; } + +#volume-control #mute-button { cursor: pointer; } \ No newline at end of file diff --git a/Images/next_icon.png b/Images/next_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..10b3e4eb9c37fff0689e74382d3a2ff3a2cd8c91 GIT binary patch literal 33196 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 literal 0 HcmV?d00001 diff --git a/Js/Audio.js b/Js/Audio.js index 43ee13b..78e18f2 100644 --- a/Js/Audio.js +++ b/Js/Audio.js @@ -61,15 +61,68 @@ class bufferLoader { } }); } + + resetAll() { + this.bufferList = {}; + } } class audioController { - constructor() { + constructor(utage) { + this.utage = utage; this.volume = 1.0; this.muted = false; this.audioCtx = new (window.AudioContext || window.webkitAudioContext)(); this.gainNode = this.audioCtx.createGain(); + this.gainNode.connect(this.audioCtx.destination); this.loader = undefined; + this.sources = {}; + } + + playSound(sound, type) { + if(!this.loader.bufferList[sound]) { + return; + } + let source = this.audioCtx.createBufferSource() + this.sources[sound] = source; + source.buffer = this.loader.bufferList[sound]; + source.loop = false; + if(type === "bgm") { + if(this.utage.bgmLoopData[this.utage.soundInfo[sound].origFileName]) { + let loop = this.utage.bgmLoopData[this.utage.soundInfo[sound].origFileName]; + source.loopStart = loop["loop_start"]["seconds"]; + source.loopEnd = loop["loop_end"]["seconds"]; + source.loop = true; + } + } + source.connect(this.gainNode); + source.onended = () => { + if(!this.sources[sound]) { return; } + this.sources[sound].disconnect(this.gainNode); + this.sources[sound] = undefined; + } + source.start(0); + } + + stopSound(sound) { + if(sound === 'bgm') { + for(let sKey of Object.keys(this.sources)) { + try { + if(!sKey.startsWith('bgm')) { continue; } + let s = this.sources[sKey]; + s.stop(); + s.disconnect(this.gainNode); + s = undefined; + } catch (error) { } + } + } else { + if(!this.sources[sound]) { + return; + } + this.sources[sound].stop(); + this.sources[sound].disconnect(this.gainNode); + this.sources[sound] = undefined; + } } changeVolume(vol) { @@ -79,10 +132,14 @@ class audioController { } } - mute() { - this.muted = !this.muted; + mute(mute) { + if(mute != undefined) { + this.muted = mute; + } else { + this.muted = !this.muted; + } if(this.muted) { - this.gainNode.gain.setValueAtTime(0, athis.udioCtx.currentTime); + this.gainNode.gain.setValueAtTime(0, this.audioCtx.currentTime); } else { this.gainNode.gain.setValueAtTime(this.volume, this.audioCtx.currentTime); } @@ -96,4 +153,20 @@ class audioController { }); this.loader.load(); } + + resetAll() { + if(this.loader) { + this.loader.resetAll(); + this.loader = undefined; + } + for(let sKey of Object.keys(this.sources)) { + let s = this.sources[sKey]; + try { + s.stop(); + s.disconnect(this.gainNode); + s = undefined; + } catch(error) { } + } + this.sources = {}; + } } \ No newline at end of file diff --git a/Js/Common.js b/Js/Common.js index 725f2e5..2f62a75 100644 --- a/Js/Common.js +++ b/Js/Common.js @@ -85,6 +85,13 @@ class commonFunctions { case "sqrt": t = Math.sqrt(t); break; + //Some of the stuff here is just kinda arbitrary + case "dampsin": + t = (1 * (Math.pow(0.3, t)) * Math.sin((2*Math.PI*t/0.5) + 0)) / 1.25; + if(t < -0.45) { + t = -0.45; + } + break; } return (1 - t) * start + t * end; //-(2*x-1)^4 +1 @@ -165,7 +172,7 @@ class commonFunctions { return {x, y}; } - static getPropertiesFromTweenCommand(props) { + static getPropertiesFromTweenCommand(props, reverseY = true) { var retval = {}; let indexX = props.indexOf("x="); if(indexX !== -1) { @@ -183,7 +190,7 @@ class commonFunctions { if(props[i] == " ") { break; } retval.y += props[i]; } - retval.y = -Number(retval.y); + retval.y = reverseY ? -Number(retval.y) : Number(retval.y); } let indexT = props.indexOf("time="); if(indexT !== -1) { @@ -212,6 +219,15 @@ class commonFunctions { } retval.alpha = Number(retval.alpha); } + let indexS = props.indexOf("speed="); + if(indexS !== -1) { + retval.speed = ""; + for(let i = indexS + 6; i < props.length; ++i) { + if(props[i] == " ") { break; } + retval.speed += props[i]; + } + retval.speed = Number(retval.speed); + } return retval; } } \ No newline at end of file diff --git a/Js/Main.js b/Js/Main.js index 3b9d2fe..6d45bfc 100644 --- a/Js/Main.js +++ b/Js/Main.js @@ -7,7 +7,7 @@ const pixiApp = { const utage = new UtageInfo(); const textFunc = new TextFunctions(); -const audio = new audioController(); +const audio = new audioController(utage); const player = new Player(pixiApp, utage, textFunc, audio); const context = new (window.AudioContext || window.webkitAudioContext)(); const languages = ["eng", "jpn"]; @@ -17,6 +17,8 @@ let selectedLang = "eng"; let screenw = Math.max(document.documentElement.clientWidth, window.innerWidth || 0); let screenh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); let screenSizeTimeout = undefined; +let isMuted = false; +let volume = 0.5; function onBodyLoaded() { bodyLoaded = true; @@ -38,6 +40,19 @@ function onBodyLoaded() { (function checkIsLoaded() { if(bodyLoaded) { document.getElementById('loading-font').style.cssText = "display: none;"; + volume = localStorage.getItem('volume') || 0.5; + volume = Number(volume); + audio.changeVolume(volume); + document.getElementById('volume-range').value = volume * 100; + isMuted = localStorage.getItem('ismuted') || false; + if(isMuted === "false") { isMuted = false; } + else if(isMuted === "true") { isMuted = true; } + audio.mute(isMuted); + if(isMuted) { + document.getElementById('mute-button').innerText = "🔇"; + } else { + document.getElementById('mute-button').innerText = "🔊"; + } } if(utageLoaded) { document.getElementById('loading-utage').style.cssText = "display: none;"; @@ -115,6 +130,35 @@ function hideUiClicked(event) { player.hideUiClicked(event); } +function dialogScrollUp(event) { + event.preventDefault(); + event.stopPropagation(); + textFunc.scrollTextUp(); +} + +function dialogScrollDown(event) { + event.preventDefault(); + event.stopPropagation(); + textFunc.scrollTextDown(); +} + +function toggleMute(event) { + isMuted = !isMuted; + audio.mute(isMuted); + localStorage.setItem('ismuted', isMuted); + if(isMuted) { + document.getElementById('mute-button').innerText = "🔇"; + } else { + document.getElementById('mute-button').innerText = "🔊"; + } +} + +function onVolumeChange(event) { + let vol = event.currentTarget.value / 100; + audio.changeVolume(vol); + localStorage.setItem('volume', vol); +} + function onWindowResize(event) { if(screenSizeTimeout) { clearTimeout(screenSizeTimeout); diff --git a/Js/Player.js b/Js/Player.js index 96c29b8..55e5b0c 100644 --- a/Js/Player.js +++ b/Js/Player.js @@ -32,6 +32,7 @@ class Player { this.center = {x: ((baseDimensions.width / 2) * this.resolutionScale), y: ((baseDimensions.height / 2) * this.resolutionScale) }; this.assetLoadPercent = 0; this.audioLoadPercent = 0; + this.playingVoice = undefined; } playFile() { @@ -162,8 +163,6 @@ class Player { //center the position of the container then offset it by the value in the layer info let x = (((baseDimensions.width / 2) + Number(l.X)) * this.resolutionScale); let y = (((baseDimensions.height / 2) - Number(l.Y)) * this.resolutionScale); - //let x = (Number(l.X) * this.resolutionScale); - //let y = (Number(l.Y) * this.resolutionScale); cont.position.set(x, y); cont.visible = false; } @@ -249,8 +248,7 @@ class Player { //Loop through the lerp targets, modify the needed objects. If a object is at its 1 time state remove it from the list. let toRemove = []; for(let i = 0; i < this.lerpTargets.length; ++i) { - try - { + try { let l = this.lerpTargets[i]; l.curTime += deltaTime; if(l.curTime < 0) { continue; } @@ -264,17 +262,41 @@ class Player { continue; } } - let newValue = commonFunctions.lerp(l.initV, l.finalV, pos, inter); - let split = l.type.split("."); - switch(split.length) { - case 1: - l.object[split[0]] = newValue; + switch(l.type) { + case "shake": { + if(pos === 1) { + if(l.object instanceof HTMLElement) { + l.object.style = ""; + } else { + l.object.position.set(l.initV.x, l.initV.y); + } + } else { + let x = Math.floor(Math.random() * (l.finalV.x * (1-pos))); + let y = Math.floor(Math.random() * (l.finalV.y * (1-pos))); + if(l.object instanceof HTMLElement) { + l.object.style = `transform: translate(${x}px, ${y}px);`; + } else { + l.object.position.set(x, y); + } + } break; - case 2: - l.object[split[0]][split[1]] = newValue; + } + default: { + let newValue = commonFunctions.lerp(l.initV, l.finalV, pos, inter); + let split = l.type.split("."); + if(split[0] == 'scale') { debugger; } + switch(split.length) { + case 1: + l.object[split[0]] = newValue; + break; + case 2: + l.object[split[0]][split[1]] = newValue; + break; + default: + continue; + } break; - default: - continue; + } } } catch(error) { //If we got an exception during this it probably means the object doesnt exist anymore so just remove it. @@ -418,14 +440,26 @@ class Player { this.processTween(delta, cur); break; case "bgm": + if(!this.utage.soundInfo[cur.Arg1]) { + break; + } + this.audio.playSound(cur.Arg1, 'bgm'); break; case "stopbgm": + this.audio.stopSound('bgm'); break; case "se": + if(!this.utage.soundInfo[cur.Arg1]) { + break; + } + this.audio.playSound(cur.Arg1, 'se'); break; - case "shake": + case "shake": { + this.processShake(delta, cur); break; + } case "henshin01_bgmoff": + this.audio.stopSound('bgm'); this.checkPutCharacterScreen(cur, true); break; default: @@ -500,8 +534,11 @@ class Player { lay.container.visible = true; } } - + checkPutText(cur) { + if(this.playingVoice) { + this.audio.stopSound(this.playingVoice); + } if(!cur.Command && cur.Arg1 && cur.Text) { //If its chracter off screen text var text = cur.English ? (utage.currentTranslation[cur.English] || cur.Text) : cur.Text; @@ -541,6 +578,10 @@ class Player { this.text.dialogText(true, commonFunctions.convertUtageTextTags(text)); this.manualNext = true; } + if(cur.Voice) { + this.playingVoice = cur.Voice; + this.audio.playSound(cur.Voice); + } } processTween(delta, cur) { @@ -587,24 +628,43 @@ class Player { } case "punchposition": { let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3); - if(!props.time) { props.time = 0.5; } + if(!props.time) { props.time = 500; } if(!cur.Arg6 || cur.Arg6 !== "NoWait") { this.waitTime = props.time + (props.delay || 0); } if(props.x) { this.lerpTargets.push({type: 'position.x', object: curChar.sprite, curTime: 0 - (props.delay || 0), time: props.time, - finalV: curChar.sprite.position.x + props.x, initV: curChar.sprite.position.x, inter: 'fullwait' }); + finalV: curChar.sprite.position.x + props.x, initV: curChar.sprite.position.x, inter: 'dampsin' }); } if(props.y) { this.lerpTargets.push({type: 'position.y', object: curChar.sprite, curTime: 0 - (props.delay || 0), time: props.time, - finalV: curChar.sprite.position.y + props.y, initV: curChar.sprite.position.y, inter: 'fullwait' }); + finalV: curChar.sprite.position.y + props.y, initV: curChar.sprite.position.y, inter: 'dampsin' }); } break; } + case "scaleto": { + let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3, false); + if(!props.time) { props.time = 500; } + //cuz I don't care about their values that make no sense when everything else uses time. + if(props.speed) { props.time = props.speed * 1000; } + if(!cur.Arg6 || cur.Arg6 !== "NoWait") { + this.waitTime = props.time + (props.delay || 0); + } + if(props.x) { + this.lerpTargets.push({type: 'scale.x', object: curChar.sprite, curTime: 0 - (props.delay || 0), time: props.time, + finalV: curChar.sprite.scale.x * props.x, initV: curChar.sprite.scale.x }); + } + if(props.y) { + this.lerpTargets.push({type: 'scale.y', object: curChar.sprite, curTime: 0 - (props.delay || 0), time: props.time, + finalV: curChar.sprite.scale.y * props.y, initV: curChar.sprite.scale.y }); + } + } case "colorto": { let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3); if(props.alpha) { if(props.time) { + this.lerpTargets.push({type: 'alpha', object: curChar.sprite, curTime: 0 - (props.delay || 0), time: props.time, + finalV: props.alpha, initV: curChar.sprite.alpha }); } else { curChar.sprite.alpha = 0; } @@ -612,6 +672,37 @@ class Player { } } } + + processShake(delta, cur) { + let obj = cur.Arg1; + switch(obj.toLowerCase()) { + case "camera": { + let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3); + if(!props.time) { props.time = 1000; } + if(!cur.Arg6 || cur.Arg6 !== "NoWait") { + this.waitTime = props.time + (props.delay || 0); + } + if(!props.x) { props.x = 30; } + if(!props.y) { props.y = 30; } + let stage = this.pixi.app.stage.position; + this.lerpTargets.push({type: 'shake', object: this.pixi.app.stage, curTime: 0 - (props.delay || 0), time: props.time, + finalV: {x: props.x + stage.x, y: props.y + stage.y}, initV: {x: stage.x, y: stage.y} }); + break; + } + case "messagewindow": { + let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3); + if(!props.time) { props.time = 1000; } + if(!cur.Arg6 || cur.Arg6 !== "NoWait") { + this.waitTime = props.time + (props.delay || 0); + } + if(!props.x) { props.x = 30; } + if(!props.y) { props.y = 30; } + this.lerpTargets.push({type: 'shake', object: document.getElementById('dialog-box'), curTime: 0 - (props.delay || 0), time: props.time, + finalV: {x: props.x, y: props.y}, initV: {x: 0, y: 0} }); + break; + } + } + } processEndCommand(delta) { let cur = this.currentCommand; @@ -680,9 +771,6 @@ class Player { } updateResolution(res) { - //this.resolutionScale = res.height / baseDimensions.height; - //this.center = {x: ((baseDimensions.width / 2) * this.resolutionScale), y: ((baseDimensions.height / 2) * this.resolutionScale) }; - //this.pixi.app.renderer.resolution = res.height / baseDimensions.height; let newScale = res.height / baseDimensions.height; this.pixi.app.stage.scale.set(newScale, newScale); this.pixi.app.renderer.resize(res.width, res.height); @@ -714,7 +802,9 @@ class Player { this.hasMoreText = false; this.audioLoadPercent = 0; this.assetLoadPercent = 0; + this.playingVoice = undefined; this.text.resetAll(); + this.audio.resetAll(); resolve(); } catch (error) { reject(error); diff --git a/Js/TextFunctions.js b/Js/TextFunctions.js index 60cfa5a..36f5a87 100644 --- a/Js/TextFunctions.js +++ b/Js/TextFunctions.js @@ -8,6 +8,8 @@ class TextFunctions { this.dialogBox = undefined; this.character = undefined; this.dialog = undefined; + this.scrollControls = undefined; + this.nextIndicator = undefined; this.dialogToDisplay = {timeout: undefined, fullText: "", text: "", curPos: 0}; this.textScrollSpeedMs = 40; this.scrollingText = false; @@ -22,34 +24,38 @@ class TextFunctions { this.character = document.getElementById('character'); this.dialog = document.getElementById('dialog'); this.dialogInner = document.getElementById('dialog-inner'); + this.scrollControls = document.getElementById('dialog-scroll'); + this.nextIndicator = document.getElementById('dialog-next'); } titleText(show, text) { if(text != undefined) { this.title.innerHTML = text; } - this.title.style = show ? "opacity: 1;" : "opacity: 0;"; + this.title.classList.toggle('hidden', !show); } divaText(show, text) { if(text != undefined) { this.diva.innerHTML = text; } - this.diva.style = show ? "opacity: 1;" : "opacity: 0;"; + this.diva.classList.toggle('hidden', !show); } characterName(show, text) { if(text != undefined) { this.character.innerHTML = text; } - this.mainUi.style = show ? "opacity: 1;" : "opacity: 0;"; - this.character.style = show ? "opacity: 1;" : "opacity: 0;"; + this.mainUi.classList.toggle('hidden', !show); + this.character.classList.toggle('hidden', !show); } dialogText(show, text) { if(this.lineHeight == -1) { this.lineHeight = Number(window.getComputedStyle(this.dialog, null).getPropertyValue("line-height").replace('px', '')); } + this.showNextIndicator(false); + this.showScrollControls(false); if(text != undefined) { if(this.dialogToDisplay.timeout) { clearTimeout(this.dialogToDisplay.timeout); @@ -69,8 +75,8 @@ class TextFunctions { this.dialogToDisplay.timeout = setTimeout(putText.bind(this), this.textScrollSpeedMs); } } - this.mainUi.style = show ? "opacity: 1;" : "opacity: 0;"; - this.dialogBox.style = show ? "opacity: 1;" : "opacity: 0;"; + this.mainUi.classList.toggle('hidden', !show); + this.dialogBox.classList.toggle('hidden', !show); //This is based off https://github.com/mattboldt/typed.js/ function putText() { @@ -78,6 +84,7 @@ class TextFunctions { this.dialogToDisplay.curPos = this.typeHtmlChars(this.dialogToDisplay.text, this.dialogToDisplay.curPos); let substr = this.dialogToDisplay.text.substr(this.dialogToDisplay.curPos); if (this.dialogToDisplay.curPos === this.dialogToDisplay.text.length) { + this.showNextIndicator(true); this.scrollingText = false; return; } else { @@ -85,8 +92,10 @@ class TextFunctions { const nextString = this.dialogToDisplay.text.substr(0, this.dialogToDisplay.curPos); this.dialogInner.innerHTML = nextString; let lHeight = this.lineHeight * 2 - if(this.dialogInner.offsetHeight > lHeight) { + //the +5 is just to give a bit of tolerance + if(this.dialogInner.offsetHeight > lHeight + 5) { this.dialog.scrollTop = this.dialogInner.offsetHeight - lHeight; + this.showScrollControls(true); } } @@ -100,13 +109,15 @@ class TextFunctions { this.dialogToDisplay.timeout = undefined; } this.dialogInner.innerHTML = this.dialogToDisplay.fullText; - let lHeight = this.lineHeight * 2 - if(this.dialogInner.offsetHeight > lHeight) { + let lHeight = this.lineHeight * 2; + if(this.dialogInner.offsetHeight > lHeight + 5) { this.dialog.scrollTop = this.dialogInner.offsetHeight - lHeight; + this.showScrollControls(true); } + this.showNextIndicator(true); this.scrollingText = false; } - + typeHtmlChars(curString, curStrPos) { const curChar = curString.substr(curStrPos).charAt(0); if (curChar === '<' || curChar === '&') { @@ -125,10 +136,36 @@ class TextFunctions { return curStrPos; } + showScrollControls(show) { + this.scrollControls.classList.toggle('hidden', !show); + } + + scrollTextUp() { + let lHeight = this.lineHeight * 2; + let val = this.dialog.scrollTop - lHeight; + if(val < 0) { + val = 0; + } + this.dialog.scrollTop = val; + } + + scrollTextDown() { + let lHeight = this.lineHeight * 2; + let val = this.dialog.scrollTop + lHeight; + if(val > this.dialogInner.offsetHeight - lHeight) { + val = this.dialogInner.offsetHeight - lHeight; + } + this.dialog.scrollTop = val; + } + + showNextIndicator(show) { + this.nextIndicator.classList.toggle('hidden', !show); + } + hideUi(show) { - this.mainUi.style = show ? "opacity: 1;" : "opacity: 0;"; - this.dialogBox.style = show ? "opacity: 1;" : "opacity: 0;"; - this.character.style = show ? "opacity: 1;" : "opacity: 0;"; + this.mainUi.classList.toggle('hidden', !show); + this.dialogBox.classList.toggle('hidden', !show); + this.character.classList.toggle('hidden', !show); } resetAll() { @@ -136,10 +173,12 @@ class TextFunctions { this.diva.innerHTML = ''; this.character.innerHTML = ''; this.dialogInner.innerHTML = ''; - this.title.style = "opacity: 0;"; - this.diva.style = "opacity: 0;"; - this.mainUi.style = "opacity: 0;"; - this.character.style = "opacity: 0;"; - this.dialogBox.style = "opacity: 0;"; + this.title.classList.add('hidden'); + this.diva.classList.add('hidden'); + this.mainUi.classList.add('hidden'); + this.character.classList.add('hidden'); + this.dialogBox.classList.add('hidden'); + this.scrollControls.classList.add('hidden'); + this.nextIndicator.classList.add('hidden'); } } \ No newline at end of file diff --git a/Js/UtageParse.js b/Js/UtageParse.js index 96d2a51..9261bee 100644 --- a/Js/UtageParse.js +++ b/Js/UtageParse.js @@ -14,6 +14,7 @@ class UtageInfo { this.soundInfo = {}; this.textureInfo = {}; this.currentTranslation = {}; + this.bgmLoopData = {}; } loadUtageSettings(resolve, reject) { @@ -26,7 +27,8 @@ class UtageInfo { commonFunctions.getFileText(`${this.rootDirectory}XDUData/Utage/Diva/Settings/Param.tsv`), //commonFunctions.getFileText(`${this.rootDirectory}XDUData/Utage/Diva/Settings/Scenario.tsv`), commonFunctions.getFileText(`${this.rootDirectory}XDUData/Utage/Diva/Settings/Sound.tsv`), - commonFunctions.getFileText(`${this.rootDirectory}XDUData/Utage/Diva/Settings/Texture.tsv`) + commonFunctions.getFileText(`${this.rootDirectory}XDUData/Utage/Diva/Settings/Texture.tsv`), + commonFunctions.getFileJson(`${this.rootDirectory}Js/bgmLoop.json`), ]; Promise.all(promises) .then((success) => { @@ -41,6 +43,7 @@ class UtageInfo { this.parseParamInfo(success[4]); this.parseSoundInfo(success[5]); this.parseTextureInfo(success[6]); + this.bgmLoopData = success[7]; resolve(); }, (failure) => { reject(failure); @@ -186,6 +189,7 @@ class UtageInfo { let read = commonFunctions.readLine(line, headers); if(read && read.Label) { if(read.FileName && read.Type) { + read.origFileName = read.FileName; if(!read.FileName.includes('.')) { read.FileName = `${read.FileName}.opus`; } diff --git a/Player.html b/Player.html index f7e7212..e36c672 100644 --- a/Player.html +++ b/Player.html @@ -7,6 +7,7 @@ + @@ -20,23 +21,35 @@
-
🔊
+
+ 🔊 + +
- -
Title Text
-
Diva Text
-
+ + + +