From 9248a521945c94e9305166c1d16a147e0e0f9136 Mon Sep 17 00:00:00 2001 From: LoveEevee Date: Mon, 9 Mar 2020 15:36:57 +0300 Subject: [PATCH] Lots of bug fixes - Toggling autoplay checkbox in debug now disallows saving the score - Fix crown of the song that was previously selected rendering above the genre - Outline of empty crowns is slightly darker - Fix rendering when there is a crown on oni and no crown on ura - Fix crowns overlapping the netplay 2P icon - Fix gauge in latency calibration - Fix debug to work on mobile, can be toggled with ctrl+alt+`;` on hacker's keyboard with permanent notification - Fix being unable to scroll the settings list without toggling something - Handle KeyboardInterrupt in server.py - Fix category jumping not working in session mode - Fix mouse cursor being hidden at results screen in session mode - Make "Issues" on the about screen and "An error occurred, please refresh" on loading screens translateable - CanvasCache uses integer increments for comparison instead of Date.now() - For imported songs, exclude song titles from genre comparisons if they appear in the name of the folder - Fix tja files with spaces in the notation - Fix second player's score on the results screen to have upside down appearance - Add fixed chinese strings --- public/src/js/about.js | 2 + public/src/js/canvascache.js | 11 +-- public/src/js/canvasdraw.js | 105 ++++++++++++++------------ public/src/js/controller.js | 1 + public/src/js/debug.js | 141 +++++++++++++++++++++++++++-------- public/src/js/game.js | 2 +- public/src/js/gamerules.js | 10 ++- public/src/js/importsongs.js | 27 ++++--- public/src/js/loader.js | 37 +++++++-- public/src/js/loadsong.js | 2 +- public/src/js/main.js | 2 +- public/src/js/pageevents.js | 26 ++++--- public/src/js/parsetja.js | 3 +- public/src/js/scoresheet.js | 46 +++++++----- public/src/js/settings.js | 51 ++++++++++--- public/src/js/songselect.js | 137 ++++++++++++++++++++++------------ public/src/js/strings.js | 34 ++++++--- public/src/js/view.js | 2 +- public/src/views/about.html | 4 +- public/src/views/debug.html | 2 +- server.py | 25 ++++++- 21 files changed, 459 insertions(+), 211 deletions(-) diff --git a/public/src/js/about.js b/public/src/js/about.js index afa4a23..8037a29 100644 --- a/public/src/js/about.js +++ b/public/src/js/about.js @@ -31,6 +31,8 @@ this.items = [] + this.getLink(this.linkIssues).innerText = strings.about.issues + this.linkIssues.setAttribute("alt", strings.about.issues) var versionUrl = gameConfig._version.url this.getLink(this.linkIssues).href = versionUrl + "issues" this.items.push(this.linkIssues) diff --git a/public/src/js/canvascache.js b/public/src/js/canvascache.js index c3c6913..fbe9a79 100644 --- a/public/src/js/canvascache.js +++ b/public/src/js/canvascache.js @@ -4,6 +4,7 @@ class CanvasCache{ if(w){ this.resize(w, h, scale) } + this.index = Number.MIN_SAFE_INTEGER } resize(w, h, scale){ if(this.canvas){ @@ -33,7 +34,7 @@ class CanvasCache{ return } var saved = false - var time = Date.now() + var index = this.index++ if(!img){ var w = config.w var h = config.h @@ -44,11 +45,11 @@ class CanvasCache{ } if(this.y + h > this.h){ var clear = true - var oldest = {time: time} + var oldest = {index: index} this.map.forEach((oldImg, id) => { - if(oldImg.time < oldest.time){ + if(oldImg.index < oldest.index){ oldest.id = id - oldest.time = oldImg.time + oldest.index = oldImg.index } }) var oldImg = this.map.get(oldest.id) @@ -84,7 +85,7 @@ class CanvasCache{ this.map.set(config.id, img) callback(this.ctx) } - img.time = time + img.index = index if(setOnly){ this.ctx.restore() return diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index f31a174..0a4ddb4 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -1304,7 +1304,7 @@ ctx.globalAlpha = 1 - config.shine } - ctx.strokeStyle = config.type ? "#000" : "rgba(255, 193, 0, 0.5)" + ctx.strokeStyle = config.type ? "#000" : "#ffc616" ctx.lineWidth = 18 ctx.stroke(this.crownPath) @@ -1362,12 +1362,21 @@ ctx.fillStyle = "#000" ctx.beginPath() if(config.scoresheet){ - ctx.moveTo(-4, 26) - ctx.lineTo(gaugeClear - 4, 26) - this.roundedCorner(ctx, gaugeClear - 4, 4, 13, 0) - this.roundedCorner(ctx, 760, 4, 13, 1) - ctx.lineTo(760, 56) - ctx.lineTo(-4, 56) + if(config.multiplayer){ + ctx.moveTo(-4, -4) + ctx.lineTo(760, -4) + this.roundedCorner(ctx, 760, 48, 13, 2) + this.roundedCorner(ctx, gaugeClear - 4, 48, 13, 3) + ctx.lineTo(gaugeClear - 4, 26) + ctx.lineTo(-4, 26) + }else{ + ctx.moveTo(-4, 26) + ctx.lineTo(gaugeClear - 4, 26) + this.roundedCorner(ctx, gaugeClear - 4, 4, 13, 0) + this.roundedCorner(ctx, 760, 4, 13, 1) + ctx.lineTo(760, 56) + ctx.lineTo(-4, 56) + } }else if(config.multiplayer){ ctx.moveTo(gaugeClear - 7, 27) ctx.lineTo(788, 27) @@ -1381,42 +1390,44 @@ } ctx.fill() - if(gaugeFilled <= gaugeClear){ + if(gaugeFilled < gaugeClear){ ctx.fillStyle = config.blue ? "#184d55" : "#680000" var x = Math.max(0, gaugeFilled - 5) - ctx.fillRect(x, firstTop, gaugeClear - x + 2, 22) + ctx.fillRect(x, firstTop, gaugeClear - x + 2 + (gaugeClear < gaugeW ? 0 : -7), 22) } if(gaugeFilled > 0){ - var w = Math.min(gaugeClear + 1, gaugeFilled - 4) + var w = Math.min(gaugeW - 5, gaugeClear + 1, gaugeFilled - 4) ctx.fillStyle = config.blue ? "#00edff" : "#ff3408" ctx.fillRect(0, firstTop + 2, w, 20) ctx.fillStyle = config.blue ? "#9cffff" : "#ffa191" ctx.fillRect(0, firstTop, w, 3) } - if(gaugeFilled < gaugeW - 4){ - ctx.fillStyle = "#684900" - var x = Math.max(gaugeClear + 9, gaugeFilled - gaugeClear + 9) - ctx.fillRect(x, secondTop, gaugeW - 4 - x, 44) + if(gaugeClear < gaugeW){ + if(gaugeFilled < gaugeW - 4){ + ctx.fillStyle = "#684900" + var x = Math.max(gaugeClear + 9, gaugeFilled - gaugeClear + 9) + ctx.fillRect(x, secondTop, gaugeW - 4 - x, 44) + } + if(gaugeFilled > gaugeClear + 14){ + var w = Math.min(gaugeW - 4, gaugeFilled - gaugeClear - 14) + ctx.fillStyle = "#ff0" + ctx.fillRect(gaugeClear + 9, secondTop + 2, w, 42) + ctx.fillStyle = "#fff" + ctx.fillRect(gaugeClear + 9, secondTop, w, 3) + } + ctx.fillStyle = cleared ? "#ff0" : "#684900" + ctx.beginPath() + if(config.multiplayer){ + this.roundedCorner(ctx, gaugeClear, secondTop + 44, 10, 3) + ctx.lineTo(gaugeClear, secondTop) + ctx.lineTo(gaugeClear + 10, secondTop) + }else{ + ctx.moveTo(gaugeClear, secondTop + 44) + this.roundedCorner(ctx, gaugeClear, secondTop, 10, 0) + ctx.lineTo(gaugeClear + 10, secondTop + 44) + } + ctx.fill() } - if(gaugeFilled > gaugeClear + 14){ - var w = Math.min(gaugeW - 4, gaugeFilled - gaugeClear - 14) - ctx.fillStyle = "#ff0" - ctx.fillRect(gaugeClear + 9, secondTop + 2, w, 42) - ctx.fillStyle = "#fff" - ctx.fillRect(gaugeClear + 9, secondTop, w, 3) - } - ctx.fillStyle = cleared ? "#ff0" : "#684900" - ctx.beginPath() - if(config.multiplayer){ - this.roundedCorner(ctx, gaugeClear, secondTop + 44, 10, 3) - ctx.lineTo(gaugeClear, secondTop) - ctx.lineTo(gaugeClear + 10, secondTop) - }else{ - ctx.moveTo(gaugeClear, secondTop + 44) - this.roundedCorner(ctx, gaugeClear, secondTop, 10, 0) - ctx.lineTo(gaugeClear + 10, secondTop + 44) - } - ctx.fill() if(cleared){ ctx.save() ctx.clip() @@ -1430,7 +1441,7 @@ ctx.lineWidth = 5 for(var i = 0; i < 49; i++){ var x = 14 + i * 14 - ctx.lineWidth / 2 - if(i === 26){ + if(i === config.clear * 50 - 1){ ctx.stroke() ctx.beginPath() ctx.lineWidth = 4 @@ -1439,18 +1450,20 @@ ctx.lineTo(x, x < gaugeClear ? firstTop + 22 : secondTop + 44) } ctx.stroke() - this.layeredText({ - ctx: ctx, - text: strings.clear, - fontSize: 18, - fontFamily: config.font, - x: gaugeClear + 3, - y: config.multiplayer ? 22 : 11, - letterSpacing: -2 - }, [ - {scale: [1.1, 1.01], outline: "#000", letterBorder: 6}, - {scale: [1.11, 1], fill: cleared ? "#fff" : "#737373"} - ]) + if(config.clear < 47 / 50){ + this.layeredText({ + ctx: ctx, + text: strings.clear, + fontSize: 18, + fontFamily: config.font, + x: gaugeClear + 3, + y: config.multiplayer ? 22 : 11, + letterSpacing: -2 + }, [ + {scale: [1.1, 1.01], outline: "#000", letterBorder: 6}, + {scale: [1.11, 1], fill: cleared ? "#fff" : "#737373"} + ]) + } ctx.restore() } diff --git a/public/src/js/controller.js b/public/src/js/controller.js index 776f184..583ffd3 100644 --- a/public/src/js/controller.js +++ b/public/src/js/controller.js @@ -3,6 +3,7 @@ class Controller{ this.selectedSong = selectedSong this.songData = songData this.autoPlayEnabled = autoPlayEnabled + this.saveScore = !autoPlayEnabled this.multiplayer = multiplayer this.touchEnabled = touchEnabled this.snd = this.multiplayer ? "_p" + this.multiplayer : "" diff --git a/public/src/js/debug.js b/public/src/js/debug.js index a6fa9a7..a940730 100644 --- a/public/src/js/debug.js +++ b/public/src/js/debug.js @@ -17,6 +17,7 @@ class Debug{ this.branchSelect = this.branchSelectDiv.getElementsByTagName("select")[0] this.branchResetBtn = this.branchSelectDiv.getElementsByClassName("reset")[0] this.volumeDiv = this.byClass("music-volume") + this.restartLabel = this.byClass("change-restart-label") this.restartCheckbox = this.byClass("change-restart") this.autoplayLabel = this.byClass("autoplay-label") this.autoplayCheckbox = this.byClass("autoplay") @@ -24,15 +25,19 @@ class Debug{ this.exitBtn = this.byClass("exit-btn") this.moving = false - pageEvents.add(window, ["mousedown", "mouseup", "blur"], this.stopMove.bind(this)) + this.windowSymbol = Symbol() + pageEvents.add(window, ["mousedown", "mouseup", "touchstart", "touchend", "blur", "resize"], this.stopMove.bind(this), this.windowSymbol) pageEvents.mouseAdd(this, this.onMove.bind(this)) - pageEvents.add(this.titleDiv, "mousedown", this.startMove.bind(this)) - pageEvents.add(this.minimiseDiv, "click", this.minimise.bind(this)) - pageEvents.add(this.restartBtn, "click", this.restartSong.bind(this)) - pageEvents.add(this.exitBtn, "click", this.clean.bind(this)) + pageEvents.add(window, "touchmove", this.onMove.bind(this)) + pageEvents.add(this.titleDiv, ["mousedown", "touchstart"], this.startMove.bind(this)) + pageEvents.add(this.minimiseDiv, ["click", "touchstart"], this.minimise.bind(this)) + pageEvents.add(this.restartBtn, ["click", "touchstart"], this.restartSong.bind(this)) + pageEvents.add(this.exitBtn, ["click", "touchstart"], this.clean.bind(this)) + pageEvents.add(this.restartLabel, "touchstart", this.touchBox.bind(this)) + pageEvents.add(this.autoplayLabel, "touchstart", this.touchBox.bind(this)) pageEvents.add(this.autoplayCheckbox, "change", this.toggleAutoplay.bind(this)) pageEvents.add(this.branchSelect, "change", this.branchChange.bind(this)) - pageEvents.add(this.branchResetBtn, "click", this.branchReset.bind(this)) + pageEvents.add(this.branchResetBtn, ["click", "touchstart"], this.branchReset.bind(this)) this.offsetSlider = new InputSlider(this.offsetDiv, -60, 60, 3) this.offsetSlider.onchange(this.offsetChange.bind(this)) @@ -54,24 +59,38 @@ class Debug{ return this.debugDiv.getElementsByClassName(name)[0] } startMove(event){ - if(event.which === 1){ + if(event.which === 1 || event.type === "touchstart"){ event.stopPropagation() - this.moving = { - x: event.offsetX, - y: event.offsetY - } + var divPos = this.debugDiv.getBoundingClientRect() + var click = event.type === "touchstart" ? event.changedTouches[0] : event + var x = click.pageX - divPos.left + var y = click.pageY - divPos.top + this.moving = {x: x, y: y} } } onMove(event){ if(this.moving){ - var x = event.clientX - this.moving.x - var y = event.clientY - this.moving.y + var click = event.type === "touchmove" ? event.changedTouches[0] : event + var x = click.clientX - this.moving.x + var y = click.clientY - this.moving.y this.moveTo(x, y) } } stopMove(event){ - var x = event.clientX - this.moving.x - var y = event.clientY - this.moving.y + if(!event || event.type === "resize"){ + var divPos = this.debugDiv.getBoundingClientRect() + var x = divPos.left + var y = divPos.top + }else{ + var click = event.type === "touchstart" || event.type === "touchend" ? event.changedTouches[0] : event + if(event.type == "blur"){ + var x = this.moving.x + var y = this.moving.y + }else{ + var x = click.clientX - this.moving.x + var y = click.clientY - this.moving.y + } + } var w = this.debugDiv.offsetWidth var h = this.debugDiv.offsetHeight if(x + w > innerWidth){ @@ -95,6 +114,7 @@ class Debug{ restore(){ debugObj.state = "open" this.debugDiv.style.display = "" + this.stopMove() } minimise(){ debugObj.state = "minimised" @@ -156,6 +176,7 @@ class Debug{ this.branchHideDiv.style.display = "" this.controller = null } + this.stopMove() } offsetChange(value, noRestart){ if(this.controller){ @@ -197,10 +218,12 @@ class Debug{ this.controller.restartSong() } } - toggleAutoplay(){ + toggleAutoplay(event){ if(this.controller){ this.controller.autoPlayEnabled = this.autoplayCheckbox.checked - if(!this.controller.autoPlayEnabled){ + if(this.controller.autoPlayEnabled){ + this.controller.saveScore = false + }else{ var keyboard = debugObj.controller.keyboard keyboard.setKey(false, "don_l") keyboard.setKey(false, "don_r") @@ -229,21 +252,30 @@ class Debug{ this.branchSelect.value = "auto" this.branchChange(null, noRestart) } + touchBox(event){ + event.currentTarget.click() + } clean(){ this.offsetSlider.clean() this.measureNumSlider.clean() + this.volumeSlider.clean() - pageEvents.remove(window, ["mousedown", "mouseup", "blur"]) + pageEvents.remove(window, ["mousedown", "mouseup", "touchstart", "touchend", "blur", "resize"], this.windowSymbol) pageEvents.mouseRemove(this) - pageEvents.remove(this.titleDiv, "mousedown") - pageEvents.remove(this.title, "mousedown") - pageEvents.remove(this.minimiseDiv, "click") - pageEvents.remove(this.restartBtn, "click") - pageEvents.remove(this.exitBtn, "click") + pageEvents.remove(window, "touchmove") + pageEvents.remove(this.titleDiv, ["mousedown", "touchstart"]) + pageEvents.remove(this.minimiseDiv, ["click", "touchstart"]) + pageEvents.remove(this.restartBtn, ["click", "touchstart"]) + pageEvents.remove(this.exitBtn, ["click", "touchstart"]) + pageEvents.remove(this.restartLabel, "touchstart") + pageEvents.remove(this.autoplayLabel, "touchstart") pageEvents.remove(this.autoplayCheckbox, "change") pageEvents.remove(this.branchSelect, "change") - pageEvents.remove(this.branchResetBtn, "click") + pageEvents.remove(this.branchResetBtn, ["click", "touchstart"]) + delete this.offsetSlider + delete this.measureNumSlider + delete this.volumeSlider delete this.titleDiv delete this.minimiseDiv delete this.offsetDiv @@ -259,6 +291,7 @@ class Debug{ delete this.restartBtn delete this.exitBtn delete this.controller + delete this.windowSymbol debugObj.state = "closed" debugObj.debug = null @@ -281,10 +314,22 @@ class InputSlider{ this.value = null this.defaultValue = null this.callbacks = [] + this.touchEnd = [] + this.windowSymbol = Symbol() + pageEvents.add(this.input, ["touchstart", "touchend"], event => { + event.stopPropagation() + }) + pageEvents.add(window, ["mouseup", "touchstart", "touchend", "blur"], event => { + if(event.type !== "touchstart"){ + this.touchEnd.forEach(func => func(event)) + }else if(event.target !== this.input){ + this.input.blur() + } + }, this.windowSymbol) - pageEvents.add(this.plus, "click", this.add.bind(this)) - pageEvents.add(this.minus, "click", this.subtract.bind(this)) - pageEvents.add(this.reset, "click", this.resetValue.bind(this)) + this.addTouchRepeat(this.plus, this.add.bind(this)) + this.addTouchRepeat(this.minus, this.subtract.bind(this)) + this.addTouch(this.reset, this.resetValue.bind(this)) pageEvents.add(this.input, "change", this.manualSet.bind(this)) pageEvents.add(this.input, "keydown", this.captureKeys.bind(this)) } @@ -364,15 +409,49 @@ class InputSlider{ captureKeys(event){ event.stopPropagation() } + addTouch(element, callback){ + pageEvents.add(element, ["mousedown", "touchstart"], event => { + if(event.type === "touchstart"){ + event.preventDefault() + }else if(event.which !== 1){ + return + } + callback(event) + }) + } + addTouchRepeat(element, callback){ + this.addTouch(element, event => { + var active = true + var func = () => { + active = false + this.touchEnd.splice(this.touchEnd.indexOf(func), 1) + } + this.touchEnd.push(func) + var repeat = delay => { + if(active && this.touchEnd){ + callback(event) + setTimeout(() => repeat(50), delay) + } + } + repeat(400) + }) + } + removeTouch(element){ + pageEvents.remove(element, ["mousedown", "touchstart"]) + } clean(){ - pageEvents.remove(this.plus, "click") - pageEvents.remove(this.minus, "click") - pageEvents.remove(this.reset, "click") - pageEvents.remove(this.input, ["change", "keydown"]) + this.removeTouch(this.plus) + this.removeTouch(this.minus) + this.removeTouch(this.reset) + pageEvents.remove(this.input, ["touchstart", "touchend"]) + pageEvents.remove(window, ["mouseup", "touchstart", "touchend", "blur"], this.windowSymbol) + pageEvents.remove(this.input, ["touchstart", "change", "keydown"]) delete this.input delete this.reset delete this.plus delete this.minus + delete this.windowSymbol + delete this.touchEnd } } diff --git a/public/src/js/game.js b/public/src/js/game.js index 3dc34d5..fd1f94b 100644 --- a/public/src/js/game.js +++ b/public/src/js/game.js @@ -811,7 +811,7 @@ class Game{ offsets.push(offset) progress.hit++ progress.last = current - this.globalScore.gauge = 100 / (progress.requirement / progress.hit) + this.globalScore.gauge = 10000 / (progress.requirement / progress.hit) } } calibrationReset(to, togglePause){ diff --git a/public/src/js/gamerules.js b/public/src/js/gamerules.js index 9dc1f11..51cd4fc 100644 --- a/public/src/js/gamerules.js +++ b/public/src/js/gamerules.js @@ -13,6 +13,7 @@ class GameRules{ case "hard": case "oni": case "ura": + default: this.good = 3 / 2 * frame this.ok = 9 / 2 * frame this.bad = 13 / 2 * frame @@ -30,6 +31,9 @@ class GameRules{ case "ura": this.gaugeClear = 40 / 50 break + default: + this.gaugeClear = 51 / 50 + break } this.daiLeniency = 2 * frame @@ -61,8 +65,10 @@ class GameRules{ } return {good: good, ok: ok, bad: bad} } + gaugePercent(gauge){ + return Math.floor(gauge / 200) / 50 + } clearReached(gauge){ - var gaugePercent = Math.round(gauge / 200) / 50 - return gaugePercent >= this.gaugeClear + return this.gaugePercent(gauge) >= this.gaugeClear } } diff --git a/public/src/js/importsongs.js b/public/src/js/importsongs.js index 793e006..840d0bf 100644 --- a/public/src/js/importsongs.js +++ b/public/src/js/importsongs.js @@ -269,7 +269,7 @@ songObj.subtitle_lang = subtitleLangArray.join("\n") } if(!songObj.category){ - songObj.category = category || this.getCategory(file) + songObj.category = category || this.getCategory(file, [songTitle || songObj.title, file.name.slice(0, file.name.lastIndexOf("."))]) } if(songObj.stars.length !== 0){ this.songs[index] = songObj @@ -277,7 +277,7 @@ var hash = md5.base64(event.target.result).slice(0, -2) songObj.hash = hash scoreStorage.songTitles[songObj.title] = hash - var score = scoreStorage.get(hash) + var score = scoreStorage.get(hash, false, true) if(score){ score.title = songObj.title } @@ -307,7 +307,7 @@ music: this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] || "muted" } var filename = file.name.slice(0, file.name.lastIndexOf(".")) - var title = osu.metadata.TitleUnicode || osu.metadata.Title + var title = osu.metadata.TitleUnicode || osu.metadata.Title || file.name.slice(0, file.name.lastIndexOf(".")) if(title){ var suffix = "" var matches = filename.match(/\[.+?\]$/) @@ -320,11 +320,11 @@ songObj.title = filename } this.songs[index] = songObj - songObj.category = category || this.getCategory(file) + songObj.category = category || this.getCategory(file, [osu.metadata.TitleUnicode, osu.metadata.Title, file.name.slice(0, file.name.lastIndexOf("."))]) var hash = md5.base64(event.target.result).slice(0, -2) songObj.hash = hash scoreStorage.songTitles[songObj.title] = hash - var score = scoreStorage.get(hash) + var score = scoreStorage.get(hash, false, true) if(score){ score.title = songObj.title } @@ -394,12 +394,21 @@ return name.slice(0, name.lastIndexOf(".")) } - getCategory(file){ + getCategory(file, exclude){ var path = file.webkitRelativePath.toLowerCase().split("/") for(var i = path.length - 2; i >= 0; i--){ - for(var cat in this.categories){ - if(path[i].indexOf(cat) !== -1){ - return this.categories[cat] + var hasTitle = false + for(var j in exclude){ + if(path[i].indexOf(exclude[j].toLowerCase()) !== -1){ + hasTitle = true + break + } + } + if(!hasTitle){ + for(var cat in this.categories){ + if(path[i].indexOf(cat) !== -1){ + return this.categories[cat] + } } } } diff --git a/public/src/js/loader.js b/public/src/js/loader.js index 3a5cd75..f8e9aca 100644 --- a/public/src/js/loader.js +++ b/public/src/js/loader.js @@ -20,6 +20,7 @@ class Loader{ } run(){ this.promises = [] + this.loaderDiv = document.querySelector("#loader") this.loaderPercentage = document.querySelector("#loader .percentage") this.loaderProgress = document.querySelector("#loader .progress") @@ -213,7 +214,7 @@ class Loader{ song.hash = song.title } scoreStorage.songTitles[song.title] = song.hash - var score = scoreStorage.get(song.hash) + var score = scoreStorage.get(song.hash, false, true) if(score){ score.title = song.title } @@ -248,12 +249,38 @@ class Loader{ return name.slice(0, name.lastIndexOf(".")) } errorMsg(error){ + if(Array.isArray(error) && error[1] instanceof HTMLElement){ + error = error[0] + ": " + error[1].outerHTML + } console.error(error) pageEvents.send("loader-error", error) - this.error = true - this.loaderPercentage.appendChild(document.createElement("br")) - this.loaderPercentage.appendChild(document.createTextNode("An error occurred, please refresh")) - this.clean() + if(!this.error){ + this.error = true + this.loaderDiv.classList.add("loaderError") + if(typeof allStrings === "object"){ + var lang = localStorage.lang + if(!lang){ + var userLang = navigator.languages.slice() + userLang.unshift(navigator.language) + for(var i in userLang){ + for(var j in allStrings){ + if(allStrings[j].regex.test(userLang[i])){ + lang = j + } + } + } + } + if(!lang){ + lang = "en" + } + var errorOccured = allStrings[lang].errorOccured + }else{ + var errorOccured = "An error occurred, please refresh" + } + this.loaderPercentage.appendChild(document.createElement("br")) + this.loaderPercentage.appendChild(document.createTextNode(errorOccured)) + this.clean() + } } assetLoaded(){ if(!this.error){ diff --git a/public/src/js/loadsong.js b/public/src/js/loadsong.js index df82530..b40461b 100644 --- a/public/src/js/loadsong.js +++ b/public/src/js/loadsong.js @@ -160,7 +160,7 @@ class LoadSong{ console.error(error) pageEvents.send("load-song-error", error) errorMessage(new Error(error).stack) - alert("An error occurred, please refresh") + alert(strings.errorOccured) }) } loadSongBg(){ diff --git a/public/src/js/main.js b/public/src/js/main.js index 25dea20..3a393a4 100644 --- a/public/src/js/main.js +++ b/public/src/js/main.js @@ -102,7 +102,7 @@ pageEvents.add(versionDiv, ["click", "touchend"], event => { resizeRoot() setInterval(resizeRoot, 100) pageEvents.keyAdd(debugObj, "all", "down", event => { - if((event.keyCode === 186 || event.keyCode === 59) && event.ctrlKey && event.shiftKey && !event.altKey){ + if((event.keyCode === 186 || event.keyCode === 59) && event.ctrlKey && (event.shiftKey || event.altKey)){ // Semicolon if(debugObj.state === "open"){ debugObj.debug.minimise() diff --git a/public/src/js/pageevents.js b/public/src/js/pageevents.js index c8c0af7..56c0d1a 100644 --- a/public/src/js/pageevents.js +++ b/public/src/js/pageevents.js @@ -11,60 +11,62 @@ class PageEvents{ this.add(window, "blur", this.blurEvent.bind(this)) this.kbd = [] } - add(target, type, callback){ + add(target, type, callback, symbol){ if(Array.isArray(type)){ - type.forEach(type => this.add(target, type, callback)) + type.forEach(type => this.add(target, type, callback, symbol)) return } this.remove(target, type) - var addedEvent = this.allEvents.get(target) + var addedEvent = this.allEvents.get(symbol || target) if(!addedEvent){ addedEvent = new Map() - this.allEvents.set(target, addedEvent) + this.allEvents.set(symbol || target, addedEvent) } addedEvent.set(type, callback) return target.addEventListener(type, callback) } - remove(target, type){ + remove(target, type, symbol){ if(Array.isArray(type)){ - type.forEach(type => this.remove(target, type)) + type.forEach(type => this.remove(target, type, symbol)) return } - var addedEvent = this.allEvents.get(target) + var addedEvent = this.allEvents.get(symbol || target) if(addedEvent){ var callback = addedEvent.get(type) if(callback){ target.removeEventListener(type, callback) addedEvent.delete(type) if(addedEvent.size == 0){ - return this.allEvents.delete(target) + return this.allEvents.delete(symbol || target) } } } } - once(target, type){ + once(target, type, symbol){ return new Promise(resolve => { this.add(target, type, event => { this.remove(target, type) return resolve(event) - }) + }, symbol) }) } race(){ + var symbols = [] var target = arguments[0] return new Promise(resolve => { for(var i = 1;i < arguments.length; i++){ + symbols[i] = Symbol() let type = arguments[i] this.add(target, type, event => { resolve({ type: type, event: event }) - }) + }, symbols[i]) } }).then(response => { for(var i = 1;i < arguments.length; i++){ - this.remove(target, arguments[i]) + this.remove(target, arguments[i], symbols[i]) } return response }) diff --git a/public/src/js/parsetja.js b/public/src/js/parsetja.js index 1cd996c..a6f94e2 100644 --- a/public/src/js/parsetja.js +++ b/public/src/js/parsetja.js @@ -149,6 +149,7 @@ var circles = [] var circleID = 0 var regexAZ = /[A-Z]/ + var regexSpace = /\s/ var isAllDon = (note_chain, start_pos) => { for (var i = start_pos; i < note_chain.length; ++i) { var note = note_chain[i]; @@ -470,7 +471,7 @@ bpm: bpm, scroll: scroll }) - }else{ + }else if(!regexSpace.test(symbol)){ error = true } break diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index 8a12ac7..4e5cca6 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -63,7 +63,8 @@ class Scoresheet{ assets.sounds["v_results"].play() assets.sounds["bgm_result"].playLoop(3, false, 0, 0.847, 17.689) - if(p2.session){ + this.session = p2.session + if(this.session){ if(p2.getMessage("songsel")){ this.toSongsel(true) } @@ -324,14 +325,15 @@ class Scoresheet{ var elapsed = 0 } - var gaugePercent = Math.round(this.results.gauge / 200) / 50 - var gaugeClear = [this.controller.game.rules.gaugeClear] + var rules = this.controller.game.rules + var gaugePercent = rules.gaugePercent(this.results.gauge) + var gaugeClear = [rules.gaugeClear] if(players === 2){ gaugeClear.push(this.controller.syncWith.game.rules.gaugeClear) } var failedOffset = gaugePercent >= gaugeClear[0] ? 0 : -2000 if(players === 2){ - var gauge2 = Math.round(p2.results.gauge / 200) / 50 + var gauge2 = this.controller.syncWith.game.rules.gaugePercent(p2.results.gauge) if(gauge2 > gaugePercent && failedOffset !== 0 && gauge2 >= gaugeClear[1]){ failedOffset = 0 } @@ -343,7 +345,8 @@ class Scoresheet{ if(p === 1){ results = p2.results } - var resultGauge = Math.round(results.gauge / 200) / 50 + var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules + var resultGauge = playerRules.gaugePercent(results.gauge) var clear = resultGauge >= gaugeClear[p] if(p === 1 || !this.multiplayer && clear){ ctx.translate(0, 290) @@ -368,8 +371,8 @@ class Scoresheet{ if(elapsed >= 0){ if(this.state.hasPointer === 0){ this.state.hasPointer = 1 - if(!this.state.pointerLocked && !p2.session){ - this.canvas.style.cursor = "pointer" + if(!this.state.pointerLocked){ + this.canvas.style.cursor = this.session ? "" : "pointer" } } ctx.save() @@ -578,7 +581,7 @@ class Scoresheet{ if(this.tetsuoHanaClass){ this.tetsuoHana.classList.remove(this.tetsuoHanaClass) } - this.tetsuoHanaClass = this.controller.game.rules.clearReached(this.results.gauge) ? "dance" : "failed" + this.tetsuoHanaClass = rules.clearReached(this.results.gauge) ? "dance" : "failed" this.tetsuoHana.classList.add(this.tetsuoHanaClass) } } @@ -597,26 +600,27 @@ class Scoresheet{ results = p2.results ctx.translate(0, p2Offset) } - var gaugePercent = Math.round(results.gauge / 200) / 50 + var gaugePercent = rules.gaugePercent(results.gauge) var w = 712 this.draw.gauge({ ctx: ctx, x: 558 + w, - y: 116, + y: p === 1 ? 124 : 116, clear: gaugeClear[p], percentage: gaugePercent, font: this.font, scale: w / 788, scoresheet: true, - blue: p === 1 + blue: p === 1, + multiplayer: p === 1 }) - var rules = p === 0 ? this.controller.game.rules : this.controller.syncWith.game.rules + var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules this.draw.soul({ ctx: ctx, x: 1215, y: 144, scale: 36 / 42, - cleared: rules.clearReached(results.gauge) + cleared: playerRules.clearReached(results.gauge) }) } }) @@ -634,8 +638,8 @@ class Scoresheet{ results = p2.results } var crownType = null - var rules = p === 0 ? this.controller.game.rules : this.controller.syncWith.game.rules - if(rules.clearReached(results.gauge)){ + var playerRules = p === 0 ? rules : this.controller.syncWith.game.rules + if(playerRules.clearReached(results.gauge)){ crownType = results.bad === "0" ? "gold" : "silver" } if(crownType !== null){ @@ -796,9 +800,13 @@ class Scoresheet{ ctx.restore() } - if(p2.session && !this.state.scoreNext && this.state.screen === "scoresShown" && ms - this.state.screenMS >= 10000){ + if(this.session && !this.state.scoreNext && this.state.screen === "scoresShown" && ms - this.state.screenMS >= 10000){ this.state.scoreNext = true - p2.send("songsel") + if(p2.session){ + p2.send("songsel") + }else{ + this.toSongsel(true) + } } if(this.state.screen === "fadeOut"){ @@ -861,7 +869,7 @@ class Scoresheet{ } saveScore(){ - if(!this.controller.autoPlayEnabled){ + if(this.controller.saveScore){ if(this.resultsObj.points < 0){ this.resultsObj.points = 0 } @@ -903,7 +911,7 @@ class Scoresheet{ if(this.multiplayer !== 2 && this.touchEnabled){ pageEvents.remove(document.getElementById("touch-full-btn"), "touchend") } - if(p2.session){ + if(this.session){ pageEvents.remove(p2, "message") } if(!this.multiplayer){ diff --git a/public/src/js/settings.js b/public/src/js/settings.js index c52dcd1..c9fed36 100644 --- a/public/src/js/settings.js +++ b/public/src/js/settings.js @@ -167,9 +167,29 @@ class SettingsView{ this.viewOuter.classList.add("touch-enabled") } this.touchEnd = [] - pageEvents.add(this.viewOuter, ["mouseup", "touchend"], event => { - this.touchEnd.forEach(func => func(event)) - }) + this.windowSymbol = Symbol() + this.touchMove = { + active: false, + x: 0, + y: 0 + } + pageEvents.add(window, ["mouseup", "touchstart", "touchmove", "touchend", "blur"], event => { + var move = this.touchMove + if(event.type === "touchstart"){ + var cursor = event.changedTouches[0] + move.active = false + move.x = cursor.pageX + move.y = cursor.pageY + }else if(event.type === "touchmove"){ + var cursor = event.changedTouches[0] + if (Math.abs(move.x - cursor.pageX) > 10 || Math.abs(move.y - cursor.pageY) > 10){ + move.active = true + } + }else{ + this.touchEnd.forEach(func => func(event)) + move.active = false + } + }, this.windowSymbol) var gamepadEnabled = false if("getGamepads" in navigator){ @@ -234,7 +254,7 @@ class SettingsView{ this.selected = this.items.length settingBox.classList.add("selected") } - this.addTouch(settingBox, event => this.setValue(i)) + this.addTouchEnd(settingBox, event => this.setValue(i)) this.items.push({ id: i, settingBox: settingBox, @@ -365,9 +385,10 @@ class SettingsView{ getElement(name){ return loader.screen.getElementsByClassName(name)[0] } - addTouch(element, callback){ - pageEvents.add(element, ["mousedown", "touchstart"], event => { - if(event.type === "touchstart"){ + addTouch(element, callback, end){ + var touchEvent = end ? "touchend" : "touchstart" + pageEvents.add(element, ["mousedown", touchEvent], event => { + if(event.type === touchEvent){ event.preventDefault() this.touched = true }else if(event.which !== 1){ @@ -375,9 +396,14 @@ class SettingsView{ }else{ this.touched = false } - callback(event) + if(event.type !== "touchend" || !this.touchMove.active){ + callback(event) + } }) } + addTouchEnd(element, callback){ + this.addTouch(element, callback, true) + } addTouchRepeat(element, callback){ this.addTouch(element, event => { var active = true @@ -398,6 +424,9 @@ class SettingsView{ removeTouch(element){ pageEvents.remove(element, ["mousedown", "touchstart"]) } + removeTouchEnd(element){ + pageEvents.remove(element, ["mousedown", "touchend"]) + } getValue(name, valueDiv){ var current = settings.items[name] var value = settings.getItem(name) @@ -879,9 +908,9 @@ class SettingsView{ this.keyboard.clean() this.gamepad.clean() assets.sounds["bgm_settings"].stop() - pageEvents.remove(this.viewOuter, ["mouseup", "touchend"]) + pageEvents.remove(window, ["mouseup", "touchstart", "touchmove", "touchend", "blur"], this.windowSymbol) for(var i in this.items){ - this.removeTouch(this.items[i].settingBox) + this.removeTouchEnd(this.items[i].settingBox) } for(var i in this.latencyItems){ this.removeTouch(this.latencyItems[i].settingBox) @@ -899,6 +928,8 @@ class SettingsView{ this.removeTouch(this.latencySettings) this.removeTouch(this.latencyDefaultButton) this.removeTouch(this.latencyEndButton) + delete this.windowSymbol + delete this.touchMove delete this.viewOuter delete this.touchEnd delete this.tutorialTitle diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 6bc9d16..85df8db 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -608,18 +608,25 @@ class SongSelect{ this.pointer(false) } } - - categoryJump(moveBy){ - if(this.state.locked === 1){ - return + + categoryJump(moveBy, fromP2){ + if(p2.session && !fromP2){ + var ms = this.getMS() + if(!this.state.selLock && ms > this.state.moveMS + 800){ + this.state.selLock = true + p2.send("catjump", { + song: this.selectedSong, + move: moveBy + }) + } + }else if(this.state.locked !== 1 || fromP2){ + this.state.catJump = true + this.state.move = moveBy; + this.state.locked = 1 + + this.endPreview() + this.playSound("se_jump") } - - this.state.catJump = true - this.state.move = moveBy; - this.state.locked = 1 - - this.endPreview() - this.playSound("se_jump") } moveToDiff(moveBy){ @@ -925,7 +932,7 @@ class SongSelect{ } this.selectableText = "" - }else if(!document.hasFocus()){ + }else if(!document.hasFocus() && !p2.session){ this.pointer(false) return }else{ @@ -1128,7 +1135,15 @@ class SongSelect{ disabled: p2.session && this.songs[index].action && this.songs[index].action !== "random" }) } + var startFrom for(var i = this.selectedSong + 1; ; i++){ + var _x = winW / 2 + (i - this.selectedSong - 1) * (this.songAsset.width + this.songAsset.marginLeft) + this.songAsset.marginLeft + selectedWidth / 2 + xOffset + if(_x > winW){ + startFrom = i - 1 + break + } + } + for(var i = startFrom; i > this.selectedSong ; i--){ var highlight = 0 if(i - this.selectedSong === this.state.moveHover){ highlight = 1 @@ -1136,9 +1151,6 @@ class SongSelect{ var index = this.mod(this.songs.length, i) var currentSong = this.songs[index] var _x = winW / 2 + (i - this.selectedSong - 1) * (this.songAsset.width + this.songAsset.marginLeft) + this.songAsset.marginLeft + selectedWidth / 2 + xOffset - if(_x > winW){ - break - } this.drawClosedSong({ ctx: ctx, x: _x, @@ -1150,6 +1162,43 @@ class SongSelect{ } } + var currentSong = this.songs[this.selectedSong] + var highlight = 0 + if(!currentSong.stars){ + highlight = 2 + } + if(this.state.moveHover === 0){ + highlight = 1 + } + var selectedSkin = this.songSkin.selected + if(screen === "title" || screen === "titleFadeIn" || this.state.locked === 3){ + selectedSkin = currentSong.skin + highlight = 2 + }else if(songSelMoving){ + selectedSkin = currentSong.skin + highlight = 0 + } + var selectedHeight = this.songAsset.height + if(screen === "difficulty"){ + selectedWidth = this.songAsset.fullWidth + selectedHeight = this.songAsset.fullHeight + highlight = 0 + } + + if(this.currentSongTitle !== currentSong.title){ + this.currentSongTitle = currentSong.title + this.currentSongCache.clear() + } + + if(ms > this.state.screenMS + 2000 && selectedWidth === this.songAsset.width){ + this.drawSongCrown({ + ctx: ctx, + song: currentSong, + x: winW / 2 - selectedWidth / 2 + xOffset, + y: songTop + this.songAsset.height - selectedHeight + }) + } + if(screen === "title" || screen === "titleFadeIn" || screen === "song"){ var textW = strings.id === "en" ? 350 : 280 this.selectTextCache.get({ @@ -1230,35 +1279,7 @@ class SongSelect{ }) } - var currentSong = this.songs[this.selectedSong] - var highlight = 0 - if(!currentSong.stars){ - highlight = 2 - } - if(this.state.moveHover === 0){ - highlight = 1 - } - var selectedSkin = this.songSkin.selected - if(screen === "title" || screen === "titleFadeIn" || this.state.locked === 3){ - selectedSkin = currentSong.skin - highlight = 2 - }else if(songSelMoving){ - selectedSkin = currentSong.skin - highlight = 0 - } - var selectedHeight = this.songAsset.height - if(screen === "difficulty"){ - selectedWidth = this.songAsset.fullWidth - selectedHeight = this.songAsset.fullHeight - highlight = 0 - } - - if(this.currentSongTitle !== currentSong.title){ - this.currentSongTitle = currentSong.title - this.currentSongCache.clear() - } - - if(selectedWidth === this.songAsset.width){ + if(ms <= this.state.screenMS + 2000 && selectedWidth === this.songAsset.width){ this.drawSongCrown({ ctx: ctx, song: currentSong, @@ -1398,7 +1419,7 @@ class SongSelect{ } var drawDifficulty = (ctx, i, currentUra) => { if(currentSong.stars[i] || currentUra){ - var score = scoreStorage.get(currentSong.hash) + var score = scoreStorage.get(currentSong.hash, false, true) var crownDiff = currentUra ? "ura" : this.difficultyId[i] var crownType = "" if(score && score[crownDiff]){ @@ -1585,6 +1606,8 @@ class SongSelect{ alphaFade = this.draw.easeIn((fade - 0.45) * 20) } this.draw.alpha(alphaFade, ctx, ctx => { + ctx.fillStyle = this.songSkin.selected.background + ctx.fillRect(x + 7 + i * 60, y + 60, 52, 352) drawDifficulty(ctx, i, true) }, winW, winH) }else{ @@ -1990,7 +2013,7 @@ class SongSelect{ drawSongCrown(config){ if(!config.song.action && config.song.hash){ var ctx = config.ctx - var score = scoreStorage.get(config.song.hash) + var score = scoreStorage.get(config.song.hash, false, true) for(var i = this.difficultyId.length; i--;){ var diff = this.difficultyId[i] if(!score){ @@ -2140,13 +2163,19 @@ class SongSelect{ onsongsel(response){ if(response && response.value){ var selected = false - if("selected" in response.value){ + if(response.type === "songsel" && "selected" in response.value){ selected = response.value.selected } if("song" in response.value){ var song = +response.value.song if(song >= 0 && song < this.songs.length){ - if(!selected){ + if(response.type === "catjump"){ + var moveBy = response.value.move + if(moveBy === -1 || moveBy === 1){ + this.selectedSong = song + this.categoryJump(moveBy, true) + } + }else if(!selected){ this.state.locked = true if(this.state.screen === "difficulty"){ this.toSongSelect(true) @@ -2174,6 +2203,16 @@ class SongSelect{ } } } + oncatjump(response){ + if(response && response.value){ + if("song" in response.value){ + var song = +response.value.song + if(song >= 0 && song < this.songs.length){ + this.state.locked = true + } + } + } + } startP2(){ this.onusers(p2.getMessage("users")) if(p2.session){ @@ -2183,7 +2222,7 @@ class SongSelect{ if(response.type == "users"){ this.onusers(response) } - if(p2.session && response.type == "songsel"){ + if(p2.session && (response.type == "songsel" || response.type == "catjump")){ this.onsongsel(response) this.state.selLock = false } diff --git a/public/src/js/strings.js b/public/src/js/strings.js index 2b76c46..17986fc 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -86,6 +86,7 @@ this.maxCombo = "最大コンボ数" this.drumroll = "連打数" + this.errorOccured = "エラーが発生しました。再読み込みしてください。" this.tutorial = { basics: [ "流れてくる音符がワクに重なったらバチで太鼓をたたこう!", @@ -109,7 +110,8 @@ "Gitリポジトリかメールでバグを報告してください。" ], diagnosticWarning: "以下の端末診断情報も併せて報告してください!", - issueTemplate: "###### 下記の問題を説明してください。 スクリーンショットと診断情報を含めてください。" + issueTemplate: "###### 下記の問題を説明してください。 スクリーンショットと診断情報を含めてください。", + issues: "課題" } this.session = { multiplayerSession: "オンラインセッション", @@ -281,6 +283,7 @@ function StringsEn(){ this.maxCombo = "MAX Combo" this.drumroll = "Drumroll" + this.errorOccured = "An error occurred, please refresh" this.tutorial = { basics: [ "When a note overlaps the frame, that is your cue to hit the drum!", @@ -304,7 +307,8 @@ function StringsEn(){ "You can report bugs either via our Git repository or email." ], diagnosticWarning: "Be sure to include the following diagnostic data!", - issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information." + issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information.", + issues: "Issues" } this.session = { multiplayerSession: "Multiplayer Session", @@ -426,10 +430,10 @@ function StringsCn(){ this.hard = "困难" this.oni = "魔王" this.songBranch = "有谱面分歧" - this.sessionStart = "开始在线会话!" + this.sessionStart = "开始在线会话!" this.sessionEnd = "结束在线会话" this.loading = "加载中..." - this.waitingForP2 = "Waiting for Another Player..." + this.waitingForP2 = "正在等待对方玩家..." this.cancel = "取消" this.note = { don: "咚", @@ -476,6 +480,7 @@ function StringsCn(){ this.maxCombo = "最多连段数" this.drumroll = "连打数" + this.errorOccured = "An error occurred, please refresh" this.tutorial = { basics: [ "当流动的音符将与框框重叠时就用鼓棒敲打太鼓吧", @@ -499,11 +504,12 @@ function StringsCn(){ "You can report bugs either via our Git repository or email." ], diagnosticWarning: "Be sure to include the following diagnostic data!", - issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information." + issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information.", + issues: "工单" } this.session = { - multiplayerSession: "Multiplayer Session", - linkTutorial: "Share this link with your friend to start playing together! Do not leave this screen while they join.", + multiplayerSession: "在线会话", + linkTutorial: "复制下方地址,给你的朋友即可开始一起游戏!当他们与您联系之前,请不要离开此页面。", cancel: "取消" } this.settings = { @@ -624,7 +630,7 @@ function StringsTw(){ this.sessionStart = "開始多人模式!" this.sessionEnd = "結束多人模式" this.loading = "讀取中..." - this.waitingForP2 = "Waiting for Another Player..." + this.waitingForP2 = "正在等待對方玩家..." this.cancel = "取消" this.note = { don: "咚", @@ -671,6 +677,7 @@ function StringsTw(){ this.maxCombo = "最多連段數" this.drumroll = "連打數" + this.errorOccured = "An error occurred, please refresh" this.tutorial = { basics: [ "當流動的音符將與框框重疊時就用鼓棒敲打太鼓吧", @@ -694,11 +701,12 @@ function StringsTw(){ "You can report bugs either via our Git repository or email." ], diagnosticWarning: "Be sure to include the following diagnostic data!", - issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information." + issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information.", + issues: "問題" } this.session = { - multiplayerSession: "Multiplayer Session", - linkTutorial: "Share this link with your friend to start playing together! Do not leave this screen while they join.", + multiplayerSession: "多人模式", + linkTutorial: "複製下方地址,給你的朋友即可開始一起遊戲!當他們與您聯繫之前,請不要離開此頁面。", cancel: "取消" } this.settings = { @@ -866,6 +874,7 @@ function StringsKo(){ this.maxCombo = "최대 콤보 수" this.drumroll = "연타 횟수" + this.errorOccured = "An error occurred, please refresh" this.tutorial = { basics: [ "이동하는 음표가 테두리와 겹쳐졌을 때 북채로 태고를 두드리자!", @@ -889,7 +898,8 @@ function StringsKo(){ "You can report bugs either via our Git repository or email." ], diagnosticWarning: "Be sure to include the following diagnostic data!", - issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information." + issueTemplate: "###### Describe the problem you are having below. Please include a screenshot and the diagnostic information.", + issues: "이슈" } this.session = { multiplayerSession: "Multiplayer Session", diff --git a/public/src/js/view.js b/public/src/js/view.js index 8c1e4d1..20828e6 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -348,7 +348,7 @@ } var score = this.controller.getGlobalScore() - var gaugePercent = Math.round(score.gauge / 200) / 50 + var gaugePercent = this.rules.gaugePercent(score.gauge) if(this.multiplayer === 2){ var scoreImg = "bg_score_p2" diff --git a/public/src/views/about.html b/public/src/views/about.html index 37e0c74..ae18ed6 100644 --- a/public/src/views/about.html +++ b/public/src/views/about.html @@ -4,8 +4,8 @@
-