diff --git a/app.py b/app.py index f1eac37..48db087 100644 --- a/app.py +++ b/app.py @@ -161,22 +161,24 @@ def route_api_songs(): songs_out = [] for song in songs: song_id = song[0] - song_type = song[10] + song_type = song[12] preview = get_preview(song_id, song_type) - category_out = categories[song[9]] if song[9] in categories else def_category + category_out = categories[song[11]] if song[11] in categories else def_category songs_out.append({ 'id': song_id, 'title': song[1], 'title_en': song[2], + 'subtitle': song[3], + 'subtitle_en': song[4], 'stars': [ - song[3], song[4], song[5], song[6], song[7] + song[5], song[6], song[7], song[8], song[9] ], 'preview': preview, 'category': category_out['title'], 'category_en': category_out['title_en'], 'type': song_type, - 'offset': song[11] + 'offset': song[13] }) return jsonify(songs_out) diff --git a/public/src/js/canvasdraw.js b/public/src/js/canvasdraw.js index 71bf916..1349551 100644 --- a/public/src/js/canvasdraw.js +++ b/public/src/js/canvasdraw.js @@ -50,8 +50,9 @@ comma: /[,.]/, ideographicComma: /[、。]/, apostrophe: /['']/, + degree: /[゚°]/, brackets: /[\((\))「」『』]/, - tilde: /[\--~~]/, + tilde: /[\--~~〜]/, tall: /[bbddffh-lh-ltt0-90-9♪]/, uppercase: /[A-ZA-Z]/, lowercase: /[a-za-z・]/, @@ -283,15 +284,20 @@ }else if(symbol === "ー"){ // Long-vowel mark 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: 3, h: 39, rotate: true}) }else if(r.comma.test(symbol)){ // Comma, full stop - drawn.push({text: symbol, x: 16, y: -7, h: 0, scale: [1.2, 0.7]}) + drawn.push({text: symbol, x: 13, y: -9, h: 13, 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]}) + }else if(r.degree.test(symbol)){ + // Degree + 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}) @@ -359,6 +365,10 @@ } } + if(config.align === "bottom"){ + drawn.reverse() + } + var drawnHeight = 0 for(let symbol of drawn){ if(config.letterSpacing){ @@ -382,9 +392,16 @@ style.transform = "" } + var scaling = 1 if(config.height && drawnHeight > config.height){ - var scaling = config.height / drawnHeight - ctx.scale(1, scaling) + scaling = config.height / drawnHeight + if(config.align === "bottom"){ + ctx.translate(40 * mul, 0) + ctx.scale(scaling, scaling) + ctx.translate(-40 * mul, 0) + }else{ + ctx.scale(1, scaling) + } if(config.selectable){ style.transform = "scale(1, " + scaling + ")" style.top = (config.y + (config.height - drawnHeight) / 2 - 15 / 2 * scaling) * scale + "px" @@ -407,12 +424,19 @@ if(action === "stroke"){ ctx.strokeStyle = config.outline ctx.lineWidth = config.outlineSize * mul + if(config.align === "bottom"){ + ctx.lineWidth /= scaling + } ctx.lineJoin = "round" ctx.miterLimit = 1 }else if(action === "fill"){ ctx.fillStyle = config.fill } - var offsetY = 0 + if(config.align === "bottom"){ + var offsetY = drawnHeight > config.height ? drawnHeight : config.height + }else{ + var offsetY = 0 + } for(let symbol of drawn){ var saved = false @@ -421,7 +445,10 @@ currentX += 20 * mul } var currentY = offsetY + symbol.y * mul - offsetY += symbol.h * mul + if(config.align === "bottom"){ + currentY -= symbol.h * mul + } + offsetY = offsetY + symbol.h * mul * (config.align === "bottom" ? -1 : 1) if(action === "selectable"){ let div = document.createElement("div") div.classList.add("stroke-sub") diff --git a/public/src/js/main.js b/public/src/js/main.js index 87055af..ae427bd 100644 --- a/public/src/js/main.js +++ b/public/src/js/main.js @@ -85,7 +85,8 @@ pageEvents.add(versionDiv, ["click", "touchend"], () => { resizeRoot() setInterval(resizeRoot, 100) pageEvents.keyAdd(debugObj, "all", "down", event => { - if(event.keyCode === 186 && 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() }else if(debugObj.state === "minimised"){ @@ -95,6 +96,7 @@ pageEvents.keyAdd(debugObj, "all", "down", event => { } } if(event.keyCode === 82 && debugObj.debug && debugObj.controller){ + // R debugObj.controller.restartSong() } }) diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index 3095894..42de8a5 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -91,6 +91,7 @@ class SongSelect{ this.songs.push({ id: song.id, title: song.title, + subtitle: song.subtitle, skin: song.category in this.songSkin ? this.songSkin[song.category] : this.songSkin.default, stars: song.stars, category: song.category, @@ -218,6 +219,8 @@ class SongSelect{ this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_" + sort].src + "')" this.previewId = 0 + this.previewList = Array(5) + var skipStart = fromTutorial || p2.session this.state = { screen: fadeIn ? "titleFadeIn" : (skipStart ? "song" : "title"), @@ -708,7 +711,11 @@ class SongSelect{ this.canvas.style.height = (winH / this.pixelRatio) + "px" var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2 - this.songTitleCache.resize((this.songAsset.width - borders + 1) * this.songs.length, (this.songAsset.height - borders + 1) * 2, ratio + 0.5) + this.songTitleCache.resize( + (this.songAsset.width - borders + 1) * this.songs.length, + (this.songAsset.height - borders + 1) * 3, + ratio + 0.5 + ) this.selectTextCache.resize((280 + 53 + 60 + 1) * 2, this.songAsset.marginTop + 15, ratio + 0.5) @@ -1285,30 +1292,55 @@ class SongSelect{ drawDifficulty(ctx, i, currentUra) } } + + var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2 + var textW = this.songAsset.width - borders + var textH = this.songAsset.height - borders + var textX = Math.max(w - 37 - textW / 2, w / 2 - textW / 2) + var textY = opened * 12 + (1 - opened) * 7 + + if(currentSong.subtitle){ + this.songTitleCache.get({ + ctx: ctx, + x: x + textX - textW, + y: y + textY, + w: textW, + h: textH, + id: currentSong.subtitle, + }, ctx => { + this.draw.verticalText({ + ctx: ctx, + text: currentSong.subtitle, + x: textW / 2, + y: 7, + width: textW, + height: textH - 35, + fill: "#fff", + outline: "#000", + outlineSize: 14, + fontSize: 28, + fontFamily: this.font, + align: "bottom" + }) + }) + } + if(!songSel && currentSong.stars[4]){ var fade = ((ms - this.state.screenMS) % 1200) / 1200 var _x = x + 402 + 4 * 100 + fade * 25 var _y = y + 258 - ctx.save() - ctx.globalAlpha = this.draw.easeInOut(1 - fade) - ctx.fillStyle = "#e0be28" + ctx.fillStyle = "rgba(0, 0, 0, " + 0.2 * this.draw.easeInOut(1 - fade) + ")" ctx.beginPath() ctx.moveTo(_x - 35, _y - 25) ctx.lineTo(_x - 10, _y) ctx.lineTo(_x - 35, _y + 25) ctx.fill() - ctx.restore() } ctx.globalAlpha = 1 - Math.max(0, opened - 0.5) * 2 ctx.fillStyle = selectedSkin.background ctx.fillRect(x, y, w, h) ctx.globalAlpha = 1 - var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2 - var textW = this.songAsset.width - borders - var textH = this.songAsset.height - borders - var textX = Math.max(w - 37 - textW / 2, w / 2 - textW / 2) - var textY = opened * 12 + (1 - opened) * 7 this.songTitleCache.get({ ctx: ctx, x: x + textX, @@ -1551,15 +1583,17 @@ class SongSelect{ var currentId = this.previewId this.previewing = this.selectedSong } - var songObj = assets.songs.find(song => song.id == id) + var songObj = this.previewList.find(song => song && song.id === id) - if(songObj.preview_sound){ + if(songObj){ if(!loadOnly){ this.preview = songObj.preview_sound this.preview.gain = snd.previewGain this.previewLoaded(startLoad, songObj.preview_time) } }else{ + songObj = {id: id} + var previewFilename = prvTime > 0.1 ? "/preview.mp3" : "/main.mp3" var loadPreview = previewFilename => { @@ -1575,6 +1609,14 @@ class SongSelect{ songObj.preview_sound = sound this.preview = sound this.previewLoaded(startLoad, songObj.preview_time) + + var oldPreview = this.previewList.shift() + if(oldPreview){ + oldPreview.preview_sound.clean() + } + this.previewList.push(songObj) + }else{ + sound.clean() } }) } @@ -1714,6 +1756,11 @@ class SongSelect{ } this.redrawRunning = false this.endPreview() + this.previewList.forEach(song => { + if(song){ + song.preview_sound.clean() + } + }) pageEvents.keyRemove(this, "all") pageEvents.remove(loader.screen, ["mousemove", "mouseleave", "mousedown", "touchstart"]) pageEvents.remove(p2, "message") diff --git a/public/src/js/soundbuffer.js b/public/src/js/soundbuffer.js index 9a8c1c2..df906c8 100644 --- a/public/src/js/soundbuffer.js +++ b/public/src/js/soundbuffer.js @@ -206,4 +206,7 @@ class Sound{ } } } + clean(){ + delete this.buffer + } }