diff --git a/public/src/css/loader.css b/public/src/css/loader.css index 306ced8..de0e97d 100644 --- a/public/src/css/loader.css +++ b/public/src/css/loader.css @@ -17,7 +17,6 @@ body{ background-color: #000; background-position: top center; background-size: 30vh; - font-family: TnT, Meiryo, sans-serif; } #screen.pattern-bg{ background-color: #fe7839; diff --git a/public/src/css/titlescreen.css b/public/src/css/titlescreen.css index 0cced4c..55b6921 100644 --- a/public/src/css/titlescreen.css +++ b/public/src/css/titlescreen.css @@ -41,5 +41,50 @@ .click-to-continue::before{ -webkit-text-stroke: 0.25em #f00; filter: blur(0.3vmin); - left: auto; +} +#lang{ + font-size: 3vmin; + position: absolute; + bottom: 0; + left: 0; + width: 7em; + height: 4em; + color: #000; +} +#lang:focus-within{ + outline: #4d90fe auto 5px; +} +#lang-dropdown{ + font-size: 1.7em; + font-family: Microsoft YaHei, sans-serif; + opacity: 0; + width: 100%; + height: 100%; + color: #000; + cursor: pointer; +} +#lang-id{ + position: absolute; + top: 0; + bottom: 0; + left: 2.6em; + font-family: TnT, Meiryo, sans-serif; + font-size: 1.5em; + font-weight: normal; + color: #fff; + line-height: 2.75em; + z-index: 0; +} +#lang-icon{ + position: absolute; + width: 2.8em; + height: 2.8em; + padding: 0.6em; + fill: currentColor; +} +#lang:hover #lang-icon{ + color: #f00; +} +#lang:hover #lang-id::before { + -webkit-text-stroke: 0.25em #f00; } diff --git a/public/src/js/assets.js b/public/src/js/assets.js index 89097f8..91eb0fa 100644 --- a/public/src/js/assets.js +++ b/public/src/js/assets.js @@ -48,11 +48,7 @@ var assets = { "taiko.png", "dancing-don.gif", "bg-pattern-1.png", - "muzu_easy.png", - "muzu_normal.png", - "muzu_hard.png", - "muzu_oni.png", - "muzu_ura.png", + "difficulty.png", "don_anim_normal.png", "don_anim_10combo.png", "don_anim_gogo.png", diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index 48e3bbb..c141b91 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -285,6 +285,7 @@ inputText = inputText.slice(0, matches.index) ura = matches[0] } + var bold = this.bold(config.fontFamily) var string = inputText.split("") var drawn = [] @@ -296,30 +297,56 @@ drawn.push({text: symbol, x: 0, y: 0, h: 18}) }else if(symbol === "ー"){ // Long-vowel mark - drawn.push({realText: symbol, svg: this.longVowelMark, x: -4, y: 5, h: 33, scale: [mul, mul]}) + if(bold){ + drawn.push({text: symbol, x: -1, y: -1, h: 33, rotate: true}) + }else{ + drawn.push({realText: symbol, svg: this.longVowelMark, x: -4, y: 5, h: 33, scale: [mul, mul]}) + } }else if(symbol === "∀"){ drawn.push({text: symbol, x: 0, y: 0, h: 39, rotate: true}) }else if(symbol === "↓"){ drawn.push({text: symbol, x: 0, y: 12, h: 45}) }else if(symbol === "."){ - drawn.push({realText: symbol, text: ".", x: 13, y: -7, h: 15, scale: [1.2, 0.7]}) + if(bold){ + drawn.push({realText: symbol, text: ".", x: 13, y: -15, h: 15}) + }else{ + drawn.push({realText: symbol, text: ".", x: 13, y: -7, h: 15, scale: [1.2, 0.7]}) + } }else if(symbol === "…"){ - drawn.push({text: symbol, x: 0, y: 5, h: 25, rotate: true}) + drawn.push({text: symbol, x: bold ? 9 : 0, y: 5, h: 25, rotate: true}) + }else if(symbol === '"'){ + drawn.push({text: symbol, x: 0, y: 5, h: 20, rotate: true}) }else if(r.comma.test(symbol)){ // Comma, full stop - drawn.push({text: symbol, x: 13, y: -7, h: 15, scale: [1.2, 0.7]}) + if(bold){ + drawn.push({text: symbol, x: 13, y: -15, h: 15}) + }else{ + drawn.push({text: symbol, x: 13, y: -7, h: 15, scale: [1.2, 0.7]}) + } }else if(r.ideographicComma.test(symbol)){ // Ideographic comma, full stop drawn.push({text: symbol, x: 16, y: -16, h: 18}) }else if(r.apostrophe.test(symbol)){ // Apostrophe - drawn.push({realText: symbol, text: ",", x: 20, y: -39, h: 0, scale: [1.2, 0.7]}) + if(bold){ + drawn.push({text: symbol, x: 20, y: -25, h: 0}) + }else{ + drawn.push({realText: symbol, text: ",", x: 20, y: -39, h: 0, scale: [1.2, 0.7]}) + } }else if(r.degree.test(symbol)){ // Degree - drawn.push({text: symbol, x: 16, y: 3, h: 18}) + if(bold){ + drawn.push({text: symbol, x: 16, y: 9, h: 25}) + }else{ + drawn.push({text: symbol, x: 16, y: 3, h: 18}) + } }else if(r.brackets.test(symbol)){ // Rotated brackets - drawn.push({text: symbol, x: 0, y: -5, h: 25, rotate: true}) + if(bold){ + drawn.push({text: symbol, x: 0, y: 0, h: 35, rotate: true}) + }else{ + drawn.push({text: symbol, x: 0, y: -5, h: 25, rotate: true}) + } }else if(r.tilde.test(symbol)){ // Rotated hyphen, tilde drawn.push({realText: symbol, text: symbol === "~" ? "~" : symbol, x: 0, y: 2, h: 35, rotate: true}) @@ -448,7 +475,7 @@ actions.push("selectable") } for(let action of actions){ - ctx.font = config.fontSize + "px " + config.fontFamily + ctx.font = bold + config.fontSize + "px " + config.fontFamily ctx.textBaseline = "top" if(action === "stroke"){ ctx.strokeStyle = config.outline @@ -571,6 +598,7 @@ inputText = inputText.slice(0, matches.index) ura = matches[0] } + var bold = this.bold(config.fontFamily) var string = inputText.split("") var drawn = [] @@ -587,12 +615,20 @@ }else if(symbol === "'"){ drawn.push({text: ",", x: 0, y: -15, w: 7, scale: [1, 0.7]}) }else if(symbol === "∀"){ - drawn.push({text: symbol, x: -3, y: 0, w: 55}) + if(bold){ + drawn.push({text: symbol, x: 0, y: 0, w: 40}) + }else{ + drawn.push({text: symbol, x: -3, y: 0, w: 55}) + } }else if(symbol === "."){ drawn.push({text: symbol, x: -9, y: 0, w: 37}) }else if(r.comma.test(symbol)){ // Comma, full stop - drawn.push({text: symbol, x: -3, y: 13, w: 13, scale: [1.2, 0.7]}) + if(bold){ + drawn.push({text: symbol, x: -3, y: 0, w: 13}) + }else{ + drawn.push({text: symbol, x: -3, y: 13, w: 13, scale: [1.2, 0.7]}) + } }else if(r.en.test(symbol)){ // n-width drawn.push({text: symbol, x: 0, y: 0, w: 28}) @@ -614,7 +650,11 @@ drawn.push({text: number, x: 0, y: 0, w: 32}) }else if(r.degree.test(symbol)){ // Degree - drawn.push({text: symbol, x: 5, y: 0, w: 0}) + if(bold){ + drawn.push({text: symbol, x: 0, y: 0, w: 20}) + }else{ + drawn.push({text: symbol, x: 5, y: 0, w: 0}) + } }else if(r.uppercase.test(symbol)){ // Latin script uppercase drawn.push({text: symbol, x: 0, y: 0, w: 32}) @@ -668,7 +708,7 @@ drawn.reverse() } - ctx.font = config.fontSize + "px " + config.fontFamily + ctx.font = bold + config.fontSize + "px " + config.fontFamily ctx.textBaseline = config.baseline || "top" ctx.textAlign = "center" @@ -965,32 +1005,65 @@ if(config.scale){ ctx.scale(config.scale, config.scale) } - if(config.align === "center"){ - ctx.translate(config.score === "bad" ? -49 / 2 : -23 / 2, 0) - } ctx.strokeStyle = "#000" ctx.lineWidth = 7 - if(config.score === "good"){ - var grd = ctx.createLinearGradient(0, 0, 0, 29) - grd.addColorStop(0.3, "#f7fb00") - grd.addColorStop(0.9, "#ff4900") - ctx.fillStyle = grd - ctx.stroke(this.diffPath.good) - ctx.fill(this.diffPath.good) - }else if(config.score === "ok"){ - ctx.fillStyle = "#fff" - ctx.stroke(this.diffPath.ok) - ctx.fill(this.diffPath.ok) - }else if(config.score === "bad"){ - var grd = ctx.createLinearGradient(0, 0, 0, 27) - grd.addColorStop(0.1, "#6B5DFF") - grd.addColorStop(0.7, "#00AEDE") - ctx.fillStyle = grd - ctx.stroke(this.diffPath.bad) - ctx.fill(this.diffPath.bad) - ctx.translate(26, 0) - ctx.stroke(this.diffPath.ok) - ctx.fill(this.diffPath.ok) + if(strings.good === "良"){ + if(config.align === "center"){ + ctx.translate(config.score === "bad" ? -49 / 2 : -23 / 2, 0) + } + if(config.score === "good"){ + var grd = ctx.createLinearGradient(0, 0, 0, 29) + grd.addColorStop(0.3, "#f7fb00") + grd.addColorStop(0.9, "#ff4900") + ctx.fillStyle = grd + ctx.stroke(this.diffPath.good) + ctx.fill(this.diffPath.good) + }else if(config.score === "ok"){ + ctx.fillStyle = "#fff" + ctx.stroke(this.diffPath.ok) + ctx.fill(this.diffPath.ok) + }else if(config.score === "bad"){ + var grd = ctx.createLinearGradient(0, 0, 0, 27) + grd.addColorStop(0.1, "#6B5DFF") + grd.addColorStop(0.7, "#00AEDE") + ctx.fillStyle = grd + ctx.stroke(this.diffPath.bad) + ctx.fill(this.diffPath.bad) + ctx.translate(26, 0) + ctx.stroke(this.diffPath.ok) + ctx.fill(this.diffPath.ok) + } + }else{ + ctx.font = this.bold(strings.font) + "26px " + strings.font + if(config.results){ + ctx.textAlign = "left" + }else{ + ctx.textAlign = "center" + } + ctx.textBaseline = "top" + ctx.miterLimit = 1 + if(config.score === "good"){ + if(config.results && strings.id === "en"){ + ctx.scale(0.75, 1) + } + var grd = ctx.createLinearGradient(0, 0, 0, 29) + grd.addColorStop(0.3, "#f7fb00") + grd.addColorStop(0.9, "#ff4900") + ctx.fillStyle = grd + ctx.strokeText(strings.good, 0, 4) + ctx.fillText(strings.good, 0, 4) + }else if(config.score === "ok"){ + ctx.fillStyle = "#fff" + ctx.strokeText(strings.ok, 0, 4) + ctx.fillText(strings.ok, 0, 4) + }else if(config.score === "bad"){ + var grd = ctx.createLinearGradient(0, 0, 0, 27) + grd.addColorStop(0.1, "#6B5DFF") + grd.addColorStop(0.7, "#00AEDE") + ctx.fillStyle = grd + ctx.strokeText(strings.bad, 0, 4) + ctx.fillText(strings.bad, 0, 4) + } } ctx.restore() } @@ -1252,6 +1325,10 @@ } } + bold(font){ + return font === "Microsoft YaHei, sans-serif" ? "bold " : "" + } + getMS(){ return Date.now() } diff --git a/public/src/js/main.js b/public/src/js/main.js index 7176140..aa21888 100644 --- a/public/src/js/main.js +++ b/public/src/js/main.js @@ -80,9 +80,10 @@ var perf = { allImg: 0, load: 0 } +var strings pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => { - if(event.cancelable && cancelTouch){ + if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){ event.preventDefault() } }) diff --git a/public/src/js/parseosu.js b/public/src/js/parseosu.js index 0039bd8..336bc70 100644 --- a/public/src/js/parseosu.js +++ b/public/src/js/parseosu.js @@ -319,10 +319,10 @@ class ParseOsu{ if(hitSound & this.osu.FINISH){ if(hitSound & this.osu.WHISTLE || hitSound & this.osu.CLAP){ type = "daiKa" - txt = "カッ(大)" + txt = strings.note.daiKa }else if(hitSound & this.osu.NORMAL || hitSound === this.osu.FINISH){ type = "daiDon" - txt = "ドン(大)" + txt = strings.note.daiDon }else{ emptyValue = true } diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js index d0ed61e..de3dd44 100644 --- a/public/src/js/scoresheet.js +++ b/public/src/js/scoresheet.js @@ -16,7 +16,8 @@ class Scoresheet{ this.fadeScreen.id = "fade-screen" this.game.appendChild(this.fadeScreen) - this.font = "TnT, Meiryo, sans-serif" + this.font = strings.font + this.numbersFont = "TnT, Meiryo, sans-serif" this.state = { screen: "fadeIn", screenMS: this.getMS(), @@ -34,6 +35,14 @@ class Scoresheet{ "13": ["a", "b", "start", "ls", "rs"] }) + this.difficulty = { + "easy": 0, + "normal": 1, + "hard": 2, + "oni": 3, + "ura": 4 + } + this.redrawRunning = true this.redrawBind = this.redraw.bind(this) this.redraw() @@ -403,9 +412,10 @@ class Scoresheet{ ctx.translate(0, p2Offset) } - var imgScale = 1.35 - ctx.drawImage(assets.image["muzu_" + results.difficulty], - 276, 150, imgScale * 176, imgScale * 120 + ctx.drawImage(assets.image["difficulty"], + 0, 144 * this.difficulty[results.difficulty], + 168, 143, + 300, 150, 189, 162 ) if(this.controller.autoPlayEnabled){ @@ -454,31 +464,40 @@ class Scoresheet{ }) ctx.fillStyle = "#000" ctx.fill() - ctx.font = "36px " + this.font - ctx.textAlign = "right" - ctx.fillStyle = "#fff" - ctx.strokeStyle = "#000" - ctx.lineWidth = 0.5 - ctx.fillText(strings.points, 788, 284) - ctx.strokeText(strings.points, 788, 284) + this.draw.layeredText({ + ctx: ctx, + text: strings.points, + x: 792, + y: strings.id === "ko" ? 260 : 253, + fontSize: 36, + fontFamily: this.font, + align: "right", + width: 36 + }, [ + {fill: "#fff"}, + {outline: "#000", letterBorder: 0.5} + ]) this.draw.score({ ctx: ctx, score: "good", x: 823, - y: 192 + y: 192, + results: true }) this.draw.score({ ctx: ctx, score: "ok", x: 823, - y: 233 + y: 233, + results: true }) this.draw.score({ ctx: ctx, score: "bad", x: 823, - y: 273 + y: 273, + results: true }) ctx.textAlign = "right" @@ -494,7 +513,7 @@ class Scoresheet{ fontFamily: this.font, align: "right", width: 154, - letterSpacing: 1 + letterSpacing: strings.id === "ja" ? 1 : 0 }, [ {outline: "#000", letterBorder: 8}, {fill: grd} @@ -506,8 +525,9 @@ class Scoresheet{ y: 233, fontSize: 29, fontFamily: this.font, - letterSpacing: 4, - align: "right" + align: "right", + width: 154, + letterSpacing: strings.id === "ja" ? 4 : 0 }, [ {outline: "#000", letterBorder: 8}, {fill: "#ffc700"} @@ -682,7 +702,7 @@ class Scoresheet{ var points = this.getNumber(results.points, 3100 + noCrownResultWait, elapsed) var scale = 1.3 - ctx.font = "35px " + this.font + ctx.font = "35px " + this.numbersFont ctx.translate(760, 286) ctx.scale(1 / scale, 1 * 1.1) ctx.textAlign = "center" @@ -714,7 +734,7 @@ class Scoresheet{ x: 971 + 270 * Math.floor(i / 3), y: 196 + (40 * (i % 3)), fontSize: 26, - fontFamily: this.font, + fontFamily: this.numbersFont, letterSpacing: 1, align: "right" }, [ diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index c011a63..e235250 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -90,14 +90,15 @@ class SongSelect{ outline: "#656565" } } - this.font = "TnT, Meiryo, sans-serif" + this.font = strings.font this.songs = [] for(let song of assets.songs){ + var en = strings.id === "en" this.songs.push({ id: song.id, - title: song.title, - subtitle: song.subtitle, + title: en ? song.title_en : song.title, + subtitle: en ? song.subtitle_en : song.subtitle, skin: song.category in this.songSkin ? this.songSkin[song.category] : this.songSkin.default, stars: song.stars, category: song.category, @@ -793,7 +794,8 @@ class SongSelect{ ratio + 0.2 ) - this.selectTextCache.resize((280 + 53 + 60 + 1) * 2, this.songAsset.marginTop + 15, ratio + 0.5) + var textW = strings.id === "en" ? 350 : 280 + this.selectTextCache.resize((textW + 53 + 60 + 1) * 2, this.songAsset.marginTop + 15, ratio + 0.5) var categories = 0 var lastCategory @@ -871,11 +873,12 @@ class SongSelect{ } if(screen === "title" || screen === "titleFadeIn" || screen === "song"){ + var textW = strings.id === "en" ? 350 : 280 this.selectTextCache.get({ ctx: ctx, x: frameLeft, y: frameTop, - w: 280 + 53 + 60, + w: textW + 53 + 60, h: this.songAsset.marginTop + 15, id: "song" }, ctx => { @@ -886,6 +889,7 @@ class SongSelect{ fontFamily: this.font, x: 53, y: 30, + width: textW, letterSpacing: 2, forceShadow: true }, [ @@ -1089,8 +1093,7 @@ class SongSelect{ highlight = 0 } - if(this.currentSongId !== currentSong.id || this.currentSongTitle !== currentSong.title){ - this.currentSongId = currentSong.id + if(this.currentSongTitle !== currentSong.title){ this.currentSongTitle = currentSong.title this.currentSongCache.clear() } @@ -1117,11 +1120,12 @@ class SongSelect{ var opened = ((selectedWidth - this.songAsset.width) / (this.songAsset.selectedWidth - this.songAsset.width)) var songSel = true }else{ + var textW = strings.id === "en" ? 350 : 280 this.selectTextCache.get({ ctx: ctx, x: x - 144 - 53, y: y - 24 - 30, - w: 280 + 53 + 60, + w: textW + 53 + 60, h: this.songAsset.marginTop + 15, id: "difficulty" }, ctx => { @@ -1132,7 +1136,7 @@ class SongSelect{ fontFamily: this.font, x: 53, y: 30, - width: 280, + width: textW, forceShadow: true }, [ {x: -2, y: -2, outline: "#000", letterBorder: 23}, @@ -1279,15 +1283,16 @@ class SongSelect{ h: (songSel ? 88 : 135) + 10, id: this.difficulty[currentUra ? 4 : i] + (songSel ? "1" : "0") }, ctx => { + var ja = strings.id === "ja" this.draw.verticalText({ ctx: ctx, text: this.difficulty[i], x: offset, y: 0, width: songSel ? 44 : 56, - height: songSel ? (i === 1 ? 66 : 88) : (i === 0 ? 130 : (i === 1 ? 110 : 135)), + height: songSel ? (i === 1 && ja ? 66 : 88) : (ja ? 130 : (i === 1 && ja ? 110 : 135)), fill: currentUra ? "#fff" : "#000", - fontSize: songSel ? 25 : (i === 2 ? 45 : 40), + fontSize: songSel ? 25 : (i === 2 && ja ? 45 : 40), fontFamily: this.font, outline: currentUra ? "#003C52" : false, outlineSize: currentUra ? this.songAsset.letterBorder : 0 diff --git a/public/src/js/strings.js b/public/src/js/strings.js index b1ed85b..9c13e70 100644 --- a/public/src/js/strings.js +++ b/public/src/js/strings.js @@ -1,55 +1,312 @@ -class StringsJa{ - constructor(){ - this.titleProceed = "Click or Press Enter!" - this.categories = { - "J-POP": "J-POP", - "アニメ": "アニメ", - "ボーカロイド™曲": "ボーカロイド™曲", - "バラエティ": "バラエティ", - "クラシック": "クラシック", - "ゲームミュージック": "ゲームミュージック", - "ナムコオリジナル": "ナムコオリジナル" - } - this.selectSong = "曲をえらぶ" - this.selectDifficulty = "むずかしさをえらぶ" - this.back = "もどる" - this.random = "ランダム" - this.randomSong = "ランダムに曲をえらぶ" - this.tutorial = "あそびかた説明" - this.aboutSimulator = "このシミュレータについて" - this.browse = "参照する…" - this.defaultSongList = "デフォルト曲リスト" - this.songOptions = "演奏オプション" - this.none = "なし" - this.auto = "オート" - this.netplay = "ネットプレイ" - this.easy = "かんたん" - this.normal = "ふつう" - this.hard = "むずかしい" - this.oni = "おに" - this.sessionStart = "オンラインセッションを開始する!" - this.sessionEnd = "オンラインセッションを終了する" - this.loading = "Loading..." - this.cancel = "Cancel" - this.note = { - don: "ドン", - ka: "カッ", - daiDon: "ドン(大)", - daiKa: "カッ(大)", - drumroll: "連打ーっ!!", - daiDrumroll: "連打(大)ーっ!!", - balloon: "ふうせん" - } - this.clear = "クリア" - this.pauseOptions = [ - "演奏をつづける", - "はじめからやりなおす", - "「曲をえらぶ」にもどる" - ] - this.results = "成績発表" - this.points = "点" - this.maxCombo = "最大コンボ数" - this.drumroll = "連打数" +function StringsJa(){ + this.id = "ja" + this.name = "日本語" + this.regex = /^ja$/ + this.font = "TnT, Meiryo, sans-serif" + + this.titleProceed = "クリックするかEnterを押す!" + this.categories = { + "J-POP": "J-POP", + "アニメ": "アニメ", + "ボーカロイド™曲": "ボーカロイド™曲", + "バラエティ": "バラエティ", + "クラシック": "クラシック", + "ゲームミュージック": "ゲームミュージック", + "ナムコオリジナル": "ナムコオリジナル" } + this.selectSong = "曲をえらぶ" + this.selectDifficulty = "むずかしさをえらぶ" + this.back = "もどる" + this.random = "ランダム" + this.randomSong = "ランダムに曲をえらぶ" + this.tutorial = "あそびかた説明" + this.aboutSimulator = "このシミュレータについて" + this.browse = "参照する…" + this.defaultSongList = "デフォルト曲リスト" + this.songOptions = "演奏オプション" + this.none = "なし" + this.auto = "オート" + this.netplay = "ネットプレイ" + this.easy = "かんたん" + this.normal = "ふつう" + this.hard = "むずかしい" + this.oni = "おに" + this.sessionStart = "オンラインセッションを開始する!" + this.sessionEnd = "オンラインセッションを終了する" + this.loading = "ロード中..." + this.cancel = "キャンセル" + this.note = { + don: "ドン", + ka: "カッ", + daiDon: "ドン(大)", + daiKa: "カッ(大)", + drumroll: "連打ーっ!!", + daiDrumroll: "連打(大)ーっ!!", + balloon: "ふうせん" + } + this.combo = "コンボ" + this.clear = "クリア" + this.good = "良" + this.ok = "可" + this.bad = "不可" + this.pauseOptions = [ + "演奏をつづける", + "はじめからやりなおす", + "「曲をえらぶ」にもどる" + ] + this.results = "成績発表" + this.points = "点" + this.maxCombo = "最大コンボ数" + this.drumroll = "連打数" +} +function StringsEn(){ + this.id = "en" + this.name = "English" + this.regex = /^en$|^en-/ + this.font = "TnT, Meiryo, sans-serif" + + this.titleProceed = "Click or Press Enter!" + this.categories = { + "J-POP": "Pop", + "アニメ": "Anime", + "ボーカロイド™曲": "VOCALOID™ Music", + "バラエティ": "Variety", + "クラシック": "Classical", + "ゲームミュージック": "Game Music", + "ナムコオリジナル": "NAMCO Original" + } + this.selectSong = "Select Song" + this.selectDifficulty = "Select Difficulty" + this.back = "Back" + this.random = "Random" + this.randomSong = "Random Song" + this.tutorial = "How to Play" + this.aboutSimulator = "About Simulator" + this.browse = "Browse…" + this.defaultSongList = "Default Song List" + this.songOptions = "Song Options" + this.none = "None" + this.auto = "Auto" + this.netplay = "Netplay" + this.easy = "Easy" + this.normal = "Normal" + this.hard = "Hard" + this.oni = "Extreme" + this.sessionStart = "Begin an Online Session!" + this.sessionEnd = "End Online Session" + this.loading = "Loading..." + this.cancel = "Cancel" + this.note = { + don: "Don", + ka: "Ka", + daiDon: "DON", + daiKa: "KA", + drumroll: "Drum rollー!!", + daiDrumroll: "DRUM ROLLー!!", + balloon: "Balloon" + } + this.combo = "Combo" + this.clear = "Clear" + this.good = "GOOD" + this.ok = "OK" + this.bad = "BAD" + this.pauseOptions = [ + "Continue", + "Retry", + "Back to Select Song" + ] + this.results = "Results" + this.points = "pts" + this.maxCombo = "MAX Combo" + this.drumroll = "Drumroll" +} +function StringsCn(){ + this.id = "cn" + this.name = "中文简体" + this.regex = /^zh$|^zh-CN$/ + this.font = "Microsoft YaHei, sans-serif" + + this.titleProceed = "点击或按回车!" + this.categories = { + "J-POP": "流行音乐", + "アニメ": "卡通动画音乐", + "ボーカロイド™曲": "VOCALOID™ Music", + "バラエティ": "综合音乐", + "クラシック": "古典音乐", + "ゲームミュージック": "游戏音乐", + "ナムコオリジナル": "NAMCO原创音乐" + } + this.selectSong = "选择乐曲" + this.selectDifficulty = "选择难度" + this.back = "返回" + this.random = "随机" + this.randomSong = "随机选曲" + this.tutorial = "操作说明" + this.aboutSimulator = "游戏信息" + this.browse = "浏览…" + this.defaultSongList = "默认歌曲列表" + this.songOptions = "选项" + this.none = "无" + this.auto = "自动" + this.netplay = "网络对战" + this.easy = "简单" + this.normal = "普通" + this.hard = "困难" + this.oni = "魔王" + this.sessionStart = "开始在线会议!" + this.sessionEnd = "结束在线会话" + this.loading = "读取中..." + this.cancel = "取消" + this.note = { + don: "咚", + ka: "咔", + daiDon: "咚(大)", + daiKa: "咔(大)", + drumroll: "连打ー!!", + daiDrumroll: "连打(大)ー!!", + balloon: "气球" + } + this.combo = "连段" + this.clear = "通关" + this.good = "良" + this.ok = "可" + this.bad = "不可" + this.pauseOptions = [ + "继续演奏", + "从头开始", + "返回「选择乐曲」" + ] + this.results = "发表成绩" + this.points = "点" + this.maxCombo = "最多连段数" + this.drumroll = "连打数" +} +function StringsTw(){ + this.id = "tw" + this.name = "中文繁體" + this.regex = /^zh-HK$|^zh-TW$/ + this.font = "Microsoft YaHei, sans-serif" + + this.titleProceed = "點擊或按回車!" + this.categories = { + "J-POP": "流行音樂", + "アニメ": "卡通動畫音樂", + "ボーカロイド™曲": "VOCALOID™ Music", + "バラエティ": "綜合音樂", + "クラシック": "古典音樂", + "ゲームミュージック": "遊戲音樂", + "ナムコオリジナル": "NAMCO原創音樂" + } + this.selectSong = "選擇樂曲" + this.selectDifficulty = "選擇難度" + this.back = "返回" + this.random = "隨機" + this.randomSong = "隨機選曲" + this.tutorial = "操作说明" + this.aboutSimulator = "游戏信息" + this.browse = "浏览…" + this.defaultSongList = "默认歌曲列表" + this.songOptions = "選項" + this.none = "無" + this.auto = "自動" + this.netplay = "网络对战" + this.easy = "簡單" + this.normal = "普通" + this.hard = "困難" + this.oni = "魔王" + this.sessionStart = "開始在線會議!" + this.sessionEnd = "結束在線會話" + this.loading = "讀取中..." + this.cancel = "取消" + this.note = { + don: "咚", + ka: "咔", + daiDon: "咚(大)", + daiKa: "咔(大)", + drumroll: "連打ー!!", + daiDrumroll: "連打(大)ー!!", + balloon: "氣球" + } + this.combo = "連段" + this.clear = "通關" + this.good = "良" + this.ok = "可" + this.bad = "不可" + this.pauseOptions = [ + "繼續演奏", + "從頭開始", + "返回「選擇樂曲」" + ] + this.results = "發表成績" + this.points = "點" + this.maxCombo = "最多連段數" + this.drumroll = "連打數" +} +function StringsKo(){ + this.id = "ko" + this.name = "한국어" + this.regex = /^ko$/ + this.font = "Microsoft YaHei, sans-serif" + + this.titleProceed = "클릭하거나 Enter를 누릅니다!" + this.categories = { + "J-POP": "POP", + "アニメ": "애니메이션", + "ボーカロイド™曲": "VOCALOID™ Music", + "バラエティ": "버라이어티", + "クラシック": "클래식", + "ゲームミュージック": "게임", + "ナムコオリジナル": "남코 오리지널" + } + this.selectSong = "곡 선택" + this.selectDifficulty = "난이도 선택" + this.back = "돌아간다" + this.random = "랜덤" + this.randomSong = "랜덤" + this.tutorial = "지도 시간" + this.aboutSimulator = "게임 정보" + this.browse = "찾아보기…" + this.defaultSongList = "기본 노래 목록" + this.songOptions = "옵션" + this.none = "없음" + this.auto = "오토" + this.netplay = "넷 플레이" + this.easy = "쉬움" + this.normal = "보통" + this.hard = "어려움" + this.oni = "귀신" + this.sessionStart = "온라인 세션 시작!" + this.sessionEnd = "온라인 세션 끝내기" + this.loading = "로딩 중..." + this.cancel = "취소" + this.note = { + don: "쿵", + ka: "딱", + daiDon: "쿵(대)", + daiKa: "딱(대)", + drumroll: "연타ー!!", + daiDrumroll: "연타(대)ー!!", + balloon: "풍선" + } + this.combo = "콤보" + this.clear = "클리어" + this.good = "얼쑤" + this.ok = "좋다" + this.bad = "에구" + this.pauseOptions = [ + "연주 계속하기", + "처음부터 다시", + "「곡 선택」으로" + ] + this.results = "성적 발표" + this.points = "점" + this.maxCombo = "최대 콤보 수" + this.drumroll = "연타 횟수" +} +var allStrings = { + "ja": new StringsJa(), + "en": new StringsEn(), + "cn": new StringsCn(), + "tw": new StringsTw(), + "ko": new StringsKo() } -var strings = new StringsJa() diff --git a/public/src/js/titlescreen.js b/public/src/js/titlescreen.js index 777e09d..ee12b42 100644 --- a/public/src/js/titlescreen.js +++ b/public/src/js/titlescreen.js @@ -1,13 +1,20 @@ class Titlescreen{ constructor(){ loader.changePage("titlescreen", false) + this.titleScreen = document.getElementById("title-screen") - var proceed = document.getElementById("title-proceed") - proceed.appendChild(document.createTextNode(strings.titleProceed)) - proceed.setAttribute("alt", strings.titleProceed) + this.proceed = document.getElementById("title-proceed") + this.langDropdown = document.getElementById("lang-dropdown") + this.langId = document.getElementById("lang-id") + + this.lang = this.getLang() + this.setLang(allStrings[this.lang]) + this.addLangs() pageEvents.keyAdd(this, "all", "down", this.keyDown.bind(this)) pageEvents.add(this.titleScreen, ["mousedown", "touchstart"], this.onPressed.bind(this)) + pageEvents.add(this.langDropdown, "change", this.langChange.bind(this)) + assets.sounds["title"].play() this.gamepad = new Gamepad({ "13": ["a", "b", "x", "y", "start", "ls", "rs"] @@ -24,7 +31,11 @@ class Titlescreen{ }) } } + keyDown(event, code){ + if(event && event.target === this.langDropdown){ + return + } if(!code){ code = event.keyCode } @@ -61,11 +72,58 @@ class Titlescreen{ }, 500) } } + + getLang(){ + if(localStorage.lang && localStorage.lang in allStrings){ + return localStorage.lang + } + if("languages" in navigator){ + 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])){ + return j + } + } + } + } + return "ja" + } + setLang(lang){ + strings = lang + this.proceed.innerText = strings.titleProceed + this.proceed.setAttribute("alt", strings.titleProceed) + this.langId.innerText = strings.id.toUpperCase() + this.langId.setAttribute("alt", strings.id.toUpperCase()) + loader.screen.style.fontFamily = strings.font + loader.screen.style.fontWeight = strings.font === "Microsoft YaHei, sans-serif" ? "bold" : "" + } + addLangs(){ + for(var i in allStrings){ + var option = document.createElement("option") + option.value = i + if(i === this.lang){ + option.selected = true + } + option.appendChild(document.createTextNode(allStrings[i].name)) + this.langDropdown.appendChild(option) + } + } + langChange(){ + this.lang = this.langDropdown.value + localStorage.lang = this.lang + this.setLang(allStrings[this.lang]) + } + clean(){ this.gamepad.clean() assets.sounds["title"].stop() pageEvents.keyRemove(this, "all") pageEvents.remove(this.titleScreen, ["mousedown", "touchstart"]) + pageEvents.remove(this.langDropdown, "change") delete this.titleScreen + delete this.proceed + delete this.langDropdown } } diff --git a/public/src/js/view.js b/public/src/js/view.js index 203db89..9f24b26 100644 --- a/public/src/js/view.js +++ b/public/src/js/view.js @@ -49,6 +49,13 @@ infoFill: "#656565" } } + this.difficulty = { + "easy": 0, + "normal": 1, + "hard": 2, + "oni": 3, + "ura": 4 + } this.currentScore = { ms: -Infinity, @@ -69,7 +76,7 @@ this.drumroll = [] this.beatInterval = this.controller.parsedSongData.beatInfo.beatInterval - this.font = "TnT, Meiryo, sans-serif" + this.font = strings.font this.draw = new CanvasDraw() this.assets = new ViewAssets(this) @@ -260,9 +267,14 @@ }) ctx.fill() + if(selectedSong.category in strings.categories){ + var categoryName = strings.categories[selectedSong.category] + }else{ + var categoryName = selectedSong.category + } this.draw.layeredText({ ctx: ctx, - text: selectedSong.category, + text: categoryName, fontSize: 15, fontFamily: this.font, align: "center", @@ -389,13 +401,11 @@ ctx.fill() // Difficulty - var badgeImg = assets.image["muzu_" + this.controller.selectedSong.difficulty] - var badgeW = badgeImg.width / badgeImg.height * 53 - ctx.drawImage(badgeImg, - 157 - badgeW / 2, - this.multiplayer === 2 ? 497 : 228, - badgeW, - 53 + ctx.drawImage(assets.image["difficulty"], + 0, 144 * this.difficulty[this.controller.selectedSong.difficulty], + 168, 143, + 126, this.multiplayer === 2 ? 497 : 228, + 62, 53 ) // Badges @@ -540,11 +550,11 @@ ctx.globalAlpha = 1 // Difficulty - var badgeImg = assets.image["muzu_" + this.controller.selectedSong.difficulty] - var badgeW = badgeImg.width / badgeImg.height * 120 - ctx.drawImage(badgeImg, - 87 - badgeW / 2, this.multiplayer === 2 ? 194 : 232, - badgeW, 120 + ctx.drawImage(assets.image["difficulty"], + 0, 144 * this.difficulty[this.controller.selectedSong.difficulty], + 168, 143, + 16, this.multiplayer === 2 ? 194 : 232, + 141, 120 ) // Badges @@ -629,7 +639,7 @@ // Score ctx.save() - ctx.font = "30px " + this.font + ctx.font = "30px TnT, Meiryo, sans-serif" ctx.fillStyle = "#fff" ctx.strokeStyle = "#fff" ctx.lineWidth = 0.3 @@ -763,11 +773,13 @@ }else{ ctx.fillStyle = "#fff" } - ctx.font = fontSize + "px " + this.font + ctx.font = this.draw.bold(this.font) + fontSize + "px " + this.font ctx.lineWidth = 7 * mul ctx.textAlign = "center" - ctx.strokeText("コンボ", comboX, comboTextY) - ctx.fillText("コンボ", comboX, comboTextY) + ctx.miterLimit = 1 + ctx.strokeText(strings.combo, comboX, comboTextY) + ctx.miterLimit = 10 + ctx.fillText(strings.combo, comboX, comboTextY) } // Slot @@ -931,7 +943,7 @@ x: _w / 2, y: 18, width: _w, - height: _h, + height: _h - 54, fontSize: 40, fontFamily: this.font, letterSpacing: -1 @@ -1292,7 +1304,7 @@ var text = circle.getText() var textX = circlePos.x var textY = circlePos.y + 83 * mul - ctx.font = lyricsSize + "px Kozuka" + ctx.font = lyricsSize + "px Kozuka, Microsoft YaHei, sans-serif" ctx.textBaseline = "middle" ctx.textAlign = "center" @@ -1373,7 +1385,7 @@ ctx: ctx, text: i.toString(), fontSize: fontSize, - fontFamily: this.font, + fontFamily: "TnT, Meiryo, sans-serif", x: textX, y: textY }, [ diff --git a/public/src/views/titlescreen.html b/public/src/views/titlescreen.html index 91f0fee..298cab7 100644 --- a/public/src/views/titlescreen.html +++ b/public/src/views/titlescreen.html @@ -2,3 +2,8 @@