diff --git a/Css/main.css b/Css/main.css index 545f7ba..f1f3c79 100644 --- a/Css/main.css +++ b/Css/main.css @@ -64,9 +64,9 @@ #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; } +#text-container #title { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 20px; transition: opacity 0.3s; cursor: default; user-select: none; } -#text-container #diva { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 34px; transition: opacity 0.3s; } +#text-container #diva { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; font-size: 34px; transition: opacity 0.3s; cursor: default; user-select: none; } #text-container #dialog-box { box-sizing: border-box; position: absolute; bottom: 0; text-align: left; width: 100%; height: 200px; } @@ -74,11 +74,11 @@ #dialog-box { color: white; font-weight: bold; text-shadow: 1px 1px 6px black; transition: opacity 0.1s; } -#dialog-box #character { position: absolute; top: -5px; left: 70px; font-size: 30px; } +#dialog-box #character { position: absolute; top: -5px; left: 70px; font-size: 30px; cursor: default; user-select: none; } #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 #dialog-inner { max-width: 1125px; cursor: default; user-select: none; } #dialog b { font-weight: bold; } diff --git a/Images/newui_main.png b/Images/newui_main.png index 7e25dc6..c1a3a87 100644 Binary files a/Images/newui_main.png and b/Images/newui_main.png differ diff --git a/Js/Common.js b/Js/Common.js index 36cf733..c8da25a 100644 --- a/Js/Common.js +++ b/Js/Common.js @@ -92,14 +92,24 @@ class commonFunctions { t = -0.45; } break; + case "punch": { + if (t === 0 || t === 1) + return start; + debugger; + let change = end - start; + let num = 0.3; + let rad = Math.PI * 2; + let num2 = num / rad * Math.asin(0); + return change * Math.pow(2, -10 * t) * Math.sin((t * 1 - num2) * rad / num); + } //http://www.gizma.com/easing/ - case "quadinout": - var change = end - start; + case "quadinout": { + let change = end - start; t = t * 2; if (t < 1) { return change/2*t*t + start; } t--; return -change/2 * (t*(t-2) - 1) + start; - break; + } } return (1 - t) * start + t * end; //-(2*x-1)^4 +1 @@ -118,10 +128,9 @@ class commonFunctions { static hexToRgb (hex) { hex = hex.toString(16); - let bigint = parseInt(hex, 16); - let r = (bigint >> 16) & 255; - let g = (bigint >> 8) & 255; - let b = bigint & 255; + let r = (hex >> 16) & 255; + let g = (hex >> 8) & 255; + let b = hex & 255; return [r, g, b]; } diff --git a/Js/Main.js b/Js/Main.js index 5f99c03..2f16073 100644 --- a/Js/Main.js +++ b/Js/Main.js @@ -7,9 +7,8 @@ const pixiApp = { const utage = new UtageInfo(); const textFunc = new TextFunctions(); -const audio = new audioController(utage); +let audio = undefined; //Cant create a audio context without user input. const player = new Player(pixiApp, utage, textFunc, audio); -const context = new (window.AudioContext || window.webkitAudioContext)(); const languages = ["eng", "jpn"]; let bodyLoaded = false; let utageLoaded = false; @@ -72,12 +71,14 @@ function loadLocalStorage() { //audio 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(audio) { + audio.changeVolume(volume); + audio.mute(isMuted); + } if(isMuted) { document.getElementById('mute-button').innerText = "🔇"; } else { @@ -160,29 +161,39 @@ function closeMissionModal(event, wasStarted) { } function missionChanged(value) { - let newMission = utage.availableMissions[value]; - currentMission = newMission; - let promises = [ - utage.parseMissionFile(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', '_t.tsv')}`), - utage.loadMissionTranslation(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', `_translations_${selectedLang}.json`)}`, selectedLang), - player.resetAll() - ]; - closeMissionModal(undefined, true); - - Promise.all(promises) + if(!audio) { + audio = new audioController(utage); + audio.changeVolume(volume); + audio.mute(isMuted); + player.audio = audio; + } + player.resetAll() .then((success) => { - let res = player.playFile() + let newMission = utage.availableMissions[value]; + currentMission = newMission; + let promises = [ + utage.parseMissionFile(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', '_t.tsv')}`), + utage.loadMissionTranslation(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '').replace('.tsv', `_translations_${selectedLang}.json`)}`, selectedLang) + ]; + closeMissionModal(undefined, true); + + Promise.all(promises) .then((success) => { - player.resetAll(); - currentMission = undefined; - debugger; + let res = player.playFile() + .then((success) => { + player.resetAll(); + currentMission = undefined; + debugger; + }, (failure) => { + debugger; + currentMission = undefined; + console.log(failure); + }); }, (failure) => { - debugger; currentMission = undefined; console.log(failure); }); }, (failure) => { - currentMission = undefined; console.log(failure); }); } @@ -215,7 +226,9 @@ function dialogScrollDown(event) { function toggleMute(event) { isMuted = !isMuted; - audio.mute(isMuted); + if(audio) { + audio.mute(isMuted); + } localStorage.setItem('ismuted', isMuted); if(isMuted) { document.getElementById('mute-button').innerText = "🔇"; @@ -225,9 +238,11 @@ function toggleMute(event) { } function onVolumeChange(event) { - let vol = event.currentTarget.value / 100; - audio.changeVolume(vol); - localStorage.setItem('volume', vol); + volume = Number(event.currentTarget.value) / 100; + if(audio) { + audio.changeVolume(volume); + } + localStorage.setItem('volume', volume); } function onWindowResize(event) { diff --git a/Js/Player.js b/Js/Player.js index 64dbd9e..cf1ebbd 100644 --- a/Js/Player.js +++ b/Js/Player.js @@ -17,7 +17,6 @@ class Player { this.titleWaitTime = 5; this.currentCharacters = {}; - this.lastCharOffLayer = undefined; this.layers = {}; this.sprites = {}; this.currentCommand = undefined; @@ -134,6 +133,8 @@ class Player { }); //Manually load white bg for fading. Can be tinted to change color. this.loader.add('bg|whiteFade', `${this.utage.rootDirectory}Images/white.png`); + //this isint in the texture file. + this.loader.add('bg|titlecard', `${this.utage.rootDirectory}XDUData/Sample/Texture/BG/bg_title.jpg`) this.loader .on("progress", (loader, resource) => { this.onPixiProgress(loader, resource); @@ -183,6 +184,7 @@ class Player { } } + //https://jsfiddle.net/60e5pp8d/1/ buildShaders() { let divalefttorightfade = new PIXI.Filter(null, leftToRightFadeShader, { time: { type: 'f', value: 0 }, @@ -190,13 +192,22 @@ class Player { fadeincolor: { type: 'v4', value: [0.0,0.0,0.0,1.0] }, fadeoutcolor: { type: 'v4', value: [0.0,0.0,0.0,0.0] } }); - divalefttorightfade.apply = function(filterManager, input, output) - { + divalefttorightfade.apply = baseShaderApply; + this.shaders['divalefttorightfade'] = divalefttorightfade; + let divarighttoleftfade = new PIXI.Filter(null, leftToRightFadeShader, { + time: { type: 'f', value: 0 }, + dimensions: { type: 'v2', value: [baseDimensions.width, baseDimensions.height] }, + fadeincolor: { type: 'v4', value: [0.0,0.0,0.0,1.0] }, + fadeoutcolor: { type: 'v4', value: [0.0,0.0,0.0,0.0] } + }); + divarighttoleftfade.apply = baseShaderApply; + this.shaders['divarighttoleftfade'] = divarighttoleftfade; + + function baseShaderApply(filterManager, input, output) { this.uniforms.dimensions[0] = input.sourceFrame.width this.uniforms.dimensions[1] = input.sourceFrame.height filterManager.applyFilter(this, input, output); } - this.shaders['divalefttorightfade'] = divalefttorightfade; } //Laoding progress functions @@ -280,15 +291,17 @@ class Player { if(pos >= 1) { pos = 1; toRemove.push(i); - var split = l.post.split('|'); - switch(split[0].toLowerCase()) { - case "destroy": - l.object.destroy(); - continue; - case "clearshader": - l.object.filters = null; - l.object.alpha = Number(split[1]); - break; + if(l.post) { + var split = l.post.split('|'); + switch(split[0].toLowerCase()) { + case "destroy": + l.object.destroy(); + continue; + case "clearshader": + l.object.filters = null; + l.object.alpha = Number(split[1]); + break; + } } } switch(l.type) { @@ -358,6 +371,17 @@ class Player { switch((cur.Command || "").toLowerCase()) { case "scenetitle01": { this.waitTime = this.titleWaitTime * 1000; + try { + let container = this.layers[this.bgLayerName].container; + let sprite = new PIXI.Sprite(this.loader.resources[`bg|titlecard`].texture); + container.visible = true; + sprite.scale.set(1.30273438, 1.30273438); + sprite.anchor.set(0.5, 0.5); + sprite.alpha = 0; + container.addChild(sprite); + this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: 300, finalV: 1, initV: 0}); + this.lerpTargets.push({type: 'alpha', object: sprite, curTime: -(this.waitTime+500), time: 300, finalV: 0, initV: 1, post: "destroy"}); + } catch (error) { } let text = cur.English ? (utage.currentTranslation[cur.English] || cur.Text) : cur.Text; this.text.titleText(true, text); break; @@ -383,41 +407,26 @@ class Player { this.lerpTargets.push({type: 'alpha', object: this.layers["bg|whiteFade"].sprite, curTime: 0, time: this.waitTime, finalV: 0, initV: 1}); break; case "divalefttorightblackfade": { - //This has a color but ive always seen it be black and its called black so im just assuming for now. - this.waitTime = Number(cur.Arg6) * 1000; - let sprite = this.layers["bg|whiteFade"].sprite; - let filter = this.shaders['divalefttorightfade']; - var color = commonFunctions.getColorFromName(cur.Arg1); - let rgbcolor = commonFunctions.hexToRgb(color); - sprite.tint = color; - sprite.alpha = 1.0; - filter.uniforms.time = 0.0; - filter.uniforms.fadeincolor = [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0]; - filter.uniforms.fadeoutcolor = [0.0,0.0,0.0,0.0]; - sprite.filters = [ filter ]; - this.lerpTargets.push({type: 'shader', object: sprite, curTime: 0, time: this.waitTime, post: 'clearshader|1'}); + this.processDivaFade(cur, false, false); break; } case "divalefttorightclearfade": { - this.waitTime = Number(cur.Arg6) * 1000; - let sprite = this.layers["bg|whiteFade"].sprite - let filter = this.shaders['divalefttorightfade']; - var color = commonFunctions.getColorFromName(cur.Arg1); - let rgbcolor = commonFunctions.hexToRgb(color); - sprite.tint = color; - sprite.alpha = 1.0; - filter.uniforms.time = 0.0; - filter.uniforms.fadeincolor = [0.0,0.0,0.0,0.0]; - filter.uniforms.fadeoutcolor = [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0]; - sprite.filters = [ filter ]; - this.lerpTargets.push({type: 'shader', object: sprite, curTime: 0, time: this.waitTime, post: 'clearshader|0'}); + this.processDivaFade(cur, true, false); + break; + } + case "divarighttoleftblackfade": { + this.processDivaFade(cur, false, true); + break; + } + case "divarighttoleftclearfade": { + this.processDivaFade(cur, true, true); break; } case "bg": { let bgInfo = this.utage.textureInfo[cur.Arg1]; let container = this.layers[this.bgLayerName].container; //If we have a fadetime we need to keep the old bg, fade its alpha out, then destroy it. - if(cur.Arg6) { + if(cur.Arg6 && container.children[0]) { //I know im assuming a lot that there is already only one bg on the layer. this.lerpTargets.push({type: 'alpha', object: container.children[0], curTime: 0, time: (Number(cur.Arg6) * 1000), finalV: 0, initV: 1, post: "destroy"}); } else { @@ -496,8 +505,7 @@ class Player { let curChar = this.currentCharacters[c]; if(curChar.charName === cur.Arg1) { let time = Number(cur.Arg6) * 1000; - if(!time) { time = 100; } - this.lastCharOffLayer = this.currentCharacters[c].layer; + if(!time) { time = 250; } this.lerpTargets.push({type: 'alpha', object: curChar.sprite, curTime: 0, time: time, finalV: 0, initV: 1, post: "destroy" }); this.currentCharacters[c] = undefined; break; @@ -508,6 +516,7 @@ class Player { this.processTween(delta, cur); break; case "bgm": + this.audio.stopSound('bgm'); if(!this.utage.soundInfo[cur.Arg1]) { break; } @@ -540,6 +549,21 @@ class Player { } } + processDivaFade(command, clear, rtl) { + this.waitTime = Number(command.Arg6) * 1000; + let sprite = this.layers["bg|whiteFade"].sprite; + let filter = this.shaders[(rtl ? 'divarighttoleftblackfade' : 'divalefttorightfade')]; + var color = commonFunctions.getColorFromName(command.Arg1); + let rgbcolor = commonFunctions.hexToRgb(color); + sprite.tint = color; + sprite.alpha = 1.0; + filter.uniforms.time = 0.0; + filter.uniforms.fadeincolor = (clear ? [0.0,0.0,0.0,0.0] : [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0]); + filter.uniforms.fadeoutcolor = (clear ? [rgbcolor[0],rgbcolor[1],rgbcolor[2],1.0] : [0.0,0.0,0.0,0.0]); + sprite.filters = [filter]; + this.lerpTargets.push({type: 'shader', object: sprite, curTime: 0, time: this.waitTime, post: `clearshader|${(clear ? '0' : '1')}`}); + } + //This should mostly be handling things like text processCommandOther(delta) { let cur = this.currentCommand; @@ -553,7 +577,8 @@ class Player { checkPutCharacterScreen(cur, special = false) { if((!cur.Command || special) && cur.Arg1 && this.utage.characterInfo[cur.Arg1]) { let lay = undefined; - let curChar = undefined; + let curChar = undefined; //The character that is currently on screen with the same name as Arg1. + let prevChar = undefined; //The character that is already on the layer we are trying to put the new char on. //First check if the character is already on screen for(let c of Object.keys(this.currentCharacters)) { if(!this.currentCharacters[c]) { continue; } @@ -574,23 +599,36 @@ class Player { } let chr = this.utage.characterInfo[cur.Arg1][cur.Arg2]; //If the script gives us a layer get that layer and if there is a character on it already. - if(cur.Arg3 && !curChar) { + if(cur.Arg3) { lay = this.layers[cur.Arg3]; - curChar = this.currentCharacters[cur.Arg3]; + prevChar = this.currentCharacters[cur.Arg3]; if(!lay) { return; } - //If they didn't give us a layer try to use the last layer a character was removed from. - } else if(!curChar) { - lay = this.lastCharOffLayer; + //If they didn't give us a layer check for left and right positioning or try to go to default (middle) + } else if(!curChar && !lay) { + if(isCharOnLeft.apply(this)) { + lay = this.layers['キャラ右']; + } else if(isCharOnRight.apply(this)) { + lay = this.layers['キャラ左']; + } else { + lay = this.layers['キャラ中央']; + } if(!lay) { return; } cur.Arg3 = lay.info.LayerName; + prevChar = this.currentCharacters[cur.Arg3]; } - //If this chracter is already here and not changing patterns don't change anything. - if(curChar && curChar.charName === cur.Arg1 && curChar.character.Pattern === cur.Arg2) { + //If the character is already on screen on another layer move them to the new layer. + if(curChar && lay && curChar.layer.info.LayerName !== cur.Arg3) { + this.lerpTargets.push({type: 'alpha', object: curChar.sprite, curTime: 0, time: 200, finalV: 0, initV: 1, post: "destroy" }); + this.currentCharacters[curChar.layer.info.LayerName] = undefined; + } + //If this character is already here and not changing patterns don't change anything. + else if(curChar && curChar.charName === cur.Arg1 && curChar.character.Pattern === cur.Arg2) { return; } + //If the layer already has a different character on it remove it. - if(curChar && (curChar.character.NameText !== chr.NameText || curChar.character.Pattern !== chr.Pattern)) { - this.lerpTargets.push({type: 'alpha', object: curChar.sprite, curTime: 0, time: 200, finalV: 0, initV: 1, post: "destroy" }); + if(prevChar && (prevChar.character.NameText !== chr.NameText || prevChar.character.Pattern !== chr.Pattern)) { + this.lerpTargets.push({type: 'alpha', object: prevChar.sprite, curTime: 0, time: 200, finalV: 0, initV: 1, post: "destroy" }); this.currentCharacters[cur.Arg3] = undefined; } let sprite = new PIXI.Sprite(this.loader.resources[`char|${cur.Arg1}|${cur.Arg2}`].texture); @@ -599,6 +637,11 @@ class Player { sprite.anchor.set(anchor.x, anchor.y); sprite.alpha = 0; let fadeTime = 200; + //If the character is already on screen put te new sprite in the same position as the old one. + if(curChar) { + sprite.position.x = curChar.sprite.position.x; + sprite.position.y = curChar.sprite.position.y; + } if(cur.Arg4) { sprite.position.x = Number(cur.Arg4); } @@ -606,14 +649,44 @@ class Player { sprite.position.y = Number(cur.Arg5); } if(cur.Arg6) { - //Im halving this because their fades take too fucking long and look bad. + //Im halving this because their fades take too fucking long and looks bad. fadeTime = (Number(cur.Arg6) * 1000) / 2; } this.currentCharacters[cur.Arg3] = { layer: lay, character: chr, charName: cur.Arg1, sprite: sprite }; - this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: fadeTime, finalV: 1, initV: 0 }); + if(fadeTime > 0) { + this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: fadeTime, finalV: 1, initV: 0 }); + } else { + sprite.alpha = 1; + } lay.container.addChild(sprite); lay.container.visible = true; } + + function isCharOnLeft() { + for(let l of Object.keys(this.layers)) { + let lay = this.layers[l].info; + if(!lay) { continue; } + if(lay.LayerName.includes('キャラ左')) { + if(this.currentCharacters[lay.LayerName]) { + return true; + } + } + } + return false; + } + + function isCharOnRight() { + for(let l of Object.keys(this.layers)) { + let lay = this.layers[l].info; + if(!lay) { continue; } + if(lay.LayerName.includes('キャラ右')) { + if(this.currentCharacters[lay.LayerName]) { + return true; + } + } + } + return false; + } } //Checks if the current command is trying to put text on the screen. @@ -715,18 +788,16 @@ class Player { case "punchposition": { let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3); if(props.time == undefined) { props.time = 1000; } - //just watching these in game they definitely don't take as long as is advertised so i'm shortening it a bit. - props.time = props.time * 0.5; if(!cur.Arg6 || cur.Arg6 !== "NoWait") { this.waitTime = props.time + (props.delay || 0); } if(props.x != undefined) { 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: 'dampsin' }); + finalV: curChar.sprite.position.x + props.x, initV: curChar.sprite.position.x, inter: 'punch' }); } if(props.y != undefined) { 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: 'dampsin' }); + finalV: curChar.sprite.position.y + props.y, initV: curChar.sprite.position.y, inter: 'punch' }); } break; } @@ -899,9 +970,9 @@ class Player { PIXI.utils.TextureCache[tex].destroy(true); } } + utage.currentPlayingFile.length = 0; this.loader.reset(); this.currentCharacters = {}; - this.lastCharOffLayer = undefined; this.layers = {}; this.sprites = {}; this.currentCommand = undefined; diff --git a/Js/Shaders.js b/Js/Shaders.js index 362ec88..bcec0d7 100644 --- a/Js/Shaders.js +++ b/Js/Shaders.js @@ -1,3 +1,4 @@ +//http://glslsandbox.com/e#39992.0 const leftToRightFadeShader = ` precision mediump float; varying vec2 vTextureCoord; @@ -28,4 +29,33 @@ void main( void ) { gl_FragColor = color; }` -//http://glslsandbox.com/e#39992.0 \ No newline at end of file +const rightToLeftFadeShader = ` +precision mediump float; +varying vec2 vTextureCoord; +uniform vec2 dimensions; +uniform vec4 filterArea; + +uniform float time; +uniform vec4 fadeincolor; +uniform vec4 fadeoutcolor; + +vec2 mapCoord( vec2 coord ) { + coord *= filterArea.xy; + return coord; +} + +void main( void ) { + vec2 uv = vTextureCoord; + vec2 mappedCoord = mapCoord(uv) / dimensions; + + float step2 = (1.0 - time); + float step3 = (1.0 - time) - 0.2; + step3 = clamp(step3, 0.0, 1.0); + float step4 = -0.0001; + + vec4 color = fadeincolor; + color = mix(color, fadeoutcolor, smoothstep(step2, step3, mappedCoord.x)); + color = mix(color, fadeoutcolor, smoothstep(step3, step4, mappedCoord.x)); + + gl_FragColor = color; +}`