Resizing.

Work on text stuff.
Work on tweens.
Beginning audio support.
This commit is contained in:
firebingo 2018-04-15 18:35:01 -07:00
parent 00be56d0a8
commit a192a0eb0e
10 changed files with 799 additions and 173 deletions

99
Js/Audio.js Normal file
View file

@ -0,0 +1,99 @@
//(Math.exp(x)-1)/(Math.E-1)
//🔊
class bufferLoader {
constructor(context, soundMap, callback) {
this.context = context;
this.soundMap = soundMap;
this.onloadUpdate = callback;
this.bufferList = {};
this.loadCount = 0;
}
load() {
for (let s of this.soundMap) {
this.loadBuffer(s.FileName, s.Label);
}
}
loadBuffer(url, name) {
return new Promise((resolve, reject) => {
try
{
// Load buffer asynchronously
fetch(url)
.then((response) => {
if(response.status !== 200) {
if(this.onloadUpdate) {
this.onloadUpdate((++this.loadCount / this.soundMap.length) * 100);
}
reject(response); return;
}
response.arrayBuffer().then((buffer) => {
// Asynchronously decode the audio file data in request.response
this.context.decodeAudioData(buffer, (buf) => {
if (!buf) {
reject('error decoding file data: ' + url);
}
this.bufferList[name] = buf;
if(this.onloadUpdate) {
this.onloadUpdate((++this.loadCount / this.soundMap.length) * 100);
}
resolve(`${this.loadCount}|${this.soundMap.length}`);
},
function(error) {
console.log(error);
console.log(`url: ${url}, name: ${name}`);
if(this.onloadUpdate) {
this.onloadUpdate((++this.loadCount / this.soundMap.length) * 100);
}
reject(error);
}
);
});
}, (failure) => {
console.log(failure);
reject(failure);
});
} catch(error) {
console.log(error);
reject(error);
}
});
}
}
class audioController {
constructor() {
this.volume = 1.0;
this.muted = false;
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
this.gainNode = this.audioCtx.createGain();
this.loader = undefined;
}
changeVolume(vol) {
this.volume = (Math.exp(vol)-1)/(Math.E-1);
if(!this.muted) {
this.gainNode.gain.setValueAtTime(this.volume, this.audioCtx.currentTime);
}
}
mute() {
this.muted = !this.muted;
if(this.muted) {
this.gainNode.gain.setValueAtTime(0, athis.udioCtx.currentTime);
} else {
this.gainNode.gain.setValueAtTime(this.volume, this.audioCtx.currentTime);
}
}
loadSounds(soundMap, callback) {
this.loader = new bufferLoader(this.audioCtx, soundMap, (percent) => {
if (callback) {
callback(percent);
}
});
this.loader.load();
}
}

View file

@ -1,33 +1,46 @@
'use strict';
var rootUrl = `${window.location.protocol}//${window.location.host}/`;
let rootUrl = `${window.location.protocol}//${window.location.host}/`;
const screenRatio = 9/16;
class commonFunctions {
static getFileText(file) {
return new Promise((resolve, reject) => {
fetch(file)
.then((success) => {
success.text()
.then((text) => {
resolve(text);
try
{
fetch(file)
.then((success) => {
if(success.status !== 200) { reject(success); return; }
success.text()
.then((text) => {
resolve(text);
});
}, (failure) => {
reject(failure);
});
}, (failure) => {
reject(failure);
});
} catch(error) {
reject(error);
}
});
}
static getFileJson(file) {
return new Promise((resolve, reject) => {
fetch(file)
.then((success) => {
success.json()
.then((json) => {
resolve(json);
try
{
fetch(file)
.then((success) => {
if(success.status !== 200) { reject(success); return; }
success.json()
.then((json) => {
resolve(json);
});
}, (failure) => {
reject(failure);
});
}, (failure) => {
reject(failure);
});
} catch(error) {
reject(error);
}
});
}
@ -40,15 +53,41 @@ class commonFunctions {
let split = line.split('\t');
let newEntry = {};
for(let i = 0; i < split.length; ++i) {
let x = split[i];
let x = split[i].trim();
newEntry[headers[i]] = x;
}
return newEntry;
}
}
static lerp(start, end, t) {
static lerp(start, end, t, type = "linear") {
switch(type) {
default:
case "linear":
break;
case "sin":
t = t * (Math.PI / 2);
t = Math.sin(t);
break;
case "fullsin":
t = t * Math.PI;
t = Math.sin(t);
break;
case "fullwait":
t = -(Math.pow((2*t-1), 4)) + 1;
break;
case "square":
t = Math.pow(t, 2);
break;
case "exp":
t = Math.pow(t, 1/4);
break;
case "sqrt":
t = Math.sqrt(t);
break;
}
return (1 - t) * start + t * end;
//-(2*x-1)^4 +1
}
static getColorFromName(name) {
@ -64,10 +103,52 @@ class commonFunctions {
static convertUtageTextTags(text) {
text = text.replace(/<speed.*?>|<\/speed>/g, "");
text = text.replace("\\n", "<br/>")
text = text.replace(/\\n/g, "<br/>")
//rewrite ruby tags to normal html format
let rubyMatches = text.match(/<ruby=.*?<\/ruby>/g);
if(rubyMatches) {
for(let i = 0; i < rubyMatches.length; ++i) {
let m = rubyMatches[i];
let rText = '';
let innerText = '';
let startR = false;
let startI = false;
for(let j = 0; j < m.length; ++j) {
if(m[j] === '<' && j !== 0) { startI = false; }
if(startI) {
innerText+= m[j];
}
if(m[j] === '>') { startR = false; startI = true; }
if(startR) {
rText += m[j];
}
if(m[j] === '=') { startR = true; }
}
text = text.replace(m, `<ruby>${innerText}<rt>${rText}</rt></ruby>`);
}
}
return text;
}
static getNewResolution(baseRes, screenWidth, screenHeight, minusHeight) {
let retval = { width: 0, height: 0 };
if(screenWidth >= screenHeight) {
let newPer = (screenHeight - (minusHeight || 0)) / baseRes.height;
retval.height = baseRes.height * newPer;
retval.width = baseRes.width * newPer;
if(retval.width > screenWidth) {
newPer = screenWidth / baseRes.width;
retval.height = baseRes.height * newPer;
retval.width = baseRes.width * newPer;
}
} else if (screenHeight > screenWidth) {
let newPer = screenWidth / baseRes.width;
retval.height = baseRes.height * newPer;
retval.width = baseRes.width * newPer;
}
return retval;
}
static getAnchorFromCharPivot(pivot) {
let x = 0.5;
let y = 0.5;
@ -77,9 +158,60 @@ class commonFunctions {
x = Number(p.substring(2));
} else if(p.startsWith("y=")) {
y = Number(p.substring(2));
//The y pivot from utage is based from the bottom so it needs to be flipped
y = 1 - y;
}
}
return {x, y};
}
static getPropertiesFromTweenCommand(props) {
var retval = {};
let indexX = props.indexOf("x=");
if(indexX !== -1) {
retval.x = "";
for(let i = indexX + 2; i < props.length; ++i) {
if(props[i] == " ") { break; }
retval.x += props[i];
}
retval.x = Number(retval.x);
}
let indexY = props.indexOf("y=");
if(indexY !== -1) {
retval.y = "";
for(let i = indexY+ 2; i < props.length; ++i) {
if(props[i] == " ") { break; }
retval.y += props[i];
}
retval.y = -Number(retval.y);
}
let indexT = props.indexOf("time=");
if(indexT !== -1) {
retval.time = "";
for(let i = indexT + 5; i < props.length; ++i) {
if(props[i] == " ") { break; }
retval.time += props[i];
}
retval.time = Number(retval.time) * 1000;
}
let indexD = props.indexOf("delay=");
if(indexD !== -1) {
retval.delay = "";
for(let i = indexD + 6; i < props.length; ++i) {
if(props[i] == " ") { break; }
retval.delay += props[i];
}
retval.delay = Number(retval.delay) * 1000;
}
let indexA = props.indexOf("alpha=");
if(indexA !== -1) {
retval.alpha = "";
for(let i = indexA + 6; i < props.length; ++i) {
if(props[i] == " ") { break; }
retval.alpha += props[i];
}
retval.alpha = Number(retval.alpha);
}
return retval;
}
}

View file

@ -4,18 +4,26 @@ const pixiApp = {
app: new PIXI.Application(baseDimensions),
loader: PIXI.loader
};
const utage = new UtageInfo();
const textFunc = new TextFunctions();
const player = new Player(pixiApp, utage, textFunc);
const audio = new audioController();
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;
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;
function onBodyLoaded() {
bodyLoaded = true;
}
(function startLoad() {
var promises = [
let promises = [
utage.loadUtageSettings()
];
@ -47,10 +55,11 @@ function onAllLoaded(success) {
buildMissionSelectList();
let appContainer = document.getElementById('app-container');
appContainer.appendChild(pixiApp.app.view);
//appContainer.style.cssText = `width: ${baseDimensions.width}; height: ${baseDimensions.height};`;
setTimeout(() => {
document.getElementById('parent-container').style.cssText = "opacity: 1;";
});
onWindowResize();
window.addEventListener("resize", onWindowResize);
}, 0);
}
function buildMissionSelectList() {
@ -63,8 +72,11 @@ function buildMissionSelectList() {
opt.innerText = 'Select Mission';
} else {
let m = utage.missionsList[i];
//if(m.includes('MA1-') || m.includes('MA2-')|| m.includes('MA3-')) {
// continue;
//}
opt.setAttribute('value', m);
opt.innerText = m;
opt.innerText = m.replace('|', ' - ');
}
selectBox.appendChild(opt);
}
@ -74,14 +86,15 @@ function missionChanged(event) {
if(!event || !event.currentTarget || !event.currentTarget.value || event.currentTarget.value === '{Select}') { return; }
let newMission = utage.availableMissions[event.currentTarget.value.split('|')[0]];
var promises = [
utage.parseMissionFile(`${utage.rootDirectory}XDUData/${newMission.Path.replace('Asset/', '').replace('.utage', '')}`),
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`)}`),
player.resetAll()
];
Promise.all(promises)
.then((success) => {
var res = player.playFile()
let res = player.playFile()
.then((success) => {
player.resetAll();
debugger;
@ -94,8 +107,25 @@ function missionChanged(event) {
});
}
function onTextClicked(event) {
event.preventDefault();
event.stopPropagation();
function onMainClick(event) {
player.onMainClick(event);
}
function hideUiClicked(event) {
player.hideUiClicked(event);
}
function onWindowResize(event) {
if(screenSizeTimeout) {
clearTimeout(screenSizeTimeout);
screenSizeTimeout = undefined;
}
screenSizeTimeout = setTimeout(() => {
screenw = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
screenh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
let topContainerHeight = document.getElementById('other-controls-container').offsetHeight + 6;
let res = commonFunctions.getNewResolution(baseDimensions, screenw, screenh, topContainerHeight);
player.updateResolution(res);
document.getElementById('app-container').style.cssText = `width: ${res.width}px; height: ${res.height}px;`;
}, 400);
}

21
Js/Pixi.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -2,13 +2,20 @@
const baseDimensions = {width: 1334, height: 750};
class Player {
constructor(pixi, utage, text) {
constructor(pixi, utage, text, audio) {
this.pixi = pixi;
this.loader = pixi.loader;
this.utage = utage;
this.text = text;
this.audio = audio;
//consts
this.resolutionScale = 1;
this.baseFps = 60; //I am assuming that PIXI is going to stay as keeping 60fps = delta1.
this.bgLayerName = "背景";
this.defaultCharPattern = 'すまし';
this.backCharTint = 0x808080;
this.titleWaitTime = 1;
this.blackBackSp = undefined;
this.currentCharacters = {};
this.lastCharOffLayer = undefined;
@ -19,12 +26,12 @@ class Player {
this.secondTicker = 1000;
this.waitTime = 0;
this.lerpTargets = [];
this.bgLayerName = "背景";
this.defaultCharPattern = 'すまし';
this.titleWaitTime = 1;
this.manualNext = false;
this.hasMoreText = false;
this.uiHidden = false;
this.center = {x: ((baseDimensions.width / 2) * this.resolutionScale), y: ((baseDimensions.height / 2) * this.resolutionScale) };
this.assetLoadPercent = 0;
this.audioLoadPercent = 0;
}
playFile() {
@ -43,6 +50,8 @@ class Player {
preCheckFilesToGet() {
return new Promise((resolve, reject) => {
let toLoadBgm = {};
let toLoadSe = {};
for(let i = 0; i < utage.currentPlayingFile.length; ++i) {
try {
let c = utage.currentPlayingFile[i];
@ -58,7 +67,7 @@ class Player {
} else if(!this.utage.textureInfo[c.Arg1]) {
console.log(`Failed to get BG: ${c.Arg1}`);
}
break;
break;
//Text
case "":
//Character Text
@ -74,18 +83,58 @@ class Player {
(!this.utage.characterInfo[c.Arg1] || !this.utage.characterInfo[c.Arg1][Arg2])) {
console.log(`Failed to get Character: ${c.Arg1}|${Arg2}`);
}
break;
//These voices arent in the Sound.tsv because fuck you
if(c.Voice) {
let filename = c.Voice;
if(filename.includes(',')) {
let s = filename.split(',');
filename = `${s[0].split('_').join('/')}/${s[1]}`;
}
filename = `${this.utage.rootDirectory}XDUData/Voice/${filename}.opus`;
if(!toLoadSe[c.Voice]) {
toLoadSe[c.Voice] = { Label: c.Voice, FileName: filename };
}
}
break;
case "bgm":
if(this.utage.soundInfo[c.Arg1]) {
if(!toLoadBgm[c.Arg1]) {
toLoadBgm[c.Arg1] = this.utage.soundInfo[c.Arg1];
}
} else {
console.log(`Failed to get BGM: ${c.Arg1}`);
}
break;
case "se":
if(this.utage.soundInfo[c.Arg1]) {
if(!toLoadSe[c.Arg1]) {
toLoadSe[c.Arg1] = this.utage.soundInfo[c.Arg1];
}
} else {
console.log(`Failed to get SE: ${c.Arg1}`);
}
break;
}
} catch (error) {
console.log(error);
continue;
}
}
let audioArray = [];
for(let s of Object.keys(toLoadBgm)) {
audioArray.push(toLoadBgm[s]);
}
for(let s of Object.keys(toLoadSe)) {
audioArray.push(toLoadSe[s]);
}
this.audio.loadSounds(audioArray, (percent) => {
this.onAudioProgress(percent);
});
//Manually load white bg for fading. Can be tinted to change color.
this.loader.add('bg|whiteFade', `${this.utage.rootDirectory}Images/white.png`);
this.loader
.on("progress", (loader, resource) => {
this.onPixiProgress(loader, resource)
this.onPixiProgress(loader, resource);
})
.load(() => {
this.onPixiLoad(resolve, reject);
@ -133,17 +182,34 @@ class Player {
}
onPixiProgress(loader, resource) {
if(loader.progress < 100) {
this.text.titleText(true, `Loading Assets... ${loader.progress.toFixed(0)}%`);
} else {
this.text.titleText(false, '');
}
this.assetLoadPercent = loader.progress;
this.text.titleText(true, `Loading Assets... ${loader.progress.toFixed(0)}%`);
this.onLoadProgressUpdate();
}
onAudioProgress(percent) {
this.audioLoadPercent = percent;
this.onLoadProgressUpdate();
}
onLoadProgressUpdate() {
let totalProgress = (this.audioLoadPercent / 2) + (this.assetLoadPercent / 2);
this.text.titleText(true, `Loading Assets... ${totalProgress.toFixed(0)}%`);
}
onPixiLoad(resolve, reject) {
this.runEvent = true;
this.buildLayerContainers();
resolve();
if(this.audioLoadPercent === 100) {
this.text.titleText(false, '');
setTimeout(() => {
this.runEvent = true;
this.buildLayerContainers();
resolve();
}, 1000);
} else {
setTimeout(() => {
this.onPixiLoad(resolve, reject);
}, 100);
}
}
onPixiTick(delta) {
@ -185,17 +251,18 @@ class Player {
for(let i = 0; i < this.lerpTargets.length; ++i) {
let l = this.lerpTargets[i];
l.curTime += deltaTime;
if(l.curTime < 0) { continue; }
let inter = l.inter || "linear";
let pos = l.curTime / l.time;
if(pos >= 1) {
pos = 1;
if(pos >= 1) {
pos = 1;
toRemove.push(i);
if(l.post === "destroy") {
debugger;
l.object.destroy();
continue;
}
}
let newValue = commonFunctions.lerp(l.initV, l.finalV, pos);
let newValue = commonFunctions.lerp(l.initV, l.finalV, pos, inter);
let split = l.type.split(".");
switch(split.length) {
case 1:
@ -219,24 +286,28 @@ class Player {
processCommand(delta) {
try {
let cur = this.currentCommand;
if(this.checkIfAllOff()) {
this.text.dialogText(false, "");
this.text.characterName(false, "");
} else {
this.text.dialogText(true, "");
this.text.characterName(true, "");
}
//if(this.checkIfAllOff()) {
// this.text.dialogText(false, "");
// this.text.characterName(false, "");
//} else {
// this.text.dialogText(true, "");
// this.text.characterName(true, "");
//}
switch((cur.Command || "").toLowerCase()) {
case "scenetitle01":
this.waitTime = this.titleWaitTime * 1000;
this.text.titleText(true, cur.Text);
var text = cur.English ? (utage.currentTranslation[cur.English] || cur.Text) : cur.Text;
this.text.titleText(true, text);
break;
case "divaeffect":
this.waitTime = 1000//Number(cur.Arg5) * 1000;
this.text.divaText(true, cur.Text);
var text = cur.English ? (utage.currentTranslation[cur.English] || cur.Text) : cur.Text;
this.text.divaText(true, text);
break;
//FadeTo
case "fadeout":
this.text.dialogText(false, "");
this.text.characterName(false, "");
this.waitTime = Number(cur.Arg6) * 1000;
this.layers["bg|whiteFade"].sprite.tint = commonFunctions.getColorFromName(cur.Arg1);
this.lerpTargets.push({type: 'alpha', object: this.layers["bg|whiteFade"].sprite, curTime: 0, time: this.waitTime, finalV: 1, initV: 0});
@ -291,7 +362,8 @@ class Player {
let scale = 1 + (1 - Number(cur.Arg3));
let cont = this.layers["bg|mainparent"].container;
let x = this.center.x + -(Number(cur.Arg1));
let y = this.center.y + -(Number(cur.Arg2));
//y in xdu is flipped
let y = this.center.y - -(Number(cur.Arg2));
if(time) {
this.waitTime = time * 1000;
if(cont.scale.x !== scale) {
@ -307,11 +379,11 @@ class Player {
this.lerpTargets.push({type: 'position.x', object: cont, curTime: 0,
time: this.waitTime, finalV: x, initV: cont.position.x });
}
if(cont.position.y !== y) {
this.lerpTargets.push({type: 'position.y', object: cont, curTime: 0,
time: this.waitTime, finalV: y, initV: cont.position.y });
}
if(cur.Arg6 && cur.Arg6.toLowerCase() === "nowait") {
this.waitTime = 0;
}
@ -322,6 +394,8 @@ class Player {
break;
}
case "characteroff": {
this.text.dialogText(false, "");
this.text.characterName(false, "");
for(let c of Object.keys(this.currentCharacters)) {
if(!this.currentCharacters[c]) { continue; }
let curChar = this.currentCharacters[c];
@ -335,6 +409,7 @@ class Player {
}
}
case "tween":
this.processTween(delta, cur);
break;
case "bgm":
break;
@ -344,6 +419,9 @@ class Player {
break;
case "shake":
break;
case "henshin01_bgmoff":
this.checkPutCharacterScreen(cur, true);
break;
default:
this.processCommandOther(delta);
break;
@ -357,64 +435,174 @@ class Player {
processCommandOther(delta) {
let cur = this.currentCommand;
//Character on screen
checkPutCharacterScreen.apply(this);
this.checkPutCharacterScreen(cur);
//Display text
checkPutText.apply(this);
function checkPutCharacterScreen() {
if(!cur.Command && cur.Arg1 && this.utage.characterInfo[cur.Arg1]) {
if(!cur.Arg2) {
cur.Arg2 = this.defaultCharPattern;
}
let chr = this.utage.characterInfo[cur.Arg1][cur.Arg2];
let lay = undefined;
let chlay = undefined;
if(cur.Arg3) {
lay = this.layers[cur.Arg3];
chlay = this.currentCharacters[cur.Arg3];
if(!lay) { return; }
} else {
lay = this.lastCharOffLayer;
if(!lay) { return; }
cur.Arg3 = lay.info.LayerName;
}
if(this.currentCharacters[cur.Arg3] && this.currentCharacters[cur.Arg3].charName === cur.Arg1) {
return;
}
//If the layer already has a character on it remove it.
if(chlay && (chlay.character.NameText !== chr.NameText || chlay.character.Pattern !== chr.Pattern)) {
this.lerpTargets.push({type: 'alpha', object: chlay.sprite, curTime: 0, time: 100, 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);
sprite.scale.set(Number(chr.Scale), Number(chr.Scale));
let anchor = commonFunctions.getAnchorFromCharPivot(chr.Pivot);
sprite.anchor.set(anchor.x, anchor.y);
sprite.alpha = 0;
this.currentCharacters[cur.Arg3] = { layer: lay, character: chr, charName: cur.Arg1, sprite: sprite };
this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: 100, finalV: 1, initV: 0 });
lay.container.addChild(sprite);
lay.container.visible = true;
}
}
function checkPutText() {
if(!cur.Command && cur.Arg1 && cur.Text) {
if(cur.Arg2 && cur.Arg2.toLowerCase() === "<off>") {
this.text.characterName(true, cur.Arg1);
this.text.dialogText(true, commonFunctions.convertUtageTextTags(cur.Text));
} else {
let charName = "";
for(let c of Object.keys(this.currentCharacters)) {
if(!this.currentCharacters[c]) { continue; }
if(this.currentCharacters[c].charName === cur.Arg1) {
this.text.characterName(true, this.currentCharacters[c].character.NameText);
this.text.dialogText(true, commonFunctions.convertUtageTextTags(cur.Text));
break;
}
this.checkPutText(cur);
}
checkPutCharacterScreen(cur, special = false) {
if((!cur.Command || special) && cur.Arg1 && this.utage.characterInfo[cur.Arg1]) {
let lay = undefined;
let curChar = undefined;
//First check if the character is already on screen
for(let c of Object.keys(this.currentCharacters)) {
if(!this.currentCharacters[c]) { continue; }
if(this.currentCharacters[c].charName === cur.Arg1) {
curChar = this.currentCharacters[c];
lay = this.currentCharacters[c].layer;
if(!cur.Arg3) {
cur.Arg3 = c;
}
}
}
//Sometimes they don't give a pattern so just assume the default.
if(!cur.Arg2 && !curChar) {
cur.Arg2 = this.defaultCharPattern;
//If the character was already on screen use that pattern
} else if (!cur.Arg2 && curChar) {
cur.Arg2 = curChar.character.Pattern;
}
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) {
lay = this.layers[cur.Arg3];
curChar = 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(!lay) { return; }
cur.Arg3 = lay.info.LayerName;
}
//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) {
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: 100, 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);
sprite.scale.set(Number(chr.Scale), Number(chr.Scale));
let anchor = commonFunctions.getAnchorFromCharPivot(chr.Pivot);
sprite.anchor.set(anchor.x, anchor.y);
sprite.alpha = 0;
this.currentCharacters[cur.Arg3] = { layer: lay, character: chr, charName: cur.Arg1, sprite: sprite };
this.lerpTargets.push({type: 'alpha', object: sprite, curTime: 0, time: 100, finalV: 1, initV: 0 });
lay.container.addChild(sprite);
lay.container.visible = true;
}
}
checkPutText(cur) {
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;
text = commonFunctions.convertUtageTextTags(text);
if(cur.Arg2 && cur.Arg2.toLowerCase() === "<off>") {
this.text.characterName(true, cur.Arg1);
this.text.dialogText(true, commonFunctions.convertUtageTextTags(text));
} else {
let charName = "";
let found = true;
//Look for the character that is saying the text to get their name
//future note: This might be better to just look for the character in character info if this start failing.
for(let c of Object.keys(this.currentCharacters)) {
if(!this.currentCharacters[c]) { continue; }
if(this.currentCharacters[c].charName === cur.Arg1) {
this.text.characterName(true, this.currentCharacters[c].character.NameText);
this.text.dialogText(true, text);
this.currentCharacters[c].sprite.tint = 0xFFFFFF;
found = true;
continue;
}
//while were here set other characters tint to background shade
if(this.currentCharacters[c].sprite) {
this.currentCharacters[c].sprite.tint = this.backCharTint;
}
}
//If we didnt find the character just dump the text anyways with Arg1 as the name
if(!found) {
this.text.characterName(true, cur.Arg1);
this.text.dialogText(true, text);
}
}
this.manualNext = true;
} else if(!cur.Command && cur.Arg2.toLowerCase() === "<off>" && cur.Text) {
var text = cur.English ? (utage.currentTranslation[cur.English] || cur.Text) : cur.Text;
this.text.characterName(true, "");
this.text.dialogText(true, commonFunctions.convertUtageTextTags(text));
this.manualNext = true;
}
}
processTween(delta, cur) {
this.text.dialogText(false, "");
this.text.characterName(false, "");
let curChar = undefined;
for(let c of Object.keys(this.currentCharacters)) {
if(!this.currentCharacters[c]) { continue; }
if(this.currentCharacters[c].charName === cur.Arg1) {
curChar = this.currentCharacters[c];
this.currentCharacters[c].sprite.tint = 0xFFFFFF;
continue;
}
//while were here set other characters tint to background shade
if(this.currentCharacters[c].sprite) {
this.currentCharacters[c].sprite.tint = this.backCharTint;
}
}
if(!curChar) { return; }
switch(cur.Arg2.toLowerCase()) {
case "moveto": {
let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3);
//moveto has a islocal value that im just assuming is true until I run into a case it actually isint.
if(!cur.Arg6 || cur.Arg6 !== "NoWait") {
this.waitTime = props.time + (props.delay || 0);
}
if(props.x) {
if(props.time) {
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: 'exp' });
} else {
curChar.sprite.position.x = curChar.sprite.position.x + props.x;
}
}
if(props.y) {
if(props.time) {
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: 'exp' });
} else {
curChar.sprite.position.y = curChar.sprite.position.y + props.y;
}
}
break;
}
case "punchposition": {
let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3);
if(!props.time) { props.time = 0.5; }
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' });
}
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' });
}
break;
}
case "colorto": {
let props = commonFunctions.getPropertiesFromTweenCommand(cur.Arg3);
if(props.alpha) {
if(props.time) {
} else {
curChar.sprite.alpha = 0;
}
}
this.waitTime = 1000;
}
}
}
@ -439,14 +627,33 @@ class Player {
return true;
}
onMainClick() {
if(this.runEvent && this.manualNext) {
if (!this.hasMoreText) {
this.getNextCommand();
} else {
}
onMainClick(event) {
if(!this.runEvent) {
return
}
event.preventDefault();
event.stopPropagation();
if(this.manualNext && !this.uiHidden) {
if (!this.text.scrollingText) {
this.manualNext = false;
this.waitTime = 0;
} else if(this.text.scrollingText) {
this.text.showDialogFullText();
}
} else if(this.uiHidden) {
this.text.hideUi(true);
this.uiHidden = false;
}
}
hideUiClicked(event) {
if(!this.runEvent) {
return;
}
event.preventDefault();
event.stopPropagation();
this.uiHidden = true;
this.text.hideUi(false);
}
onEndFile() {
@ -466,6 +673,16 @@ class Player {
this.currentCommand = command;
}
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);
document.getElementById('text-container').style.cssText = `transform: scale(${newScale})`;
}
resetAll() {
return new Promise((resolve, reject) => {
try {
@ -478,9 +695,19 @@ class Player {
}
this.loader.reset();
this.currentCharacters = {};
this.lastCharOffLayer = undefined;
this.layers = {};
this.sprites = {};
this.blackBackSp = undefined;
this.currentCommand = undefined;
this.runEvent = false;
this.secondTicker = 1000;
this.waitTime = 0;
this.lerpTargets = [];
this.manualNext = false;
this.hasMoreText = false;
this.audioLoadPercent = 0;
this.assetLoadPercent = 0;
this.text.resetAll();
resolve();
} catch (error) {

View file

@ -8,6 +8,10 @@ class TextFunctions {
this.dialogBox = undefined;
this.character = undefined;
this.dialog = undefined;
this.dialogToDisplay = {timeout: undefined, fullText: "", text: "", subsection: "", subindex: -1};
this.textScrollSpeedMs = 40;
this.scrollingText = false;
this.lineHeight = -1;
}
findTextElements() {
@ -17,6 +21,7 @@ class TextFunctions {
this.dialogBox = document.getElementById('dialog-box');
this.character = document.getElementById('character');
this.dialog = document.getElementById('dialog');
this.dialogInner = document.getElementById('dialog-inner');
}
titleText(show, text) {
@ -42,18 +47,90 @@ class TextFunctions {
}
dialogText(show, text) {
if(this.lineHeight == -1) {
this.lineHeight = Number(window.getComputedStyle(this.dialog, null).getPropertyValue("line-height").replace('px', ''));
}
if(text != undefined) {
this.dialog.innerHTML = text;
if(this.dialogToDisplay.timeout) {
clearTimeout(this.dialogToDisplay.timeout);
this.dialogToDisplay.timeout = undefined;
}
if(text === "") {
this.dialogInner.innerHTML = text;
this.scrollingText = false;
} else {
this.dialogToDisplay.text = text;
this.dialogToDisplay.fullText = text;
this.dialogInner.innerHTML = this.dialogToDisplay.text[0];
this.dialogToDisplay.text = this.dialogToDisplay.text.slice(1);
this.scrollingText = true;
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;";
function putText() {
let t = this.getNextTextToPut();
if(!t) { return; }
this.dialogInner.innerHTML += t;
let lHeight = this.lineHeight * 2
if(this.dialogInner.offsetHeight > lHeight) {
this.dialog.scrollTop = this.dialogInner.offsetHeight - lHeight;
}
this.dialogToDisplay.timeout = setTimeout(putText.bind(this), this.textScrollSpeedMs);
}
}
showDialogFullText() {
if(this.dialogToDisplay.timeout) {
clearTimeout(this.dialogToDisplay.timeout);
this.dialogToDisplay.timeout = undefined;
}
this.dialogInner.innerHTML = this.dialogToDisplay.fullText;
let lHeight = this.lineHeight * 2
if(this.dialogInner.offsetHeight > lHeight) {
this.dialog.scrollTop = this.dialogInner.offsetHeight - lHeight;
}
this.scrollingText = false;
}
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;";
}
getNextTextToPut() {
if(!this.dialogToDisplay.text || this.dialogToDisplay.text.length === 0) {
this.scrollingText = false;
return "";
}
let toSlice = 1;
let text = this.dialogToDisplay.text[0];
if(text === '<') {
let match = this.dialogToDisplay.text.match(/<.+>/);
if(match && match[0]); {
debugger;
text = match[0];
toSlice = match[0].length;
if(!text.includes("/")) {
let s = text.split('');
s.splice(1, 0, '/');
text += s.join('');
}
}
}
this.dialogToDisplay.text = this.dialogToDisplay.text.slice(toSlice);
return text;
}
resetAll() {
this.title.innerHTML = '';
this.diva.innerHTML = '';
this.character.innerHTML = '';
this.dialog.innerHTML = '';
this.dialogInner.innerHTML = '';
this.title.style = "opacity: 0;";
this.diva.style = "opacity: 0;";
this.mainUi.style = "opacity: 0;";

View file

@ -13,11 +13,12 @@ class UtageInfo {
this.paramInfo = {};
this.soundInfo = {};
this.textureInfo = {};
this.currentTranslation = {};
}
loadUtageSettings(resolve, reject) {
return new Promise((resolve, reject) => {
var promises = [
let promises = [
commonFunctions.getFileJson(`${this.rootDirectory}Js/XduMissions.json`),
commonFunctions.getFileText(`${this.rootDirectory}XDUData/Utage/Diva/Settings/Character.tsv`),
commonFunctions.getFileText(`${this.rootDirectory}XDUData/Utage/Diva/Settings/Layer.tsv`),
@ -51,14 +52,14 @@ class UtageInfo {
return new Promise((resolve, reject) => {
commonFunctions.getFileText(file)
.then((success) => {
var lines = success.split("\n");
var headers = [];
let lines = success.split("\n");
let headers = [];
for(let i = 0; i < lines.length; ++i) {
var line = lines[i];
let line = lines[i];
if(i === 0) {
headers = line.split('\t');
headers = line.trim().split('\t');
} else {
var read = commonFunctions.readLine(line, headers);
let read = commonFunctions.readLine(line, headers);
if(read) {
this.currentPlayingFile.push(read);
}
@ -73,18 +74,31 @@ class UtageInfo {
});
}
loadMissionTranslation(file) {
return new Promise((resolve, reject) => {
commonFunctions.getFileJson(file)
.then((success) => {
this.currentTranslation = success;
resolve();
}, (failure) => {
this.currentTranslation = {};
resolve();
});
});
}
//http://madnesslabo.net/utage/?page_id=4521&lang=en
parseCharacterInfo(text) {
var lines = text.split("\n");
var headers = [];
var lastCharName = '';
var lastNameText = '';
let lines = text.split("\n");
let headers = [];
let lastCharName = '';
let lastNameText = '';
for(let i = 0; i < lines.length; ++i) {
var line = lines[i];
let line = lines[i];
if(i === 0) {
headers = line.split('\t');
} else {
var read = commonFunctions.readLine(line, headers);
let read = commonFunctions.readLine(line, headers);
if(read && !read.comment) {
//If character name is empty it means it belongs to the line before it
// so I am grouping the patterns by character name.
@ -111,14 +125,14 @@ class UtageInfo {
//http://madnesslabo.net/utage/?page_id=4518&lang=en
parseLayerInfo(text) {
var lines = text.split("\n");
var headers = [];
let lines = text.split("\n");
let headers = [];
for(let i = 0; i < lines.length; ++i) {
var line = lines[i];
let line = lines[i];
if(i === 0) {
headers = line.split('\t');
} else {
var read = commonFunctions.readLine(line, headers);
let read = commonFunctions.readLine(line, headers);
if(read && read.LayerName) {
this.layerInfo[read.LayerName] = read;
}
@ -128,14 +142,14 @@ class UtageInfo {
//http://madnesslabo.net/utage/?page_id=4514&lang=en
parseLocalizeInfo(text) {
var lines = text.split("\n");
var headers = [];
let lines = text.split("\n");
let headers = [];
for(let i = 0; i < lines.length; ++i) {
var line = lines[i];
let line = lines[i];
if(i === 0) {
headers = line.split('\t');
} else {
var read = commonFunctions.readLine(line, headers);
let read = commonFunctions.readLine(line, headers);
if(read && read.Key) {
this.localizeInfo[read.Key] = read;
}
@ -145,14 +159,14 @@ class UtageInfo {
//http://madnesslabo.net/utage/?page_id=4517&lang=en
parseParamInfo(text) {
var lines = text.split("\n");
var headers = [];
let lines = text.split("\n");
let headers = [];
for(let i = 0; i < lines.length; ++i) {
var line = lines[i];
let line = lines[i];
if(i === 0) {
headers = line.split('\t');
} else {
var read = commonFunctions.readLine(line, headers);
let read = commonFunctions.readLine(line, headers);
if(read && read.Label) {
this.paramInfo[read.Label] = read;
}
@ -162,14 +176,14 @@ class UtageInfo {
//http://madnesslabo.net/utage/?page_id=4519&lang=en
parseSoundInfo(text) {
var lines = text.split("\n");
var headers = [];
let lines = text.split("\n");
let headers = [];
for(let i = 0; i < lines.length; ++i) {
var line = lines[i];
let line = lines[i];
if(i === 0) {
headers = line.split('\t');
} else {
var read = commonFunctions.readLine(line, headers);
let read = commonFunctions.readLine(line, headers);
if(read && read.Label) {
if(read.FileName && read.Type) {
if(!read.FileName.includes('.')) {
@ -178,7 +192,7 @@ class UtageInfo {
switch(read.Type.toLowerCase()) {
case 'se':
if(read.FileName.includes(',')) {
var s = read.FileName.split(',');
let s = read.FileName.split(',');
read.FileName = `${s[0].split('_').join('/')}/${s[1]}`;
}
read.FileName = `${this.rootDirectory}XDUData/Se/${read.FileName}`;
@ -196,14 +210,14 @@ class UtageInfo {
//http://madnesslabo.net/utage/?page_id=4520&lang=en
parseTextureInfo(text) {
var lines = text.split("\n");
var headers = [];
let lines = text.split("\n");
let headers = [];
for(let i = 0; i < lines.length; ++i) {
var line = lines[i];
let line = lines[i];
if(i === 0) {
headers = line.split('\t');
} else {
var read = commonFunctions.readLine(line, headers);
let read = commonFunctions.readLine(line, headers);
if(read && read.Label) {
read.FileName = `${this.rootDirectory}XDUData/BG/${read.FileName}`;
this.textureInfo[read.Label] = read;