From d6a1b6bd41bc63d3c33482a2c55e5d1b2440b93d Mon Sep 17 00:00:00 2001 From: AnthonyDuan Date: Thu, 15 Jan 2026 23:32:43 +0800 Subject: [PATCH] Add leaderboard feature with monthly reset and top 50 limit, update version to 1.1.0 --- app.py | 152 +++ public/src/css/leaderboard.css | 13 + public/src/js/leaderboard.js | 286 +++++ public/src/js/songselect.js | 1703 +++++++++++++++-------------- public/src/views/leaderboard.html | 3 + schema.py | 11 + templates/index.html | 19 +- 7 files changed, 1343 insertions(+), 844 deletions(-) create mode 100644 public/src/css/leaderboard.css create mode 100644 public/src/js/leaderboard.js create mode 100644 public/src/views/leaderboard.html diff --git a/app.py b/app.py index 0af8fcc..4745339 100644 --- a/app.py +++ b/app.py @@ -105,6 +105,9 @@ db.users.create_index('username', unique=True) db.songs.create_index('id', unique=True) db.songs.create_index('song_type') db.scores.create_index('username') +db.leaderboards.create_index([('song_id', 1), ('difficulty', 1), ('month', 1), ('score', -1)]) +db.leaderboards.create_index([('song_id', 1), ('difficulty', 1), ('username', 1), ('month', 1)], unique=True) +db.leaderboards.create_index('month') class HashException(Exception): @@ -746,6 +749,155 @@ def route_api_scores_get(): return jsonify({'status': 'ok', 'scores': scores, 'username': user['username'], 'display_name': user['display_name'], 'don': don}) +@app.route(basedir + 'api/leaderboard/submit', methods=['POST']) +@login_required +def route_api_leaderboard_submit(): + data = request.get_json() + if not schema.validate(data, schema.leaderboard_submit): + return abort(400) + + username = session.get('username') + user = db.users.find_one({'username': username}) + if not user: + return api_error('user_not_found') + + song_id = data.get('song_id') + difficulty = data.get('difficulty') + score_data = data.get('score') + + # Validate difficulty + valid_difficulties = ['easy', 'normal', 'hard', 'oni', 'ura'] + if difficulty not in valid_difficulties: + return api_error('invalid_difficulty') + + # Get current month (YYYY-MM format) + current_month = time.strftime('%Y-%m', time.gmtime()) + + # Check if user already has a record for this song/difficulty/month + existing = db.leaderboards.find_one({ + 'song_id': song_id, + 'difficulty': difficulty, + 'username': username, + 'month': current_month + }) + + # Parse score (assuming it's in the same format as the scores collection) + try: + if isinstance(score_data, str): + import json as json_module + score_obj = json_module.loads(score_data) + else: + score_obj = score_data + + score_value = int(score_obj.get('score', 0)) + except: + return api_error('invalid_score_format') + + if existing: + # Update only if new score is higher + existing_score = int(existing.get('score', {}).get('score', 0)) + if score_value > existing_score: + db.leaderboards.update_one( + {'_id': existing['_id']}, + {'$set': { + 'score': score_data, + 'display_name': user['display_name'], + 'submitted_at': time.time() + }} + ) + return jsonify({'status': 'ok', 'message': 'score_updated'}) + else: + return jsonify({'status': 'ok', 'message': 'score_not_higher'}) + else: + # Check if this score would be in top 50 + count = db.leaderboards.count_documents({ + 'song_id': song_id, + 'difficulty': difficulty, + 'month': current_month + }) + + if count >= 50: + # Find the 50th score + leaderboard = list(db.leaderboards.find({ + 'song_id': song_id, + 'difficulty': difficulty, + 'month': current_month + }).sort('score', -1).limit(50)) + + if len(leaderboard) >= 50: + last_score = int(leaderboard[49].get('score', {}).get('score', 0)) + if score_value <= last_score: + return jsonify({'status': 'ok', 'message': 'score_too_low'}) + + # Insert new record + db.leaderboards.insert_one({ + 'song_id': song_id, + 'difficulty': difficulty, + 'username': username, + 'display_name': user['display_name'], + 'score': score_data, + 'submitted_at': time.time(), + 'month': current_month + }) + + # Remove entries beyond 50th place + if count >= 50: + # Get all entries sorted by score + all_entries = list(db.leaderboards.find({ + 'song_id': song_id, + 'difficulty': difficulty, + 'month': current_month + }).sort('score', -1)) + + # Delete entries beyond 50 + if len(all_entries) > 50: + for entry in all_entries[50:]: + db.leaderboards.delete_one({'_id': entry['_id']}) + + return jsonify({'status': 'ok', 'message': 'score_submitted'}) + + +@app.route(basedir + 'api/leaderboard/get') +def route_api_leaderboard_get(): + song_id = request.args.get('song_id', None) + difficulty = request.args.get('difficulty', None) + + if not song_id or not difficulty: + return abort(400) + + try: + song_id = int(song_id) + except: + return abort(400) + + # Validate difficulty + valid_difficulties = ['easy', 'normal', 'hard', 'oni', 'ura'] + if difficulty not in valid_difficulties: + return abort(400) + + # Get current month + current_month = time.strftime('%Y-%m', time.gmtime()) + + # Get top 50 scores + leaderboard = list(db.leaderboards.find({ + 'song_id': song_id, + 'difficulty': difficulty, + 'month': current_month + }, { + '_id': False, + 'username': True, + 'display_name': True, + 'score': True, + 'submitted_at': True + }).sort('score', -1).limit(50)) + + # Add rank to each entry + for i, entry in enumerate(leaderboard): + entry['rank'] = i + 1 + + return jsonify({'status': 'ok', 'leaderboard': leaderboard, 'month': current_month}) + + @app.route(basedir + 'privacy') def route_api_privacy(): last_modified = time.strftime('%d %B %Y', time.gmtime(os.path.getmtime('templates/privacy.txt'))) diff --git a/public/src/css/leaderboard.css b/public/src/css/leaderboard.css new file mode 100644 index 0000000..0aab58d --- /dev/null +++ b/public/src/css/leaderboard.css @@ -0,0 +1,13 @@ +#leaderboard { + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 1000; +} + +#leaderboard-canvas { + width: 100%; + height: 100%; +} diff --git a/public/src/js/leaderboard.js b/public/src/js/leaderboard.js new file mode 100644 index 0000000..76b6086 --- /dev/null +++ b/public/src/js/leaderboard.js @@ -0,0 +1,286 @@ +class Leaderboard { + constructor() { + this.init() + } + + init() { + this.canvas = document.getElementById("leaderboard-canvas") + if (!this.canvas) { + return + } + this.ctx = this.canvas.getContext("2d") + + var resolution = settings.getItem("resolution") + var noSmoothing = resolution === "low" || resolution === "lowest" + if (noSmoothing) { + this.ctx.imageSmoothingEnabled = false + } + + this.songId = null + this.difficulty = null + this.leaderboardData = [] + this.currentMonth = "" + this.visible = false + + this.draw = new CanvasDraw(noSmoothing) + + // Keyboard controls + this.keyboard = new Keyboard({ + confirm: ["enter", "escape", "don_l", "don_r"], + back: ["escape"], + left: ["left", "ka_l"], + right: ["right", "ka_r"] + }, this.keyPress.bind(this)) + + pageEvents.add(this.canvas, ["mousedown", "touchstart"], this.onClose.bind(this)) + } + + keyPress(pressed, name) { + if (!pressed || !this.visible) { + return + } + if (name === "confirm" || name === "back") { + this.close() + } else if (name === "left") { + this.changeDifficulty(-1) + } else if (name === "right") { + this.changeDifficulty(1) + } + } + + async display(songId, difficulty) { + this.songId = songId + this.difficulty = difficulty + this.visible = true + + loader.changePage("leaderboard", false) + + // Fetch leaderboard data + await this.fetchLeaderboard() + + // Start rendering + this.redrawRunning = true + this.redrawBind = this.redraw.bind(this) + this.redraw() + + assets.sounds["se_don"].play() + } + + async fetchLeaderboard() { + try { + var response = await loader.ajax( + `${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${this.songId}&difficulty=${this.difficulty}` + ) + var data = JSON.parse(response) + if (data.status === "ok") { + this.leaderboardData = data.leaderboard || [] + this.currentMonth = data.month || "" + } else { + this.leaderboardData = [] + } + } catch (e) { + console.error("Failed to fetch leaderboard:", e) + this.leaderboardData = [] + } + } + + changeDifficulty(direction) { + var difficulties = ["easy", "normal", "hard", "oni", "ura"] + var currentIndex = difficulties.indexOf(this.difficulty) + if (currentIndex === -1) { + return + } + + var newIndex = (currentIndex + direction + difficulties.length) % difficulties.length + this.difficulty = difficulties[newIndex] + + this.fetchLeaderboard().then(() => { + assets.sounds["se_ka"].play() + }) + } + + onClose(event) { + if (!this.visible) { + return + } + + var rect = this.canvas.getBoundingClientRect() + var x = (event.offsetX || event.touches[0].pageX - rect.left) + var y = (event.offsetY || event.touches[0].pageY - rect.top) + + // Check if clicked outside modal (approximately) + var centerX = this.canvas.width / 2 + var centerY = this.canvas.height / 2 + var modalWidth = 800 + var modalHeight = 600 + + if (x < centerX - modalWidth / 2 || x > centerX + modalWidth / 2 || + y < centerY - modalHeight / 2 || y > centerY + modalHeight / 2) { + this.close() + } + } + + close() { + this.visible = false + this.redrawRunning = false + + if (this.keyboard) { + this.keyboard.clean() + } + + assets.sounds["se_cancel"].play() + + // Return to song select + setTimeout(() => { + new SongSelect(false, false, touchEnabled) + }, 100) + } + + redraw() { + if (!this.redrawRunning) { + return + } + + requestAnimationFrame(this.redrawBind) + + var winW = innerWidth + var winH = innerHeight + var ratio = winH / 720 + + this.canvas.width = winW + this.canvas.height = winH + this.ctx.save() + + // Draw semi-transparent background + this.ctx.fillStyle = "rgba(0, 0, 0, 0.8)" + this.ctx.fillRect(0, 0, winW, winH) + + this.ctx.scale(ratio, ratio) + + // Draw modal background + var modalX = 240 + var modalY = 60 + var modalW = 800 + var modalH = 600 + + this.ctx.fillStyle = "#ffffff" + this.ctx.fillRect(modalX, modalY, modalW, modalH) + + this.ctx.strokeStyle = "#333333" + this.ctx.lineWidth = 4 + this.ctx.strokeRect(modalX, modalY, modalW, modalH) + + // Draw title + this.ctx.fillStyle = "#000000" + this.ctx.font = "bold 40px " + (strings.font || "sans-serif") + this.ctx.textAlign = "center" + this.ctx.fillText("🏆 排行榜 Leaderboard", 640, 110) + + // Draw difficulty selector + var diffX = 640 + var diffY = 160 + var difficulties = [ + { id: "easy", name: "簡単", color: "#00a0e9" }, + { id: "normal", name: "普通", color: "#00a040" }, + { id: "hard", name: "難しい", color: "#ff8c00" }, + { id: "oni", name: "鬼", color: "#dc143c" }, + { id: "ura", name: "裏", color: "#9400d3" } + ] + + this.ctx.font = "24px " + (strings.font || "sans-serif") + for (var i = 0; i < difficulties.length; i++) { + var diff = difficulties[i] + var x = diffX - 200 + i * 100 + + if (diff.id === this.difficulty) { + this.ctx.fillStyle = diff.color + this.ctx.fillRect(x - 45, diffY - 25, 90, 40) + this.ctx.fillStyle = "#ffffff" + } else { + this.ctx.strokeStyle = diff.color + this.ctx.lineWidth = 2 + this.ctx.strokeRect(x - 45, diffY - 25, 90, 40) + this.ctx.fillStyle = diff.color + } + + this.ctx.textAlign = "center" + this.ctx.fillText(diff.name, x, diffY + 5) + } + + // Draw month info + this.ctx.fillStyle = "#666666" + this.ctx.font = "18px " + (strings.font || "sans-serif") + this.ctx.textAlign = "center" + this.ctx.fillText("当月排行 " + this.currentMonth, 640, 210) + + // Draw leaderboard entries + var startY = 240 + var rowHeight = 35 + + this.ctx.font = "20px " + (strings.font || "sans-serif") + this.ctx.textAlign = "left" + + if (this.leaderboardData.length === 0) { + this.ctx.fillStyle = "#999999" + this.ctx.textAlign = "center" + this.ctx.fillText("暂无排行数据", 640, startY + 100) + } else { + for (var i = 0; i < Math.min(this.leaderboardData.length, 15); i++) { + var entry = this.leaderboardData[i] + var y = startY + i * rowHeight + var rank = entry.rank + + // Rank background color + if (rank === 1) { + this.ctx.fillStyle = "#ffd700" // Gold + } else if (rank === 2) { + this.ctx.fillStyle = "#c0c0c0" // Silver + } else if (rank === 3) { + this.ctx.fillStyle = "#cd7f32" // Bronze + } else { + this.ctx.fillStyle = "#f5f5f5" + } + this.ctx.fillRect(modalX + 20, y - 20, modalW - 40, 30) + + // Rank + this.ctx.fillStyle = rank <= 3 ? "#ffffff" : "#333333" + this.ctx.font = "bold 20px " + (strings.font || "sans-serif") + this.ctx.textAlign = "center" + this.ctx.fillText(rank, modalX + 60, y) + + // Display name + this.ctx.fillStyle = "#000000" + this.ctx.font = "20px " + (strings.font || "sans-serif") + this.ctx.textAlign = "left" + var displayName = entry.display_name || entry.username + if (displayName.length > 15) { + displayName = displayName.substring(0, 15) + "..." + } + this.ctx.fillText(displayName, modalX + 100, y) + + // Score + var score = entry.score && entry.score.score ? entry.score.score : 0 + this.ctx.textAlign = "right" + this.ctx.fillText(score.toLocaleString(), modalX + modalW - 40, y) + } + } + + // Draw close hint + this.ctx.fillStyle = "#666666" + this.ctx.font = "18px " + (strings.font || "sans-serif") + this.ctx.textAlign = "center" + this.ctx.fillText("按ESC或点击外部关闭 Press ESC or click outside to close", 640, 680) + + this.ctx.restore() + } + + clean() { + if (this.keyboard) { + this.keyboard.clean() + } + if (this.redrawRunning) { + this.redrawRunning = false + } + pageEvents.remove(this.canvas, ["mousedown", "touchstart"]) + } +} diff --git a/public/src/js/songselect.js b/public/src/js/songselect.js index edec6bc..eb547a8 100644 --- a/public/src/js/songselect.js +++ b/public/src/js/songselect.js @@ -1,19 +1,19 @@ -class SongSelect{ - constructor(...args){ +class SongSelect { + constructor(...args) { this.init(...args) } - init(fromTutorial, fadeIn, touchEnabled, songId, showWarning){ + init(fromTutorial, fadeIn, touchEnabled, songId, showWarning) { this.touchEnabled = touchEnabled - + loader.changePage("songselect", false) this.canvas = document.getElementById("song-sel-canvas") this.ctx = this.canvas.getContext("2d") var resolution = settings.getItem("resolution") var noSmoothing = resolution === "low" || resolution === "lowest" - if(noSmoothing){ + if (noSmoothing) { this.ctx.imageSmoothingEnabled = false } - if(resolution === "lowest"){ + if (resolution === "lowest") { this.canvas.style.imageRendering = "pixelated" } @@ -21,7 +21,7 @@ class SongSelect{ let color = Math.floor(Math.random() * 16777215).toString(16).padStart(6, "0"); return `#${color}`; } - + this.songSkin = { "selected": { background: "#ffdb2c", @@ -75,25 +75,25 @@ class SongSelect{ border: ["#fde9df", "#ce7553"], outline: "#ce7553" }, - // カスタム曲スキン - "upload": { - sort: 0, - background: "#ffe57f", - border: ["#ffd54f", "#ff9800"], - outline: "#ffab40", - }, - "keijiban": { - sort: 0, - background: "#1c1c1c", - border: ["#000000", "#333333"], - outline: "#222222", - }, - "customSettings": { - sort: 0, - background: "#a5d6a7", // 緑色の背景 - border: ["#81c784", "#66bb6a"], // 緑色の境界線 - outline: "#388e3c" // 緑色のアウトライン - }, + // カスタム曲スキン + "upload": { + sort: 0, + background: "#ffe57f", + border: ["#ffd54f", "#ff9800"], + outline: "#ffab40", + }, + "keijiban": { + sort: 0, + background: "#1c1c1c", + border: ["#000000", "#333333"], + outline: "#222222", + }, + "customSettings": { + sort: 0, + background: "#a5d6a7", // 緑色の背景 + border: ["#81c784", "#66bb6a"], // 緑色の境界線 + outline: "#388e3c" // 緑色のアウトライン + }, "default": { sort: null, background: `${rand()}`, @@ -102,12 +102,12 @@ class SongSelect{ infoFill: `${rand()}` } } - + var songSkinLength = Object.keys(this.songSkin).length - for(var i in assets.categories){ + for (var i in assets.categories) { var category = assets.categories[i] - if(!this.songSkin[category.title] && category.songSkin){ - if(category.songSkin.sort === null){ + if (!this.songSkin[category.title] && category.songSkin) { + if (category.songSkin.sort === null) { category.songSkin.sort = songSkinLength + 1 } category.songSkin.id = category.id @@ -115,13 +115,13 @@ class SongSelect{ } } this.songSkin["default"].sort = songSkinLength + 1 - + this.font = strings.font - + this.search = new Search(this) this.songs = [] - for(let song of assets.songs){ + for (let song of assets.songs) { var title = this.getLocalTitle(song.title, song.title_lang) song.titlePrepared = title ? fuzzysort.prepare(this.search.normalizeString(title)) : null var subtitle = this.getLocalTitle(title === song.title ? song.subtitle : "", song.subtitle_lang) @@ -131,13 +131,13 @@ class SongSelect{ this.songs.sort((a, b) => { var catA = a.originalCategory in this.songSkin ? this.songSkin[a.originalCategory] : this.songSkin.default var catB = b.originalCategory in this.songSkin ? this.songSkin[b.originalCategory] : this.songSkin.default - if(catA.sort !== catB.sort){ + if (catA.sort !== catB.sort) { return catA.sort > catB.sort ? 1 : -1 - }else if(a.originalCategory !== b.originalCategory){ + } else if (a.originalCategory !== b.originalCategory) { return a.originalCategory > b.originalCategory ? 1 : -1 - }else if(a.order !== b.order){ + } else if (a.order !== b.order) { return a.order > b.order ? 1 : -1 - }else{ + } else { return a.id > b.id ? 1 : -1 } }) @@ -145,7 +145,7 @@ class SongSelect{ if (titlesort === "true") { this.songs.sort((a, b) => a.title.localeCompare(b.title)); } - if(assets.songs.length){ + if (assets.songs.length) { this.songs.push({ title: strings.back, skin: this.songSkin.back, @@ -167,11 +167,11 @@ class SongSelect{ p2Enabled: true }) } - if(touchEnabled){ - if(fromTutorial === "tutorial"){ + if (touchEnabled) { + if (fromTutorial === "tutorial") { fromTutorial = false } - }else{ + } else { this.songs.push({ title: strings.howToPlay, skin: this.songSkin.tutorial, @@ -180,7 +180,7 @@ class SongSelect{ }) } this.showWarning = showWarning - if(showWarning && showWarning.name === "scoreSaveFailed"){ + if (showWarning && showWarning.name === "scoreSaveFailed") { scoreStorage.scoreSaveFailed = true } this.songs.push({ @@ -195,14 +195,14 @@ class SongSelect{ action: "settings", category: strings.random }) - + var showCustom = false - if(gameConfig.google_credentials.gdrive_enabled){ + if (gameConfig.google_credentials.gdrive_enabled) { showCustom = true - }else if("webkitdirectory" in HTMLInputElement.prototype && !(/Android|iPhone|iPad/.test(navigator.userAgent))){ + } else if ("webkitdirectory" in HTMLInputElement.prototype && !(/Android|iPhone|iPad/.test(navigator.userAgent))) { showCustom = true } - if(showCustom){ + if (showCustom) { this.songs.push({ title: assets.customSongs ? strings.customSongs.default : strings.customSongs.title, skin: this.songSkin.customSongs, @@ -217,68 +217,68 @@ class SongSelect{ category: strings.random }) - // カスタムメニュー - // this.songs.push({ - // title: "ソースコード", - // skin: this.songSkin.sourceCode, - // action: "sourceCode", - // }); - // for (let i = 0; i < 10; i++) { - this.songs.push({ - title: "曲を投稿!", - skin: this.songSkin.upload, - action: "upload", - }); - // } - this.songs.push({ - title: "掲示板", - skin: this.songSkin.keijiban, - action: "keijiban", - }); + // カスタムメニュー + // this.songs.push({ + // title: "ソースコード", + // skin: this.songSkin.sourceCode, + // action: "sourceCode", + // }); + // for (let i = 0; i < 10; i++) { + this.songs.push({ + title: "曲を投稿!", + skin: this.songSkin.upload, + action: "upload", + }); + // } + this.songs.push({ + title: "掲示板", + skin: this.songSkin.keijiban, + action: "keijiban", + }); - this.songs.push({ - title: "曲選択速度", - skin: this.songSkin.customSettings, - action: "songSelectingSpeed", - }); - - this.songs.push({ - title: "ばいそく", - skin: this.songSkin.customSettings, - action: "baisoku", - }); + this.songs.push({ + title: "曲選択速度", + skin: this.songSkin.customSettings, + action: "songSelectingSpeed", + }); - this.songs.push({ - title: "ドロン", - skin: this.songSkin.customSettings, - action: "doron", - }); + this.songs.push({ + title: "ばいそく", + skin: this.songSkin.customSettings, + action: "baisoku", + }); - this.songs.push({ - title: "あべこべ", - skin: this.songSkin.customSettings, - action: "abekobe", - }); + this.songs.push({ + title: "ドロン", + skin: this.songSkin.customSettings, + action: "doron", + }); - this.songs.push({ - title: "でたらめ", - skin: this.songSkin.customSettings, - action: "detarame", - }); + this.songs.push({ + title: "あべこべ", + skin: this.songSkin.customSettings, + action: "abekobe", + }); + + this.songs.push({ + title: "でたらめ", + skin: this.songSkin.customSettings, + action: "detarame", + }); - this.songs.push({ - title: "タイトル順で並べ替え", - skin: this.songSkin.customSettings, - action: "titlesort", - }); + this.songs.push({ + title: "タイトル順で並べ替え", + skin: this.songSkin.customSettings, + action: "titlesort", + }); this.songs.push({ title: strings.back, skin: this.songSkin.back, action: "back" }) - + this.songAsset = { marginTop: 104, marginLeft: 18, @@ -291,7 +291,7 @@ class SongSelect{ innerBorder: 8, letterBorder: 12 } - + this.diffOptions = [{ text: strings.back, fill: "#efb058", @@ -310,9 +310,15 @@ class SongSelect{ iconName: "download", iconFill: "#e7cbe1", letterSpacing: 4 + }, { + text: "排行榜", + fill: "#ffd700", + iconName: "ranking", + iconFill: "#fff4b5", + letterSpacing: 4 }] this.optionsList = [strings.none, strings.auto, strings.netplay] - + this.draw = new CanvasDraw(noSmoothing) this.songTitleCache = new CanvasCache(noSmoothing) this.selectTextCache = new CanvasCache(noSmoothing) @@ -321,64 +327,64 @@ class SongSelect{ this.sessionCache = new CanvasCache(noSmoothing) this.currentSongCache = new CanvasCache(noSmoothing) this.nameplateCache = new CanvasCache(noSmoothing) - - + + this.difficulty = [strings.easy, strings.normal, strings.hard, strings.oni] this.difficultyId = ["easy", "normal", "hard", "oni", "ura"] - + this.sessionText = { "sessionstart": strings.sessionStart, "sessionend": strings.sessionEnd } - + this.selectedSong = 0 this.selectedDiff = 0 this.lastCurrentSong = {} this.lastRandom = false assets.sounds["bgm_songsel"].playLoop(0.1, false, 0, 1.442, 3.506) - - if(!assets.customSongs && !fromTutorial && !("selectedSong" in localStorage) && !songId){ + + if (!assets.customSongs && !fromTutorial && !("selectedSong" in localStorage) && !songId) { fromTutorial = touchEnabled ? "about" : "tutorial" } - if(p2.session || assets.customSongs && "customSelected" in localStorage){ + if (p2.session || assets.customSongs && "customSelected" in localStorage) { fromTutorial = false } - + this.drumSounds = settings.getItem("latency").drumSounds this.playedSounds = {} - + var songIdIndex = -1 var newSelected = -1 - if(fromTutorial){ + if (fromTutorial) { newSelected = this.songs.findIndex(song => song.action === fromTutorial) } - if(newSelected !== -1){ + if (newSelected !== -1) { this.setSelectedSong(newSelected, false) this.playBgm(true) - }else{ - if(songId){ + } else { + if (songId) { songIdIndex = this.songs.findIndex(song => song.id === songId) - if(songIdIndex === -1){ + if (songIdIndex === -1) { this.clearHash() } } - if(songIdIndex !== -1){ + if (songIdIndex !== -1) { this.setSelectedSong(songIdIndex, false) - }else if(assets.customSongs){ + } else if (assets.customSongs) { this.setSelectedSong(Math.min(Math.max(0, assets.customSelected), this.songs.length - 1), false) - }else if((!p2.session || fadeIn) && "selectedSong" in localStorage){ - this.setSelectedSong(Math.min(Math.max(0, localStorage["selectedSong"] |0), this.songs.length - 1), false) + } else if ((!p2.session || fadeIn) && "selectedSong" in localStorage) { + this.setSelectedSong(Math.min(Math.max(0, localStorage["selectedSong"] | 0), this.songs.length - 1), false) } - if(!this.showWarning){ + if (!this.showWarning) { this.playSound(songIdIndex !== -1 ? "v_diffsel" : "v_songsel") } snd.musicGain.fadeOut() this.playBgm(false) } - if("selectedDiff" in localStorage){ - this.selectedDiff = Math.min(Math.max(0, localStorage["selectedDiff"] |0), this.diffOptions.length + 3) + if ("selectedDiff" in localStorage) { + this.selectedDiff = Math.min(Math.max(0, localStorage["selectedDiff"] | 0), this.diffOptions.length + 3) } - + this.songSelect = document.getElementById("song-select") this.songTypes = [ "01 Pop", @@ -408,10 +414,10 @@ class SongSelect{ this.updateTypeLabel() var cat = this.songs[this.selectedSong].originalCategory this.drawBackground(cat) - + this.previewId = 0 this.previewList = Array(5) - + var skipStart = fromTutorial || p2.session this.state = { screen: songIdIndex !== -1 ? "difficulty" : (fadeIn ? "titleFadeIn" : (skipStart ? "song" : "title")), @@ -436,9 +442,9 @@ class SongSelect{ } this.wheelScrolls = 0 this.wheelTimer = 0 - + this.startPreview(true) - + this.pressedKeys = {} this.keyboard = new Keyboard({ confirm: ["enter", "space", "don_l", "don_r"], @@ -466,18 +472,18 @@ class SongSelect{ jump_left: ["lb"], jump_right: ["rb"] }, this.keyPress.bind(this)) - - if(!assets.customSongs){ + + if (!assets.customSongs) { this.startP2() } - + pageEvents.add(loader.screen, "mousemove", this.mouseMove.bind(this)) pageEvents.add(loader.screen, "mouseleave", () => { this.state.moveHover = null }) pageEvents.add(loader.screen, ["mousedown", "touchstart"], this.mouseDown.bind(this)) pageEvents.add(this.canvas, "touchend", this.touchEnd.bind(this)) - if(touchEnabled && fullScreenSupported){ + if (touchEnabled && fullScreenSupported) { this.touchFullBtn = document.getElementById("touch-full-btn") this.touchFullBtn.style.display = "block" pageEvents.add(this.touchFullBtn, "touchend", toggleFullscreen) @@ -487,32 +493,32 @@ class SongSelect{ this.selectable = document.getElementById("song-sel-selectable") this.selectableText = "" - + this.redrawRunning = true this.redrawBind = this.redraw.bind(this) this.redraw() pageEvents.send("song-select") pageEvents.send("song-select-move", this.songs[this.selectedSong]) - if(songIdIndex !== -1){ + if (songIdIndex !== -1) { pageEvents.send("song-select-difficulty", this.songs[this.selectedSong]) } } - setAltText(element, text){ + setAltText(element, text) { element.innerText = text element.setAttribute("alt", text) } - setSelectedSong(songIdx, drawBg=true){ + setSelectedSong(songIdx, drawBg = true) { if (songIdx < 0) { return; } - if(drawBg){ + if (drawBg) { var cat = this.songs[songIdx].originalCategory - if(cat){ + if (cat) { this.drawBackground(cat) - }else{ + } else { this.drawBackground(false) } } @@ -520,105 +526,109 @@ class SongSelect{ this.selectedSong = songIdx } - keyPress(pressed, name, event, repeat){ - if(pressed){ - if(!this.pressedKeys[name]){ + keyPress(pressed, name, event, repeat) { + if (pressed) { + if (!this.pressedKeys[name]) { this.pressedKeys[name] = this.getMS() + (name === "left" || name === "right" ? 150 : 300) } - }else{ + } else { this.pressedKeys[name] = 0 return } - if(name === "ctrl" || name === "shift" || !this.redrawRunning){ + if (name === "ctrl" || name === "shift" || !this.redrawRunning) { return } var ctrl = event ? event.ctrlKey : (this.pressedKeys["ctrl"] || this.pressedKeys["ctrlGamepad"]) var shift = event ? event.shiftKey : this.pressedKeys["shift"] - if(this.state.showWarning){ - if(name === "confirm"){ + if (this.state.showWarning) { + if (name === "confirm") { this.playSound("se_don") this.state.showWarning = false this.showWarning = false } - }else if(this.search.opened){ + } else if (this.search.opened) { this.search.keyPress(pressed, name, event, repeat, ctrl) - }else if(this.state.screen === "song"){ - if(event && event.keyCode && event.keyCode === 70 && ctrl){ + } else if (this.state.screen === "song") { + if (event && event.keyCode && event.keyCode === 70 && ctrl) { this.search.display() - if(event){ + if (event) { event.preventDefault() } - }else if(name === "confirm"){ + } else if (name === "confirm") { this.toSelectDifficulty() - }else if(name === "back"){ + } else if (name === "back") { this.toTitleScreen() - }else if(name === "session"){ + } else if (name === "session") { this.toSession() - }else if(name === "left"){ - if(shift){ - if(!repeat){ this.changeType(-1) } - }else{ + } else if (name === "left") { + if (shift) { + if (!repeat) { this.changeType(-1) } + } else { this.moveToSong(-1) } - }else if(name === "right"){ - if(shift){ - if(!repeat){ this.changeType(1) } - }else{ + } else if (name === "right") { + if (shift) { + if (!repeat) { this.changeType(1) } + } else { this.moveToSong(1) } - }else if(name === "jump_left" && !repeat){ + } else if (name === "jump_left" && !repeat) { this.changeType(-1) - }else if(name === "jump_right" && !repeat){ + } else if (name === "jump_right" && !repeat) { this.changeType(1) - }else if(name === "mute" || name === "ctrlGamepad"){ + } else if (name === "mute" || name === "ctrlGamepad") { this.endPreview(true) this.playBgm(false) } - }else if(this.state.screen === "difficulty"){ - if(event && event.keyCode && event.keyCode === 70 && ctrl){ + } else if (this.state.screen === "difficulty") { + if (event && event.keyCode && event.keyCode === 70 && ctrl) { this.search.display() - if(event){ + if (event) { event.preventDefault() } - }else if(name === "confirm"){ - if(this.selectedDiff === 0){ + } else if (name === "confirm") { + if (this.selectedDiff === 0) { this.toSongSelect() - }else if(this.selectedDiff === 2){ - this.toDownload() - }else if(this.selectedDiff === 3){ - this.toDelete() - }else if(this.selectedDiff === 1){ + } else if (this.selectedDiff === 1) { this.toOptions(1) - }else{ + } else if (this.selectedDiff === 2) { + this.toDownload() + } else if (this.selectedDiff === 3) { + this.toLeaderboard() + } else if (this.selectedDiff === 4) { + this.toDelete() + } else if (false) { + // Moved above + } else { this.toLoadSong(this.selectedDiff - this.diffOptions.length, shift, ctrl) } - }else if(name === "back" || name === "session"){ + } else if (name === "back" || name === "session") { this.toSongSelect() - }else if(name === "left"){ + } else if (name === "left") { this.moveToDiff(-1) - }else if(name === "right"){ + } else if (name === "right") { this.moveToDiff(1) - }else if(this.selectedDiff === 1 && (name === "up" || name === "down")){ + } else if (this.selectedDiff === 1 && (name === "up" || name === "down")) { this.toOptions(name === "up" ? -1 : 1) - }else if(name === "mute" || name === "ctrlGamepad"){ + } else if (name === "mute" || name === "ctrlGamepad") { this.endPreview(true) this.playBgm(false) } - }else if(this.state.screen === "title" || this.state.screen === "titleFadeIn"){ - if(event && event.keyCode && event.keyCode === 70 && ctrl){ + } else if (this.state.screen === "title" || this.state.screen === "titleFadeIn") { + if (event && event.keyCode && event.keyCode === 70 && ctrl) { this.search.display() - if(event){ + if (event) { event.preventDefault() } } } } - updateTypeLabel(){ + updateTypeLabel() { this.setAltText(this.typeLabel, this.songTypes[this.songTypeIndex]) } - changeType(delta){ + changeType(delta) { this.songTypeIndex = (this.songTypeIndex + delta + this.songTypes.length) % this.songTypes.length localStorage.setItem("songTypeIndex", this.songTypeIndex) this.updateTypeLabel() @@ -628,28 +638,28 @@ class SongSelect{ assets.songsDefault = songs assets.songs = assets.songsDefault new SongSelect(false, false, this.touchEnabled) - }).catch(() => {}) + }).catch(() => { }) } - - mouseDown(event){ - if(event.target === this.selectable || event.target.parentNode === this.selectable){ + + mouseDown(event) { + if (event.target === this.selectable || event.target.parentNode === this.selectable) { this.selectable.focus() - }else if(event.target.tagName !== "INPUT"){ + } else if (event.target.tagName !== "INPUT") { getSelection().removeAllRanges() this.selectable.blur() } - if(event.target !== this.canvas || !this.redrawRunning){ + if (event.target !== this.canvas || !this.redrawRunning) { return } - if(event.type === "mousedown"){ - if(event.which !== 1){ + if (event.type === "mousedown") { + if (event.which !== 1) { return } var mouse = this.mouseOffset(event.offsetX, event.offsetY) var shift = event.shiftKey var ctrl = event.ctrlKey var touch = false - }else{ + } else { event.preventDefault() var x = event.touches[0].pageX - this.canvas.offsetLeft var y = event.touches[0].pageY - this.canvas.offsetTop @@ -658,232 +668,234 @@ class SongSelect{ var ctrl = false var touch = true } - if(this.state.showWarning){ - if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){ + if (this.state.showWarning) { + if (408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550) { this.playSound("se_don") this.state.showWarning = false this.showWarning = false } - }else if(this.state.screen === "song"){ - if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){ + } else if (this.state.screen === "song") { + if (20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)) { this.categoryJump(mouse.x < 640 ? -1 : 1) - }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){ + } else if (!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts) { this.toAccount() - }else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){ + } else if (p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603) { this.toSession() - }else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket && p2.socket.readyState === 1 && !assets.customSongs){ + } else if (!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket && p2.socket.readyState === 1 && !assets.customSongs) { this.toSession() - }else{ + } else { var moveBy = this.songSelMouse(mouse.x, mouse.y) - if(moveBy === 0){ + if (moveBy === 0) { this.toSelectDifficulty() - }else if(moveBy !== null){ + } else if (moveBy !== null) { this.moveToSong(moveBy) } } - }else if(this.state.screen === "difficulty"){ + } else if (this.state.screen === "difficulty") { var moveBy = this.diffSelMouse(mouse.x, mouse.y) - if(mouse.x < 183 || mouse.x > 1095 || mouse.y < 54 || mouse.y > 554){ + if (mouse.x < 183 || mouse.x > 1095 || mouse.y < 54 || mouse.y > 554) { this.toSongSelect() - }else if(moveBy === 0){ + } else if (moveBy === 0) { this.selectedDiff = 0 this.toSongSelect() - }else if(moveBy === 2){ - this.toDownload() - }else if(moveBy === 3){ - this.toDelete() - }else if(moveBy === 1){ + } else if (moveBy === 1) { this.toOptions(1) - }else if(moveBy === "maker"){ + } else if (moveBy === 2) { + this.toDownload() + } else if (moveBy === 3) { + this.toLeaderboard() + } else if (moveBy === 4) { + this.toDelete() + } else if (moveBy === "maker") { window.open(this.songs[this.selectedSong].maker.url) - }else if(moveBy === this.diffOptions.length + 4){ + } else if (moveBy === this.diffOptions.length + 4) { this.state.ura = !this.state.ura this.playSound("se_ka", 0, p2.session ? p2.player : false) - if(this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura){ + if (this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura) { this.state.move = -1 } - }else if(moveBy !== null){ + } else if (moveBy !== null) { this.toLoadSong(moveBy - this.diffOptions.length, shift, ctrl, touch) } } } - touchEnd(event){ + touchEnd(event) { event.preventDefault() } - mouseWheel(event){ - if(this.state.screen === "song" && this.state.focused){ + mouseWheel(event) { + if (this.state.screen === "song" && this.state.focused) { this.wheelTimer = this.getMS() - if(event.deltaY < 0) { + if (event.deltaY < 0) { this.wheelScrolls-- - }else if(event.deltaY > 0){ + } else if (event.deltaY > 0) { this.wheelScrolls++ } } } - mouseMove(event){ + mouseMove(event) { var mouse = this.mouseOffset(event.offsetX, event.offsetY) var moveTo = null - if(this.state.showWarning){ - if(408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550){ + if (this.state.showWarning) { + if (408 < mouse.x && mouse.x < 872 && 470 < mouse.y && mouse.y < 550) { moveTo = "showWarning" } - }else if(this.state.screen === "song" && !this.search.opened){ - if(20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)){ + } else if (this.state.screen === "song" && !this.search.opened) { + if (20 < mouse.y && mouse.y < 90 && 410 < mouse.x && mouse.x < 880 && (mouse.x < 540 || mouse.x > 750)) { moveTo = mouse.x < 640 ? "categoryPrev" : "categoryNext" - }else if(!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts){ + } else if (!p2.session && 60 < mouse.x && mouse.x < 332 && 640 < mouse.y && mouse.y < 706 && gameConfig.accounts) { moveTo = "account" - }else if(p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603){ + } else if (p2.session && 438 < mouse.x && mouse.x < 834 && mouse.y > 603) { moveTo = "session" - }else if(!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket && p2.socket.readyState === 1 && !assets.customSongs){ + } else if (!p2.session && mouse.x > 641 && mouse.y > 603 && p2.socket && p2.socket.readyState === 1 && !assets.customSongs) { moveTo = "session" - }else{ + } else { var moveTo = this.songSelMouse(mouse.x, mouse.y) - if(moveTo === null && this.state.moveHover === 0 && !this.songs[this.selectedSong].courses){ + if (moveTo === null && this.state.moveHover === 0 && !this.songs[this.selectedSong].courses) { this.state.mouseMoveMS = this.getMS() - this.songSelecting.speed } } this.state.moveHover = moveTo - }else if(this.state.screen === "difficulty"){ + } else if (this.state.screen === "difficulty") { var moveTo = this.diffSelMouse(mouse.x, mouse.y) - if(moveTo === null && this.state.moveHover === this.selectedDiff){ + if (moveTo === null && this.state.moveHover === this.selectedDiff) { this.state.mouseMoveMS = this.getMS() - 1000 } this.state.moveHover = moveTo } this.pointer(moveTo !== null) } - mouseOffset(offsetX, offsetY){ + mouseOffset(offsetX, offsetY) { return { x: (offsetX * this.pixelRatio - this.winW / 2) / this.ratio + 1280 / 2, y: (offsetY * this.pixelRatio - this.winH / 2) / this.ratio + 720 / 2 } } - pointer(enabled){ - if(!this.canvas){ + pointer(enabled) { + if (!this.canvas) { return } - if(enabled && this.state.hasPointer === false){ + if (enabled && this.state.hasPointer === false) { this.canvas.style.cursor = "pointer" this.state.hasPointer = true - }else if(!enabled && this.state.hasPointer === true){ + } else if (!enabled && this.state.hasPointer === true) { this.canvas.style.cursor = "" this.state.hasPointer = false } } - - songSelMouse(x, y){ - if(this.state.locked === 0 && this.songAsset.marginTop <= y && y <= this.songAsset.marginTop + this.songAsset.height){ + + songSelMouse(x, y) { + if (this.state.locked === 0 && this.songAsset.marginTop <= y && y <= this.songAsset.marginTop + this.songAsset.height) { x -= 1280 / 2 var dir = x > 0 ? 1 : -1 x = Math.abs(x) var selectedWidth = this.songAsset.selectedWidth - if(!this.songs[this.selectedSong].courses){ + if (!this.songs[this.selectedSong].courses) { selectedWidth = this.songAsset.width } var moveBy = Math.ceil((x - selectedWidth / 2 - this.songAsset.marginLeft / 2) / (this.songAsset.width + this.songAsset.marginLeft)) * dir - if(moveBy / dir > 0){ + if (moveBy / dir > 0) { return moveBy - }else{ + } else { return 0 } } return null } - diffSelMouse(x, y){ - if(this.state.locked === 0){ - if(223 < x && x < 223 + 72 * this.diffOptions.length && 132 < y && y < 436){ + diffSelMouse(x, y) { + if (this.state.locked === 0) { + if (223 < x && x < 223 + 72 * this.diffOptions.length && 132 < y && y < 436) { return Math.floor((x - 223) / 72) - }else if(this.songs[this.selectedSong].maker && this.songs[this.selectedSong].maker.id > 0 && this.songs[this.selectedSong].maker.url && x > 230 && x < 485 && y > 446 && y < 533) { + } else if (this.songs[this.selectedSong].maker && this.songs[this.selectedSong].maker.id > 0 && this.songs[this.selectedSong].maker.url && x > 230 && x < 485 && y > 446 && y < 533) { return "maker" - }else if(550 < x && x < 1050 && 109 < y && y < 538){ + } else if (550 < x && x < 1050 && 109 < y && y < 538) { var moveBy = Math.floor((x - 550) / ((1050 - 550) / 5)) + this.diffOptions.length var currentSong = this.songs[this.selectedSong] - if( + if ( this.state.ura && moveBy === this.diffOptions.length + 3 || currentSong.courses[ - this.difficultyId[moveBy - this.diffOptions.length] + this.difficultyId[moveBy - this.diffOptions.length] ] - ){ + ) { return moveBy } } } return null } - - moveToSong(moveBy, fromP2){ + + moveToSong(moveBy, fromP2) { var ms = this.getMS() - if(p2.session && !fromP2){ - if(!this.state.selLock && ms > this.state.moveMS + 800){ + if (p2.session && !fromP2) { + if (!this.state.selLock && ms > this.state.moveMS + 800) { this.state.selLock = true p2.send("songsel", { song: this.mod(this.songs.length, this.selectedSong + moveBy) }) } - }else if(this.state.locked !== 1 || fromP2){ - if(this.songs[this.selectedSong].courses && !this.songs[this.selectedSong].unloaded && (this.state.locked === 0 || fromP2)){ + } else if (this.state.locked !== 1 || fromP2) { + if (this.songs[this.selectedSong].courses && !this.songs[this.selectedSong].unloaded && (this.state.locked === 0 || fromP2)) { this.state.moveMS = ms - }else{ + } else { this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize } this.state.move = moveBy this.state.lastMove = moveBy this.state.locked = 1 this.state.moveHover = null - + var lastMoveMul = Math.pow(Math.abs(moveBy), 1 / 4) var changeSpeed = this.songSelecting.speed * lastMoveMul var resize = changeSpeed * this.songSelecting.resize / lastMoveMul var scrollDelay = changeSpeed * this.songSelecting.scrollDelay var resize2 = changeSpeed - resize var scroll = resize2 - resize - scrollDelay * 2 - + var soundsDelay = Math.abs((scroll + resize) / moveBy) this.lastMoveBy = fromP2 ? fromP2.player : false - - for(var i = 0; i < Math.abs(moveBy) - 1; i++){ + + for (var i = 0; i < Math.abs(moveBy) - 1; i++) { this.playSound("se_ka", (resize + i * soundsDelay) / 1000, fromP2 ? fromP2.player : false) } this.pointer(false) } } - - categoryJump(moveBy, fromP2){ - if(p2.session && !fromP2){ + + categoryJump(moveBy, fromP2) { + if (p2.session && !fromP2) { var ms = this.getMS() - if(!this.state.selLock && ms > this.state.moveMS + 800){ + 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){ + } 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", 0, fromP2 ? fromP2.player : false) } } - moveToDiff(moveBy){ - if(this.state.locked !== 1){ + moveToDiff(moveBy) { + if (this.state.locked !== 1) { this.state.move = moveBy this.state.moveMS = this.getMS() - 500 this.state.locked = 1 this.playSound("se_ka", 0, p2.session ? p2.player : false) } } - - toSelectDifficulty(fromP2, playVoice=true){ + + toSelectDifficulty(fromP2, playVoice = true) { var currentSong = this.songs[this.selectedSong] - if(p2.session && !fromP2 && (!currentSong.action || !currentSong.p2Enabled)){ - if(this.songs[this.selectedSong].courses){ - if(!this.state.selLock){ + if (p2.session && !fromP2 && (!currentSong.action || !currentSong.p2Enabled)) { + if (this.songs[this.selectedSong].courses) { + if (!this.state.selLock) { this.state.selLock = true p2.send("songsel", { song: this.selectedSong, @@ -892,10 +904,10 @@ class SongSelect{ }) } } - }else if(this.state.locked === 0 || fromP2){ + } else if (this.state.locked === 0 || fromP2) { this.search.remove() - if(currentSong.courses){ - if(currentSong.unloaded){ + if (currentSong.courses) { + if (currentSong.unloaded) { return } @@ -905,168 +917,168 @@ class SongSelect{ this.state.locked = true this.state.moveHover = null this.state.ura = 0 - if(this.selectedDiff === this.diffOptions.length + 4){ + if (this.selectedDiff === this.diffOptions.length + 4) { this.selectedDiff = this.diffOptions.length + 3 } - + this.playSound("se_don", 0, fromP2 ? fromP2.player : false) assets.sounds["v_songsel"].stop() - if(!this.showWarning && prevScreen !== "difficulty" && playVoice){ + if (!this.showWarning && prevScreen !== "difficulty" && playVoice) { this.playSound("v_diffsel", 0.3) } pageEvents.send("song-select-difficulty", currentSong) - }else if(currentSong.action === "back"){ + } else if (currentSong.action === "back") { this.toTitleScreen() - }else if(currentSong.action === "random"){ - do{ + } else if (currentSong.action === "random") { + do { var i = Math.floor(Math.random() * this.songs.length) - }while(!this.songs[i].courses) + } while (!this.songs[i].courses) this.setSelectedSong(i) this.lastRandom = true this.playBgm(false) - this.toSelectDifficulty(false, playVoice=false) + this.toSelectDifficulty(false, playVoice = false) pageEvents.send("song-select-random") - }else if(currentSong.action === "search"){ + } else if (currentSong.action === "search") { this.search.display(true) - }else if(currentSong.action === "tutorial"){ + } else if (currentSong.action === "tutorial") { this.toTutorial() - }else if(currentSong.action === "about"){ + } else if (currentSong.action === "about") { this.toAbout() - }else if(currentSong.action === "settings"){ + } else if (currentSong.action === "settings") { this.toSettings() - }else if(currentSong.action === "customSongs"){ + } else if (currentSong.action === "customSongs") { this.toCustomSongs() - }else if(currentSong.action === "plugins"){ + } else if (currentSong.action === "plugins") { this.toPlugins() } - // カスタムメニューの実行処理 - else if (currentSong.action === "sourceCode") { - this.playSound("se_don"); - setTimeout(() => { - open("https://github.com/yuukialpha/taiko-web","_blank"); - }, 500); - } else if (currentSong.action === "upload") { - this.playSound("se_don"); - setTimeout(() => { - window.location.href = "https://zizhipu.taiko.asia"; - }, 100); - } else if (currentSong.action === "keijiban") { - this.playSound("se_don"); - setTimeout(() => { - window.location.href = "https://litey.trade/"; - }, 100); - } else if (currentSong.action === "songSelectingSpeed") { - this.playSound("se_don"); - setTimeout(() => { - let songSelectingSpeed = localStorage.getItem("sss") ?? "400"; - const pro = prompt("曲選択速度を入力してね!", songSelectingSpeed); - if (pro === null) { - // キャンセル - } else if (pro === "") { - songSelectingSpeed = "400"; - } else { - songSelectingSpeed = pro; - } - const preValue = localStorage.getItem("sss") ?? "400"; - localStorage.setItem("sss", songSelectingSpeed.toString()); - if (preValue !== songSelectingSpeed) { - location.reload(); - } - }, 100); - } else if (currentSong.action === "baisoku") { - this.playSound("se_don"); - setTimeout(() => { - let baisoku = localStorage.getItem("baisoku") ?? "1"; - const input = prompt("ばいそくの倍率を入力してね!", baisoku); - if (input === null) { - // キャンセル - } else if (input === "") { - baisoku = "1"; - } else { - baisoku = input; - } - localStorage.setItem("baisoku", baisoku.toString()); - }, 100); - } else if (currentSong.action === "doron") { - this.playSound("se_don"); - setTimeout(() => { - let doron = localStorage.getItem("doron") ?? "false"; - const input = prompt("ドロンを有効にするには\"true\"を入力してね!", doron); - if (input === null) { - // キャンセル - } else if (input === "") { - doron = "false"; - } else { - doron = input; - } - localStorage.setItem("doron", doron); - }, 100); - } else if (currentSong.action === "abekobe") { - this.playSound("se_don"); - setTimeout(() => { - let abekobe = localStorage.getItem("abekobe") ?? "false"; - const input = prompt("あべこべを有効にするには\"true\"を入力してね!", abekobe); - if (input === null) { - // キャンセル - } else if (input === "") { - abekobe = "false"; - } else { - abekobe = input; - } - localStorage.setItem("abekobe", abekobe); - }, 100); - } else if (currentSong.action === "detarame") { - this.playSound("se_don"); - setTimeout(() => { - let detarame = localStorage.getItem("detarame") ?? "0"; - const input = prompt("でたらめになる確率をパーセントで入力してね!", detarame); - if (input === null) { - // キャンセル - } else if (input === "") { - detarame = "0"; - } else { - detarame = input; - } - localStorage.setItem("detarame", detarame); - }, 100); - } else if (currentSong.action === "titlesort") { - this.playSound("se_don"); - setTimeout(() => { - let titlesort = localStorage.getItem("titlesort") ?? "false"; - const input = prompt("タイトル順で並べ替えするには\"true\"を入力してね!", titlesort); - if (input === null) { - // キャンセル - } else if (input === "") { - titlesort = "false"; - } else { - titlesort = input; - } - const preValue = localStorage.getItem("titlesort") ?? "false"; - localStorage.setItem("titlesort", titlesort); - if (preValue !== titlesort) { - location.reload(); - } - }, 100); - } + // カスタムメニューの実行処理 + else if (currentSong.action === "sourceCode") { + this.playSound("se_don"); + setTimeout(() => { + open("https://github.com/yuukialpha/taiko-web", "_blank"); + }, 500); + } else if (currentSong.action === "upload") { + this.playSound("se_don"); + setTimeout(() => { + window.location.href = "https://zizhipu.taiko.asia"; + }, 100); + } else if (currentSong.action === "keijiban") { + this.playSound("se_don"); + setTimeout(() => { + window.location.href = "https://litey.trade/"; + }, 100); + } else if (currentSong.action === "songSelectingSpeed") { + this.playSound("se_don"); + setTimeout(() => { + let songSelectingSpeed = localStorage.getItem("sss") ?? "400"; + const pro = prompt("曲選択速度を入力してね!", songSelectingSpeed); + if (pro === null) { + // キャンセル + } else if (pro === "") { + songSelectingSpeed = "400"; + } else { + songSelectingSpeed = pro; + } + const preValue = localStorage.getItem("sss") ?? "400"; + localStorage.setItem("sss", songSelectingSpeed.toString()); + if (preValue !== songSelectingSpeed) { + location.reload(); + } + }, 100); + } else if (currentSong.action === "baisoku") { + this.playSound("se_don"); + setTimeout(() => { + let baisoku = localStorage.getItem("baisoku") ?? "1"; + const input = prompt("ばいそくの倍率を入力してね!", baisoku); + if (input === null) { + // キャンセル + } else if (input === "") { + baisoku = "1"; + } else { + baisoku = input; + } + localStorage.setItem("baisoku", baisoku.toString()); + }, 100); + } else if (currentSong.action === "doron") { + this.playSound("se_don"); + setTimeout(() => { + let doron = localStorage.getItem("doron") ?? "false"; + const input = prompt("ドロンを有効にするには\"true\"を入力してね!", doron); + if (input === null) { + // キャンセル + } else if (input === "") { + doron = "false"; + } else { + doron = input; + } + localStorage.setItem("doron", doron); + }, 100); + } else if (currentSong.action === "abekobe") { + this.playSound("se_don"); + setTimeout(() => { + let abekobe = localStorage.getItem("abekobe") ?? "false"; + const input = prompt("あべこべを有効にするには\"true\"を入力してね!", abekobe); + if (input === null) { + // キャンセル + } else if (input === "") { + abekobe = "false"; + } else { + abekobe = input; + } + localStorage.setItem("abekobe", abekobe); + }, 100); + } else if (currentSong.action === "detarame") { + this.playSound("se_don"); + setTimeout(() => { + let detarame = localStorage.getItem("detarame") ?? "0"; + const input = prompt("でたらめになる確率をパーセントで入力してね!", detarame); + if (input === null) { + // キャンセル + } else if (input === "") { + detarame = "0"; + } else { + detarame = input; + } + localStorage.setItem("detarame", detarame); + }, 100); + } else if (currentSong.action === "titlesort") { + this.playSound("se_don"); + setTimeout(() => { + let titlesort = localStorage.getItem("titlesort") ?? "false"; + const input = prompt("タイトル順で並べ替えするには\"true\"を入力してね!", titlesort); + if (input === null) { + // キャンセル + } else if (input === "") { + titlesort = "false"; + } else { + titlesort = input; + } + const preValue = localStorage.getItem("titlesort") ?? "false"; + localStorage.setItem("titlesort", titlesort); + if (preValue !== titlesort) { + location.reload(); + } + }, 100); + } } this.pointer(false) } - toSongSelect(fromP2){ - if(p2.session && !fromP2){ - if(!this.state.selLock){ + toSongSelect(fromP2) { + if (p2.session && !fromP2) { + if (!this.state.selLock) { this.state.selLock = true p2.send("songsel", { song: this.lastRandom ? this.songs.findIndex(song => song.action === "random") : this.selectedSong }) } - - }else if(fromP2 || this.state.locked !== 1){ + + } else if (fromP2 || this.state.locked !== 1) { this.state.screen = "song" this.state.screenMS = this.getMS() this.state.locked = true this.state.moveHover = null - if(this.lastRandom){ + if (this.lastRandom) { this.endPreview(false) this.setSelectedSong(this.songs.findIndex(song => song.action === "random")) this.lastRandom = false @@ -1078,45 +1090,45 @@ class SongSelect{ this.clearHash() pageEvents.send("song-select-back") } - toLoadSong(difficulty, shift, ctrl, touch){ + toLoadSong(difficulty, shift, ctrl, touch) { this.clean() var selectedSong = this.songs[this.selectedSong] assets.sounds["v_diffsel"].stop() this.playSound("se_don", 0, p2.session ? p2.player : false) - - try{ - if(assets.customSongs){ + + try { + if (assets.customSongs) { assets.customSelected = this.selectedSong localStorage["customSelected"] = this.selectedSong - }else{ + } else { localStorage["selectedSong"] = this.selectedSong } localStorage["selectedDiff"] = difficulty + this.diffOptions.length - }catch(e){} - - if(difficulty === 3 && this.state.ura){ + } catch (e) { } + + if (difficulty === 3 && this.state.ura) { difficulty = 4 } var autoplay = false var multiplayer = false - if(p2.session || this.state.options === 2){ + if (p2.session || this.state.options === 2) { multiplayer = true - }else if(this.state.options === 1){ + } else if (this.state.options === 1) { autoplay = true - }else if(shift){ + } else if (shift) { autoplay = shift - }else if(p2.socket && p2.socket.readyState === 1 && !assets.customSongs){ + } else if (p2.socket && p2.socket.readyState === 1 && !assets.customSongs) { multiplayer = ctrl } var diff = this.difficultyId[difficulty] - + new LoadSong({ "title": selectedSong.title, "originalTitle": selectedSong.originalTitle, "folder": selectedSong.id, "difficulty": diff, "category": selectedSong.category, - "category_id":selectedSong.category_id, + "category_id": selectedSong.category_id, "type": selectedSong.type, "offset": selectedSong.offset, "songSkin": selectedSong.songSkin, @@ -1126,17 +1138,17 @@ class SongSelect{ "video": selectedSong.video, }, autoplay, multiplayer, touch) } - toOptions(moveBy){ - if(!p2.session){ + toOptions(moveBy) { + if (!p2.session) { this.playSound("se_ka", 0, p2.session ? p2.player : false) this.selectedDiff = 1 - do{ + do { this.state.options = this.mod(this.optionsList.length, this.state.options + moveBy) - }while((!p2.socket || p2.socket.readyState !== 1 || assets.customSongs) && this.state.options === 2) + } while ((!p2.socket || p2.socket.readyState !== 1 || assets.customSongs) && this.state.options === 2) } } - toTitleScreen(){ - if(!p2.session){ + toTitleScreen() { + if (!p2.session) { this.playSound("se_cancel") this.clean() setTimeout(() => { @@ -1144,45 +1156,45 @@ class SongSelect{ }, 500) } } - toTutorial(){ + toTutorial() { this.playSound("se_don") this.clean() setTimeout(() => { new Tutorial(true) }, 500) } - toAbout(){ + toAbout() { this.playSound("se_don") this.clean() setTimeout(() => { new About(this.touchEnabled) }, 500) } - toSettings(){ + toSettings() { this.playSound("se_don") this.clean() setTimeout(() => { new SettingsView(this.touchEnabled) }, 500) } - toAccount(){ + toAccount() { this.playSound("se_don") this.clean() setTimeout(() => { new Account(this.touchEnabled) }, 500) } - toSession(){ - if(p2.socket.readyState !== 1 || assets.customSongs){ + toSession() { + if (p2.socket.readyState !== 1 || assets.customSongs) { return } - if(p2.session){ + if (p2.session) { this.playSound("se_don") p2.send("gameend") this.state.moveHover = null - }else{ + } else { localStorage["selectedSong"] = this.selectedSong - + this.playSound("se_don") this.clean() setTimeout(() => { @@ -1190,8 +1202,8 @@ class SongSelect{ }, 500) } } - toCustomSongs(){ - if(assets.customSongs){ + toCustomSongs() { + if (assets.customSongs) { assets.customSongs = false assets.songs = assets.songsDefault delete assets.otherFiles @@ -1203,9 +1215,9 @@ class SongSelect{ localStorage.removeItem("customSelected") db.removeItem("customFolder") pageEvents.send("import-songs-default") - }else{ + } else { localStorage["selectedSong"] = this.selectedSong - + this.playSound("se_don") this.clean() setTimeout(() => { @@ -1213,47 +1225,47 @@ class SongSelect{ }, 500) } } - toPlugins(){ + toPlugins() { this.playSound("se_don") this.clean() setTimeout(() => { new SettingsView(this.touchEnabled, false, undefined, undefined, plugins.getSettings()) }, 500) } - - redraw(){ - if(!this.redrawRunning){ + + redraw() { + if (!this.redrawRunning) { return } requestAnimationFrame(this.redrawBind) var ms = this.getMS() - - for(var key in this.pressedKeys){ - if(this.pressedKeys[key]){ - if(ms >= this.pressedKeys[key] + (this.state.screen === "song" && (key === "right" || key === "left") ? 20 : 50)){ + + for (var key in this.pressedKeys) { + if (this.pressedKeys[key]) { + if (ms >= this.pressedKeys[key] + (this.state.screen === "song" && (key === "right" || key === "left") ? 20 : 50)) { this.keyPress(true, key, null, true) this.pressedKeys[key] = ms } } } - - if(!this.redrawRunning){ + + if (!this.redrawRunning) { return } - + var ctx = this.ctx var winW = innerWidth var winH = lastHeight - if(winW / 32 > winH / 9){ + if (winW / 32 > winH / 9) { winW = winH / 9 * 32 } this.pixelRatio = window.devicePixelRatio || 1 var resolution = settings.getItem("resolution") - if(resolution === "medium"){ + if (resolution === "medium") { this.pixelRatio *= 0.75 - }else if(resolution === "low"){ + } else if (resolution === "low") { this.pixelRatio *= 0.5 - }else if(resolution === "lowest"){ + } else if (resolution === "lowest") { this.pixelRatio *= 0.25 } winW *= this.pixelRatio @@ -1261,47 +1273,47 @@ class SongSelect{ var ratioX = winW / 1280 var ratioY = winH / 720 var ratio = (ratioX < ratioY ? ratioX : ratioY) - if(this.winW !== winW || this.winH !== winH){ + if (this.winW !== winW || this.winH !== winH) { this.canvas.width = Math.max(1, winW) this.canvas.height = Math.max(1, winH) ctx.scale(ratio, ratio) this.canvas.style.width = (winW / this.pixelRatio) + "px" this.canvas.style.height = (winH / this.pixelRatio) + "px" - + var borders = (this.songAsset.border + this.songAsset.innerBorder) * 2 var songsLength = Math.ceil(winW / ratio / (this.songAsset.width + this.songAsset.marginLeft)) + 1 - + this.songTitleCache.resize( (this.songAsset.width - borders + 1) * songsLength, this.songAsset.height - borders + 1, ratio + 0.2 ) - + this.currentSongCache.resize( (this.songAsset.width - borders + 1) * 2, this.songAsset.height - borders + 1, ratio + 0.2 ) - + var textW = strings.id === "en" ? 350 : 280 this.selectTextCache.resize((textW + 53 + 60 + 1) * 2, this.songAsset.marginTop + 15, ratio + 0.5) - + this.nameplateCache.resize(274, 134, ratio + 0.2) - + var lastCategory this.songs.forEach(song => { var cat = (song.category || "") + song.skin.outline - if(lastCategory !== cat){ + if (lastCategory !== cat) { lastCategory = cat } }) - this.categoryCache.resize(280, this.songAsset.marginTop + 1 , ratio + 0.5) - + this.categoryCache.resize(280, this.songAsset.marginTop + 1, ratio + 0.5) + this.difficultyCache.resize((44 + 56 + 2) * 5, 135 + 10, ratio + 0.5) - + var w = winW / ratio / 2 this.sessionCache.resize(w, 39 * 2, ratio + 0.5) - for(var id in this.sessionText){ + for (var id in this.sessionText) { this.sessionCache.set({ w: w, h: 38, @@ -1318,28 +1330,28 @@ class SongSelect{ align: "center", baseline: "middle" }, [ - {outline: "#000", letterBorder: 8}, - {fill: "#fff"} + { outline: "#000", letterBorder: 8 }, + { fill: "#fff" } ]) }) } - + this.selectableText = "" - - if(this.search.opened && this.search.container){ + + if (this.search.opened && this.search.container) { this.search.onInput(true) } - }else if(!document.hasFocus() && !p2.session){ - if(this.state.focused){ + } else if (!document.hasFocus() && !p2.session) { + if (this.state.focused) { this.state.focused = false this.songSelect.classList.add("unfocused") this.pressedKeys = {} } return - }else{ + } else { ctx.clearRect(0, 0, winW / ratio, winH / ratio) } - if(!this.state.focused){ + if (!this.state.focused) { this.state.focused = true this.songSelect.classList.remove("unfocused") } @@ -1348,7 +1360,7 @@ class SongSelect{ this.ratio = ratio winW /= ratio winH /= ratio - + var frameTop = winH / 2 - 720 / 2 var frameLeft = winW / 2 - 1280 / 2 var songTop = frameTop + this.songAsset.marginTop @@ -1356,44 +1368,44 @@ class SongSelect{ var songSelMoving = false var screen = this.state.screen var selectedWidth = this.songAsset.width - + this.search.redraw() - - if(this.wheelScrolls !== 0 && !this.state.locked && ms >= this.wheelTimer + 20) { - if(p2.session){ + + if (this.wheelScrolls !== 0 && !this.state.locked && ms >= this.wheelTimer + 20) { + if (p2.session) { this.moveToSong(this.wheelScrolls) - }else{ + } else { this.state.move = this.wheelScrolls this.state.waitPreview = ms + 400 this.endPreview() } this.wheelScrolls = 0 } - - if(screen === "title" || screen === "titleFadeIn"){ - if(ms > this.state.screenMS + 1000){ + + if (screen === "title" || screen === "titleFadeIn") { + if (ms > this.state.screenMS + 1000) { this.state.screen = "song" this.state.screenMS = ms + (ms - this.state.screenMS - 1000) this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize + (ms - this.state.screenMS) this.state.locked = 3 this.state.lastMove = 1 - }else{ + } else { this.state.moveMS = ms - this.songSelecting.speed * this.songSelecting.resize + (ms - this.state.screenMS - 1000) } - if(screen === "titleFadeIn" && ms > this.state.screenMS + 500){ + if (screen === "titleFadeIn" && ms > this.state.screenMS + 500) { this.state.screen = "title" screen = "title" } } - - if((screen === "song" || screen === "difficulty") && (this.showWarning && !this.showWarning.shown || scoreStorage.scoreSaveFailed)){ - if(!this.showWarning){ - this.showWarning = {name: "scoreSaveFailed"} + + if ((screen === "song" || screen === "difficulty") && (this.showWarning && !this.showWarning.shown || scoreStorage.scoreSaveFailed)) { + if (!this.showWarning) { + this.showWarning = { name: "scoreSaveFailed" } } - if(this.bgmEnabled){ + if (this.bgmEnabled) { this.playBgm(false) } - if(this.showWarning.name === "scoreSaveFailed"){ + if (this.showWarning.name === "scoreSaveFailed") { scoreStorage.scoreSaveFailed = false } this.showWarning.shown = true @@ -1401,8 +1413,8 @@ class SongSelect{ this.state.locked = true this.playSound("se_pause") } - - if(screen === "title" || screen === "titleFadeIn" || screen === "song"){ + + if (screen === "title" || screen === "titleFadeIn" || screen === "song") { var textW = strings.id === "en" ? 350 : 280 this.selectTextCache.get({ ctx: ctx, @@ -1423,16 +1435,16 @@ class SongSelect{ letterSpacing: strings.id === "en" ? 0 : 2, forceShadow: true }, [ - {x: -2, y: -2, outline: "#000", letterBorder: 22}, + { x: -2, y: -2, outline: "#000", letterBorder: 22 }, {}, - {x: 2, y: 2, shadow: [3, 3, 3]}, - {x: 2, y: 2, outline: "#ad1516", letterBorder: 10}, - {x: -2, y: -2, outline: "#ff797b"}, - {outline: "#f70808"}, - {fill: "#fff", shadow: [-1, 1, 3, 1.5]} + { x: 2, y: 2, shadow: [3, 3, 3] }, + { x: 2, y: 2, outline: "#ad1516", letterBorder: 10 }, + { x: -2, y: -2, outline: "#ff797b" }, + { outline: "#f70808" }, + { fill: "#fff", shadow: [-1, 1, 3, 1.5] } ]) }) - + var selectedSong = this.songs[this.selectedSong] var category = selectedSong.category this.draw.category({ @@ -1458,11 +1470,11 @@ class SongSelect{ h: this.songAsset.marginTop, id: category + selectedSong.skin.outline }, ctx => { - if(category){ - let cat = assets.categories.find(cat=>cat.title === category) - if(cat){ + if (category) { + let cat = assets.categories.find(cat => cat.title === category) + if (cat) { var categoryName = this.getLocalTitle(cat.title, cat.title_lang) - }else{ + } else { var categoryName = category } this.draw.layeredText({ @@ -1476,18 +1488,18 @@ class SongSelect{ align: "center", forceShadow: true }, [ - {outline: selectedSong.skin.outline, letterBorder: 12, shadow: [3, 3, 3]}, - {fill: "#fff"} + { outline: selectedSong.skin.outline, letterBorder: 12, shadow: [3, 3, 3] }, + { fill: "#fff" } ]) } }) } - - if(screen === "song"){ - if(this.songs[this.selectedSong].courses && !this.songs[this.selectedSong].unloaded){ + + if (screen === "song") { + if (this.songs[this.selectedSong].courses && !this.songs[this.selectedSong].unloaded) { selectedWidth = this.songAsset.selectedWidth } - + var lastMoveMul = Math.pow(Math.abs(this.state.lastMove || 0), 1 / 4) var changeSpeed = this.songSelecting.speed * lastMoveMul var resize = changeSpeed * (lastMoveMul === 0 ? 0 : this.songSelecting.resize / lastMoveMul) @@ -1495,46 +1507,46 @@ class SongSelect{ var resize2 = changeSpeed - resize var scroll = resize2 - resize - scrollDelay * 2 var elapsed = ms - this.state.moveMS - - if(this.state.catJump || (this.state.move && ms > this.state.moveMS + resize2 - scrollDelay)){ + + if (this.state.catJump || (this.state.move && ms > this.state.moveMS + resize2 - scrollDelay)) { var isJump = this.state.catJump var previousSelectedSong = this.selectedSong - - if(!isJump){ + + if (!isJump) { this.playSound("se_ka", 0, this.lastMoveBy) this.setSelectedSong(this.mod(this.songs.length, this.selectedSong + this.state.move)) - }else{ + } else { var currentCat = this.songs[this.selectedSong].category var currentIdx = this.mod(this.songs.length, this.selectedSong) - if(this.state.move > 0){ + if (this.state.move > 0) { var nextSong = this.songs.find(song => this.mod(this.songs.length, this.songs.indexOf(song)) > currentIdx && song.category !== currentCat && song.canJump) - if(!nextSong){ + if (!nextSong) { nextSong = this.songs[0] } - }else{ + } else { var isFirstInCat = this.songs.findIndex(song => song.category === currentCat) == this.selectedSong - if(!isFirstInCat){ + if (!isFirstInCat) { var nextSong = this.songs.find(song => this.mod(this.songs.length, this.songs.indexOf(song)) < currentIdx && song.category === currentCat && song.canJump) - }else{ + } else { var idx = this.songs.length - 1 var nextSong var lastCat - for(;idx>=0;idx--){ - if(this.songs[idx].category !== lastCat && this.songs[idx].action !== "back"){ + for (; idx >= 0; idx--) { + if (this.songs[idx].category !== lastCat && this.songs[idx].action !== "back") { lastCat = this.songs[idx].category - if(nextSong){ + if (nextSong) { break } } - if(lastCat !== currentCat && idx < currentIdx){ + if (lastCat !== currentCat && idx < currentIdx) { nextSong = idx } } nextSong = this.songs[nextSong] } - if(!nextSong){ + if (!nextSong) { var rev = [...this.songs].reverse() nextSong = rev.find(song => song.canJump) } @@ -1544,98 +1556,98 @@ class SongSelect{ this.state.catJump = false } - if(previousSelectedSong !== this.selectedSong){ + if (previousSelectedSong !== this.selectedSong) { pageEvents.send("song-select-move", this.songs[this.selectedSong]) } this.state.move = 0 this.state.locked = 2 - if(assets.customSongs){ + if (assets.customSongs) { assets.customSelected = this.selectedSong localStorage["customSelected"] = this.selectedSong - }else if(!p2.session){ - try{ + } else if (!p2.session) { + try { localStorage["selectedSong"] = this.selectedSong - }catch(e){} + } catch (e) { } } } - if(this.state.moveMS && ms < this.state.moveMS + changeSpeed){ + if (this.state.moveMS && ms < this.state.moveMS + changeSpeed) { xOffset = Math.min(scroll, Math.max(0, elapsed - resize - scrollDelay)) / scroll * (this.songAsset.width + this.songAsset.marginLeft) xOffset *= -this.state.move - if(elapsed < resize){ + if (elapsed < resize) { selectedWidth = this.songAsset.width + (((resize - elapsed) / resize) * (selectedWidth - this.songAsset.width)) - }else if(elapsed > resize2){ + } else if (elapsed > resize2) { this.playBgm(!this.songs[this.selectedSong].courses) this.state.locked = 1 selectedWidth = this.songAsset.width + ((elapsed - resize2) / resize * (selectedWidth - this.songAsset.width)) - }else{ + } else { songSelMoving = true selectedWidth = this.songAsset.width } - }else{ - if(this.previewing !== "muted"){ + } else { + if (this.previewing !== "muted") { this.playBgm(!this.songs[this.selectedSong].courses) } this.state.locked = 0 } - }else if(screen === "difficulty"){ + } else if (screen === "difficulty") { var currentSong = this.songs[this.selectedSong] - if(this.state.locked){ + if (this.state.locked) { this.state.locked = 0 } - if(this.state.move){ + if (this.state.move) { var hasUra = currentSong.courses.ura var previousSelection = this.selectedDiff - do{ - if(hasUra && this.state.move > 0){ + do { + if (hasUra && this.state.move > 0) { this.selectedDiff += this.state.move - if(this.selectedDiff > this.diffOptions.length + 4){ + if (this.selectedDiff > this.diffOptions.length + 4) { this.state.ura = !this.state.ura - if(this.state.ura){ + if (this.state.ura) { this.selectedDiff = previousSelection === this.diffOptions.length + 3 ? this.diffOptions.length + 4 : previousSelection break - }else{ + } else { this.state.move = -1 } } - }else{ + } else { this.selectedDiff = this.mod(this.diffOptions.length + 5, this.selectedDiff + this.state.move) } - }while( + } while ( this.selectedDiff >= this.diffOptions.length && !currentSong.courses[this.difficultyId[this.selectedDiff - this.diffOptions.length]] || this.selectedDiff === this.diffOptions.length + 3 && this.state.ura || this.selectedDiff === this.diffOptions.length + 4 && !this.state.ura ) this.state.move = 0 - }else if(this.selectedDiff < 0 || this.selectedDiff >= this.diffOptions.length && !currentSong.courses[this.difficultyId[this.selectedDiff - this.diffOptions.length]]){ + } else if (this.selectedDiff < 0 || this.selectedDiff >= this.diffOptions.length && !currentSong.courses[this.difficultyId[this.selectedDiff - this.diffOptions.length]]) { this.selectedDiff = 0 } } - - if(songSelMoving){ - if(this.previewing !== null){ + + if (songSelMoving) { + if (this.previewing !== null) { this.endPreview() } - }else if(screen !== "title" && screen !== "titleFadeIn" && ms > this.state.moveMS + 100){ - if(this.previewing !== "muted" && this.previewing !== this.selectedSong && "id" in this.songs[this.selectedSong]){ + } else if (screen !== "title" && screen !== "titleFadeIn" && ms > this.state.moveMS + 100) { + if (this.previewing !== "muted" && this.previewing !== this.selectedSong && "id" in this.songs[this.selectedSong]) { this.startPreview() } } - + this.songFrameCache = { w: this.songAsset.width + this.songAsset.selectedWidth + this.songAsset.fullWidth + (15 + 1) * 3, h: this.songAsset.fullHeight + 16, ratio: ratio } - - if(screen === "title" || screen === "titleFadeIn" || screen === "song"){ - for(var i = this.selectedSong - 1; ; i--){ + + if (screen === "title" || screen === "titleFadeIn" || screen === "song") { + for (var i = this.selectedSong - 1; ; i--) { var highlight = 0 - if(i - this.selectedSong === this.state.moveHover){ + if (i - this.selectedSong === this.state.moveHover) { highlight = 1 } var index = this.mod(this.songs.length, i) var _x = winW / 2 - (this.selectedSong - i) * (this.songAsset.width + this.songAsset.marginLeft) - selectedWidth / 2 + xOffset - if(_x + this.songAsset.width + this.songAsset.marginLeft < 0){ + if (_x + this.songAsset.width + this.songAsset.marginLeft < 0) { break } this.drawClosedSong({ @@ -1648,16 +1660,16 @@ class SongSelect{ }) } var startFrom - for(var i = this.selectedSong + 1; ; i++){ + 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){ + if (_x > winW) { startFrom = i - 1 break } } - for(var i = startFrom; i > this.selectedSong ; i--){ + for (var i = startFrom; i > this.selectedSong; i--) { var highlight = 0 - if(i - this.selectedSong === this.state.moveHover){ + if (i - this.selectedSong === this.state.moveHover) { highlight = 1 } var index = this.mod(this.songs.length, i) @@ -1673,37 +1685,37 @@ class SongSelect{ }) } } - + var currentSong = this.songs[this.selectedSong] var highlight = 0 - if(!currentSong.courses){ + if (!currentSong.courses) { highlight = 2 } - if(this.state.moveHover === 0){ + if (this.state.moveHover === 0) { highlight = 1 } var selectedSkin = this.songSkin.selected - if(screen === "title" || screen === "titleFadeIn" || this.state.locked === 3 || currentSong.unloaded){ + if (screen === "title" || screen === "titleFadeIn" || this.state.locked === 3 || currentSong.unloaded) { selectedSkin = currentSong.skin highlight = 2 - }else if(songSelMoving){ + } else if (songSelMoving) { selectedSkin = currentSong.skin highlight = 0 } var selectedHeight = this.songAsset.height - if(screen === "difficulty"){ + if (screen === "difficulty") { selectedWidth = this.songAsset.fullWidth selectedHeight = this.songAsset.fullHeight highlight = 0 } - - if(this.lastCurrentSong.title !== currentSong.title || this.lastCurrentSong.subtitle !== currentSong.subtitle){ + + if (this.lastCurrentSong.title !== currentSong.title || this.lastCurrentSong.subtitle !== currentSong.subtitle) { this.lastCurrentSong.title = currentSong.title this.lastCurrentSong.subtitle = currentSong.subtitle this.currentSongCache.clear() } - - if(selectedWidth === this.songAsset.width){ + + if (selectedWidth === this.songAsset.width) { this.drawSongCrown({ ctx: ctx, song: currentSong, @@ -1711,7 +1723,7 @@ class SongSelect{ y: songTop + this.songAsset.height - selectedHeight }) } - + this.draw.songFrame({ ctx: ctx, x: winW / 2 - selectedWidth / 2 + xOffset, @@ -1730,10 +1742,10 @@ class SongSelect{ disabled: p2.session && currentSong.action && !currentSong.p2Enabled, innerContent: (x, y, w, h) => { ctx.strokeStyle = "#000" - if(screen === "title" || screen === "titleFadeIn" || screen === "song"){ + if (screen === "title" || screen === "titleFadeIn" || screen === "song") { var opened = ((selectedWidth - this.songAsset.width) / (this.songAsset.selectedWidth - this.songAsset.width)) var songSel = true - }else{ + } else { var textW = strings.id === "en" ? 350 : 280 this.selectTextCache.get({ ctx: ctx, @@ -1753,19 +1765,19 @@ class SongSelect{ width: textW, forceShadow: true }, [ - {x: -2, y: -2, outline: "#000", letterBorder: 23}, + { x: -2, y: -2, outline: "#000", letterBorder: 23 }, {}, - {x: 2, y: 2, shadow: [3, 3, 3]}, - {x: 2, y: 2, outline: "#ad1516", letterBorder: 10}, - {x: -2, y: -2, outline: "#ff797b"}, - {outline: "#f70808"}, - {fill: "#fff", shadow: [-1, 1, 3, 1.5]} + { x: 2, y: 2, shadow: [3, 3, 3] }, + { x: 2, y: 2, outline: "#ad1516", letterBorder: 10 }, + { x: -2, y: -2, outline: "#ff797b" }, + { outline: "#f70808" }, + { fill: "#fff", shadow: [-1, 1, 3, 1.5] } ]) }) var opened = 1 var songSel = false - - for(var i = 0; i < this.diffOptions.length; i++){ + + for (var i = 0; i < this.diffOptions.length; i++) { var _x = x + 62 + i * 72 var _y = y + 67 ctx.fillStyle = this.diffOptions[i].fill @@ -1790,12 +1802,12 @@ class SongSelect{ y: _y + 28, iconName: this.diffOptions[i].iconName }) - + var text = this.diffOptions[i].text - if(this.diffOptions[i].iconName === "options" && (this.selectedDiff === i || this.state.options !== 0)){ + if (this.diffOptions[i].iconName === "options" && (this.selectedDiff === i || this.state.options !== 0)) { text = this.optionsList[this.state.options] } - + this.draw.verticalText({ ctx: ctx, text: text, @@ -1811,14 +1823,14 @@ class SongSelect{ fontFamily: this.font, letterSpacing: this.diffOptions[i].letterSpacing }) - + var highlight = 0 - if(this.state.moveHover === i){ + if (this.state.moveHover === i) { highlight = 2 - }else if(this.selectedDiff === i){ + } else if (this.selectedDiff === i) { highlight = 1 } - if(highlight){ + if (highlight) { this.draw.highlight({ ctx: ctx, x: _x - 32, @@ -1830,7 +1842,7 @@ class SongSelect{ opacity: highlight === 2 ? 0.8 : 1, radius: 24 }) - if(this.selectedDiff === i && !this.touchEnabled){ + if (this.selectedDiff === i && !this.touchEnabled) { this.draw.diffCursor({ ctx: ctx, font: this.font, @@ -1843,24 +1855,24 @@ class SongSelect{ } } var drawDifficulty = (ctx, i, currentUra) => { - if(currentSong.courses[this.difficultyId[i]] || currentUra){ + if (currentSong.courses[this.difficultyId[i]] || currentUra) { var crownDiff = currentUra ? "ura" : this.difficultyId[i] var players = p2.session ? 2 : 1 var score = [scoreStorage.get(currentSong.hash, false, true)] - if(p2.session){ + if (p2.session) { score[p2.player === 1 ? "push" : "unshift"](scoreStorage.getP2(currentSong.hash, false, true)) } var reversed = false - for(var a = players; a--;){ + for (var a = players; a--;) { var crownType = "" var p = reversed ? -(a - 1) : a - if(score[p] && score[p][crownDiff]){ + if (score[p] && score[p][crownDiff]) { crownType = score[p][crownDiff].crown } - if(!reversed && players === 2 && p === 1 && crownType){ + if (!reversed && players === 2 && p === 1 && crownType) { reversed = true a++ - }else{ + } else { this.draw.crown({ ctx: ctx, type: crownType, @@ -1871,7 +1883,7 @@ class SongSelect{ }) } } - if(songSel && !this.state.move){ + if (songSel && !this.state.move) { var _x = x + 33 + i * 60 var _y = y + 120 ctx.fillStyle = currentUra ? "#006279" : "#ff9f18" @@ -1887,7 +1899,7 @@ class SongSelect{ scale: 1, border: 6 }) - }else{ + } else { var _x = x + 402 + i * 100 var _y = y + 87 this.draw.diffIcon({ @@ -1946,7 +1958,7 @@ class SongSelect{ var moveMS = Math.max(this.state.moveMS, this.state.mouseMoveMS) var elapsedMS = this.state.screenMS > moveMS || !songSel ? this.state.screenMS : moveMS var fade = ((ms - elapsedMS) % 2000) / 2000 - if(songBranch && fade > 0.25 && fade < 0.75){ + if (songBranch && fade > 0.25 && fade < 0.75) { this.draw.verticalText({ ctx: ctx, text: strings.songBranch, @@ -1960,19 +1972,19 @@ class SongSelect{ outline: songSel ? false : "#f22666", outlineSize: songSel ? 0 : this.songAsset.letterBorder }) - }else{ - for(var j = 0; j < 10; j++){ - if(songSel){ + } else { + for (var j = 0; j < 10; j++) { + if (songSel) { var yPos = _y + 113 + j * 17 - }else{ + } else { var yPos = _y + 178 + j * 19.5 } - if(10 - j > songStars){ + if (10 - j > songStars) { ctx.fillStyle = currentUra ? "#187085" : (songSel ? "#e97526" : "#e7e7e7") ctx.beginPath() ctx.arc(_x, yPos, songSel ? 4.5 : 5, 0, Math.PI * 2) ctx.fill() - }else{ + } else { this.draw.diffStar({ ctx: ctx, songSel: songSel, @@ -1985,17 +1997,17 @@ class SongSelect{ } } var currentDiff = this.selectedDiff - this.diffOptions.length - if(this.selectedDiff === 4 + this.diffOptions.length){ + if (this.selectedDiff === 4 + this.diffOptions.length) { currentDiff = 3 } - if(!songSel){ + if (!songSel) { var highlight = 0 - if(this.state.moveHover - this.diffOptions.length === i){ + if (this.state.moveHover - this.diffOptions.length === i) { highlight = 2 - }else if(currentDiff === i){ + } else if (currentDiff === i) { highlight = 1 } - if(currentDiff === i && !this.touchEnabled){ + if (currentDiff === i && !this.touchEnabled) { this.draw.diffCursor({ ctx: ctx, font: this.font, @@ -2005,7 +2017,7 @@ class SongSelect{ two: p2.session && p2.player === 2 }) } - if(highlight){ + if (highlight) { this.draw.highlight({ ctx: ctx, x: _x - 32, @@ -2020,18 +2032,18 @@ class SongSelect{ } } } - for(var i = 0; currentSong.courses && i < 4; i++){ + for (var i = 0; currentSong.courses && i < 4; i++) { var currentUra = i === 3 && (this.state.ura && !songSel || currentSong.courses.ura && songSel) - if(songSel && currentUra){ + if (songSel && currentUra) { drawDifficulty(ctx, i, false) var elapsedMS = Math.max(this.state.screenMS, this.state.moveMS, this.state.mouseMoveMS) var fade = ((ms - elapsedMS) % 4000) / 4000 var alphaFade = 0 - if(fade > 0.95){ + if (fade > 0.95) { alphaFade = this.draw.easeOut(1 - (fade - 0.95) * 20) - }else if(fade > 0.5){ + } else if (fade > 0.5) { alphaFade = 1 - }else if(fade > 0.45){ + } else if (fade > 0.45) { alphaFade = this.draw.easeIn((fade - 0.45) * 20) } this.draw.alpha(alphaFade, ctx, ctx => { @@ -2039,16 +2051,16 @@ class SongSelect{ ctx.fillRect(x + 7 + i * 60, y + 60, 52, 352) drawDifficulty(ctx, i, true) }, winW, winH) - }else{ + } else { drawDifficulty(ctx, i, currentUra) } } - for(var i = 0; currentSong.courses && i < 4; i++){ - if(!songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){ + for (var i = 0; currentSong.courses && i < 4; i++) { + if (!songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1) { var _x = x + 402 + i * 100 var _y = y + 87 var currentDiff = this.selectedDiff - this.diffOptions.length - if(this.selectedDiff === 4 + this.diffOptions.length){ + if (this.selectedDiff === 4 + this.diffOptions.length) { currentDiff = 3 } this.draw.diffCursor({ @@ -2062,14 +2074,14 @@ class SongSelect{ }) } } - + 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){ + + if (currentSong.subtitle) { this.currentSongCache.get({ ctx: ctx, x: x + textX - textW, @@ -2094,22 +2106,22 @@ class SongSelect{ }) }) } - + var hasMaker = currentSong.maker || currentSong.maker === 0 var hasVideo = currentSong.video || currentSong.video === 0 - if(hasMaker || currentSong.lyrics){ + if (hasMaker || currentSong.lyrics) { if (songSel) { var _x = x + 38 var _y = y + 10 ctx.strokeStyle = "#000" ctx.lineWidth = 5 - - if(hasMaker){ + + if (hasMaker) { var grd = ctx.createLinearGradient(_x, _y, _x, _y + 50) grd.addColorStop(0, "#fa251a") grd.addColorStop(1, "#ffdc33") ctx.fillStyle = grd - }else{ + } else { ctx.fillStyle = "#000" } this.draw.roundedRect({ @@ -2122,8 +2134,8 @@ class SongSelect{ }) ctx.fill() ctx.stroke() - - if(hasMaker){ + + if (hasMaker) { this.draw.layeredText({ ctx: ctx, text: strings.creative.creative, @@ -2135,10 +2147,10 @@ class SongSelect{ y: _y + (strings.id === "ja" || strings.id === "en" ? 25 : 28), width: 172 }, [ - {outline: "#fff", letterBorder: 6}, - {fill: "#000"} + { outline: "#fff", letterBorder: 6 }, + { fill: "#000" } ]) - }else{ + } else { this.draw.layeredText({ ctx: ctx, text: strings.withLyrics, @@ -2150,15 +2162,15 @@ class SongSelect{ y: _y + (strings.id === "ja" || strings.id === "en" ? 25 : 28), width: 172 }, [ - {fill: currentSong.skin.border[0]} + { fill: currentSong.skin.border[0] } ]) } - } else if(currentSong.maker && currentSong.maker.id > 0 && currentSong.maker.name){ + } else if (currentSong.maker && currentSong.maker.id > 0 && currentSong.maker.name) { var _x = x + 62 var _y = y + 380 ctx.lineWidth = 5 - var grd = ctx.createLinearGradient(_x, _y, _x, _y+50); + var grd = ctx.createLinearGradient(_x, _y, _x, _y + 50); grd.addColorStop(0, '#fa251a'); grd.addColorStop(1, '#ffdc33'); @@ -2187,8 +2199,8 @@ class SongSelect{ x: _x - 15, y: _y + 23 }, [ - {outline: "#000", letterBorder: 8}, - {fill: "#fff"} + { outline: "#000", letterBorder: 8 }, + { fill: "#fff" } ]) this.draw.layeredText({ @@ -2202,11 +2214,11 @@ class SongSelect{ y: _y + 56, width: 210 }, [ - {outline: "#fff", letterBorder: 8}, - {fill: "#000"} + { outline: "#fff", letterBorder: 8 }, + { fill: "#000" } ]) - if(this.state.moveHover === "maker"){ + if (this.state.moveHover === "maker") { this.draw.highlight({ ctx: ctx, x: _x - 32, @@ -2219,10 +2231,10 @@ class SongSelect{ } } } - - for(var i = 0; currentSong.courses && i < 4; i++){ - if(currentSong.courses[this.difficultyId[i]] || currentUra){ - if(songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1){ + + for (var i = 0; currentSong.courses && i < 4; i++) { + if (currentSong.courses[this.difficultyId[i]] || currentUra) { + if (songSel && i === currentSong.p2Cursor && p2.socket.readyState === 1) { var _x = x + 33 + i * 60 var _y = y + 120 this.draw.diffCursor({ @@ -2237,8 +2249,8 @@ class SongSelect{ } } } - - if(!songSel && currentSong.courses.ura){ + + if (!songSel && currentSong.courses.ura) { var fade = ((ms - this.state.screenMS) % 1200) / 1200 var _x = x + 402 + 4 * 100 + fade * 25 var _y = y + 258 @@ -2316,7 +2328,7 @@ class SongSelect{ fontFamily: this.font }) } - if(selectedSkin.outline === "#000"){ + if (selectedSkin.outline === "#000") { this.currentSongCache.get({ ctx: ctx, x: x + textX, @@ -2325,7 +2337,7 @@ class SongSelect{ h: textH, id: "title", }, verticalTitle) - }else{ + } else { this.songTitleCache.get({ ctx: ctx, x: x + textX, @@ -2335,7 +2347,7 @@ class SongSelect{ id: currentSong.title + selectedSkin.outline, }, verticalTitle) } - if(!songSel && this.selectableText !== currentSong.title){ + if (!songSel && this.selectableText !== currentSong.title) { this.draw.verticalText({ ctx: ctx, text: currentSong.title, @@ -2354,13 +2366,13 @@ class SongSelect{ } } }) - - if(screen !== "difficulty" && this.selectableText){ + + if (screen !== "difficulty" && this.selectableText) { this.selectableText = "" this.selectable.style.display = "none" } - - if(songSelMoving){ + + if (songSelMoving) { this.draw.highlight({ ctx: ctx, x: winW / 2 - selectedWidth / 2, @@ -2370,7 +2382,7 @@ class SongSelect{ opacity: 0.8 }) } - + ctx.fillStyle = "#000" ctx.fillRect(0, frameTop + 595, 1280 + frameLeft * 2, 125 + frameTop) var x = 0 @@ -2402,11 +2414,11 @@ class SongSelect{ ctx.lineTo(x + w - 4, y + h) ctx.lineTo(x + w - 4, y + 4) ctx.fill() - - if(!p2.session || p2.player === 1){ + + if (!p2.session || p2.player === 1) { var name = account.loggedIn ? account.displayName : strings.defaultName var rank = account.loggedIn || !gameConfig.accounts || p2.session ? false : strings.notLoggedIn - }else{ + } else { var name = p2.name || strings.defaultName var rank = false } @@ -2427,7 +2439,7 @@ class SongSelect{ font: this.font }) }) - if(this.state.moveHover === "account"){ + if (this.state.moveHover === "account") { this.draw.highlight({ ctx: ctx, x: frameLeft + 59.5, @@ -2439,8 +2451,8 @@ class SongSelect{ size: 10 }) } - - if(p2.session){ + + if (p2.session) { x = x + w + 4 w = 396 this.draw.pattern({ @@ -2470,7 +2482,7 @@ class SongSelect{ ctx.lineTo(x + w - 4, y + h) ctx.lineTo(x + w - 4, y + 4) ctx.fill() - if(this.state.moveHover === "session"){ + if (this.state.moveHover === "session") { this.draw.highlight({ ctx: ctx, x: x, @@ -2481,10 +2493,10 @@ class SongSelect{ }) } } - + x = p2.session ? frameLeft + 642 + 200 : frameLeft + 642 w = p2.session ? frameLeft + 638 - 200 : frameLeft + 638 - if(p2.session){ + if (p2.session) { this.draw.pattern({ ctx: ctx, img: assets.image["bg_score_p2"], @@ -2497,7 +2509,7 @@ class SongSelect{ scale: 1.55 }) ctx.fillStyle = "rgba(138, 245, 247, 0.5)" - }else{ + } else { this.draw.pattern({ ctx: ctx, img: assets.image["bg_settings"], @@ -2519,22 +2531,22 @@ class SongSelect{ ctx.lineTo(x + 4, y + 4) ctx.lineTo(x + 4, y + h) ctx.fill() - if(screen !== "difficulty" && p2.socket && p2.socket.readyState === 1 && !assets.customSongs){ + if (screen !== "difficulty" && p2.socket && p2.socket.readyState === 1 && !assets.customSongs) { var elapsed = (ms - this.state.screenMS) % 3100 var fade = 1 - if(!p2.session && screen === "song"){ - if(elapsed > 2800){ + if (!p2.session && screen === "song") { + if (elapsed > 2800) { fade = (elapsed - 2800) / 300 - }else if(2000 < elapsed){ - if(elapsed < 2300){ + } else if (2000 < elapsed) { + if (elapsed < 2300) { fade = 1 - (elapsed - 2000) / 300 - }else{ + } else { fade = 0 } } } - if(fade > 0){ - if(fade < 1){ + if (fade > 0) { + if (fade < 1) { ctx.globalAlpha = this.draw.easeIn(fade) } this.sessionCache.get({ @@ -2547,7 +2559,7 @@ class SongSelect{ }) ctx.globalAlpha = 1 } - if(!p2.session && this.state.moveHover === "session"){ + if (!p2.session && this.state.moveHover === "session") { this.draw.highlight({ ctx: ctx, x: x, @@ -2558,10 +2570,10 @@ class SongSelect{ }) } } - if(p2.session){ - if(p2.player === 1){ + if (p2.session) { + if (p2.player === 1) { var name = p2.name || strings.default2PName - }else{ + } else { var name = account.loggedIn ? account.displayName : strings.default2PName } this.nameplateCache.get({ @@ -2582,17 +2594,17 @@ class SongSelect{ }) }) } - - if(this.state.showWarning){ - if(this.preview){ + + if (this.state.showWarning) { + if (this.preview) { this.endPreview() } ctx.fillStyle = "rgba(0, 0, 0, 0.5)" ctx.fillRect(0, 0, winW, winH) - + ctx.save() ctx.translate(frameLeft, frameTop) - + var pauseRect = (ctx, mul) => { this.draw.roundedRect({ ctx: ctx, @@ -2617,15 +2629,15 @@ class SongSelect{ dx: 68, dy: 11 }) - if(this.showWarning.name === "scoreSaveFailed"){ + if (this.showWarning.name === "scoreSaveFailed") { var text = strings.scoreSaveFailed - }else if(this.showWarning.name === "loadSongError"){ + } else if (this.showWarning.name === "loadSongError") { var text = [] var textIndex = 0 var subText = [this.showWarning.title, this.showWarning.id, this.showWarning.error] var textParts = strings.loadSongError.split("%s") textParts.forEach((textPart, i) => { - if(i !== 0){ + if (i !== 0) { text.push(subText[textIndex++]) } text.push(textPart) @@ -2646,7 +2658,7 @@ class SongSelect{ verticalAlign: "middle", textAlign: "center" }) - + var _x = 640 var _y = 470 var _w = 464 @@ -2662,8 +2674,8 @@ class SongSelect{ }) ctx.fill() var layers = [ - {outline: "#000", letterBorder: 10}, - {fill: "#fff"} + { outline: "#000", letterBorder: 10 }, + { fill: "#fff" } ] this.draw.layeredText({ ctx: ctx, @@ -2677,12 +2689,12 @@ class SongSelect{ letterSpacing: -1, align: "center" }, layers) - + var highlight = 1 - if(this.state.moveHover === "showWarning"){ + if (this.state.moveHover === "showWarning") { highlight = 2 } - if(highlight){ + if (highlight) { this.draw.highlight({ ctx: ctx, x: _x - _w / 2 - 3.5, @@ -2695,39 +2707,39 @@ class SongSelect{ radius: 30 }) } - + ctx.restore() } - - if(screen === "titleFadeIn"){ + + if (screen === "titleFadeIn") { ctx.save() - + var elapsed = ms - this.state.screenMS ctx.globalAlpha = Math.max(0, 1 - elapsed / 500) ctx.fillStyle = "#000" ctx.fillRect(0, 0, winW, winH) - + ctx.restore() } - - if(p2.session && (!this.lastScoreMS || ms > this.lastScoreMS + 1000)){ + + if (p2.session && (!this.lastScoreMS || ms > this.lastScoreMS + 1000)) { this.lastScoreMS = ms scoreStorage.eventLoop() } } - drawBackground(cat){ - if(this.songSkin[cat] && this.songSkin[cat].bg_img){ + drawBackground(cat) { + if (this.songSkin[cat] && this.songSkin[cat].bg_img) { let filename = this.songSkin[cat].bg_img.slice(0, this.songSkin[cat].bg_img.lastIndexOf(".")) this.songSelect.style.backgroundImage = "url('" + assets.image[filename].src + "')" - }else{ + } else { this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_def"].src + "')" } } - - drawClosedSong(config){ + + drawClosedSong(config) { var ctx = config.ctx - + this.drawSongCrown(config) config.width = this.songAsset.width config.height = this.songAsset.height @@ -2765,7 +2777,7 @@ class SongSelect{ }) } this.draw.songFrame(config) - if("p2Cursor" in config.song && config.song.p2Cursor !== null && p2.socket.readyState === 1){ + if ("p2Cursor" in config.song && config.song.p2Cursor !== null && p2.socket.readyState === 1) { this.draw.diffCursor({ ctx: ctx, font: this.font, @@ -2777,23 +2789,23 @@ class SongSelect{ }) } } - - drawSongCrown(config){ - if(!config.song.action && config.song.hash){ + + drawSongCrown(config) { + if (!config.song.action && config.song.hash) { var ctx = config.ctx var players = p2.session ? 2 : 1 var score = [scoreStorage.get(config.song.hash, false, true)] var scoreDrawn = [] - if(p2.session){ + if (p2.session) { score[p2.player === 1 ? "push" : "unshift"](scoreStorage.getP2(config.song.hash, false, true)) } - for(var i = this.difficultyId.length; i--;){ + for (var i = this.difficultyId.length; i--;) { var diff = this.difficultyId[i] - for(var p = players; p--;){ - if(!score[p] || scoreDrawn[p]){ + for (var p = players; p--;) { + if (!score[p] || scoreDrawn[p]) { continue } - if(config.song.courses[this.difficultyId[i]] && score[p][diff] && score[p][diff].crown){ + if (config.song.courses[this.difficultyId[i]] && score[p][diff] && score[p][diff].crown) { this.draw.crown({ ctx: ctx, type: score[p][diff].crown, @@ -2817,76 +2829,76 @@ class SongSelect{ } } } - - startPreview(loadOnly){ - if(!loadOnly && this.state && this.state.showWarning || this.state.waitPreview > this.getMS()){ + + startPreview(loadOnly) { + if (!loadOnly && this.state && this.state.showWarning || this.state.waitPreview > this.getMS()) { return } var currentSong = this.songs[this.selectedSong] var id = currentSong.id var prvTime = currentSong.preview this.endPreview() - - if("id" in currentSong){ + + if ("id" in currentSong) { var startLoad = this.getMS() - if(loadOnly){ + if (loadOnly) { var currentId = null - }else{ + } else { var currentId = this.previewId this.previewing = this.selectedSong } var songObj = this.previewList.find(song => song && song.id === id) - - if(songObj){ - if(!loadOnly){ + + if (songObj) { + if (!loadOnly) { this.preview = songObj.preview_sound this.preview.gain = snd.previewGain this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume) } - }else{ - songObj = {id: id} - if(currentSong.previewMusic){ + } else { + songObj = { id: id } + if (currentSong.previewMusic) { songObj.preview_time = 0 var promise = snd.previewGain.load(currentSong.previewMusic).catch(() => { songObj.preview_time = prvTime return snd.previewGain.load(currentSong.music) }) - }else if(currentSong.unloaded){ + } else if (currentSong.unloaded) { var promise = this.getUnloaded(this.selectedSong, songObj, currentId) - }else if(currentSong.sound){ + } else if (currentSong.sound) { songObj.preview_time = prvTime currentSong.sound.gain = snd.previewGain var promise = Promise.resolve(currentSong.sound) - }else if(currentSong.music !== "muted"){ + } else if (currentSong.music !== "muted") { songObj.preview_time = prvTime var promise = snd.previewGain.load(currentSong.music) - }else{ + } else { return } promise.then(sound => { - if(currentId === this.previewId || loadOnly){ + if (currentId === this.previewId || loadOnly) { songObj.preview_sound = sound - if(!loadOnly){ + if (!loadOnly) { this.preview = sound this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume) } var oldPreview = this.previewList.shift() - if(oldPreview){ + if (oldPreview) { oldPreview.preview_sound.clean() } this.previewList.push(songObj) - }else{ + } else { sound.clean() } }).catch(e => { - if(e !== "cancel"){ + if (e !== "cancel") { return Promise.reject(e) } }) } } } - previewLoaded(startLoad, prvTime, volume){ + previewLoaded(startLoad, prvTime, volume) { var endLoad = this.getMS() var difference = endLoad - startLoad var minDelay = 300 @@ -2894,26 +2906,26 @@ class SongSelect{ snd.previewGain.setVolumeMul(volume || 1) this.preview.playLoop(delay / 1000, false, prvTime) } - endPreview(force){ + endPreview(force) { this.previewId++ this.previewing = force ? "muted" : null - if(this.preview){ + if (this.preview) { this.preview.stop() } } - playBgm(enabled){ - if(enabled && this.state && this.state.showWarning){ + playBgm(enabled) { + if (enabled && this.state && this.state.showWarning) { return } - if(enabled && !this.bgmEnabled){ + if (enabled && !this.bgmEnabled) { this.bgmEnabled = true snd.musicGain.fadeIn(0.4) - }else if(!enabled && this.bgmEnabled){ + } else if (!enabled && this.bgmEnabled) { this.bgmEnabled = false snd.musicGain.fadeOut(0.4) } } - getUnloaded(selectedSong, songObj, currentId){ + getUnloaded(selectedSong, songObj, currentId) { var currentSong = this.songs[selectedSong] var file = currentSong.chart var importSongs = new ImportSongs(false, assets.otherFiles) @@ -2928,39 +2940,39 @@ class SongSelect{ importSongs.clean() songObj.preview_time = imported.preview var index = assets.songs.findIndex(song => song.id === currentSong.id) - if(index !== -1){ + if (index !== -1) { assets.songs[index] = imported } this.songs[selectedSong] = this.addSong(imported) this.state.moveMS = this.getMS() - this.songSelecting.speed * this.songSelecting.resize - if(imported.music && currentId === this.previewId){ + if (imported.music && currentId === this.previewId) { return snd.previewGain.load(imported.music).then(sound => { imported.sound = sound this.songs[selectedSong].sound = sound return sound.copy() }) - }else{ + } else { return Promise.reject("cancel") } }) } - addSong(song){ + addSong(song) { var title = this.getLocalTitle(song.title, song.title_lang) var subtitle = this.getLocalTitle(title === song.title ? song.subtitle : "", song.subtitle_lang) var skin = null var categoryName = "" var originalCategory = "" - if(song.category_id !== null && song.category_id !== undefined){ + if (song.category_id !== null && song.category_id !== undefined) { var category = assets.categories.find(cat => cat.id === song.category_id) var categoryName = this.getLocalTitle(category.title, category.title_lang) var originalCategory = category.title var skin = this.songSkin[category.title] - }else if(song.category){ + } else if (song.category) { var categoryName = song.category var originalCategory = song.category } - if(!categoryName){ - if(song.song_type){ + if (!categoryName) { + if (song.song_type) { categoryName = song.song_type originalCategory = song.song_type } @@ -2977,40 +2989,40 @@ class SongSelect{ canJump: true, hash: song.hash || song.title } - for(var i in song){ - if(!(i in addedSong)){ + for (var i in song) { + if (!(i in addedSong)) { addedSong[i] = song[i] } } return addedSong } - - onusers(response){ + + onusers(response) { var p2InSong = false this.songs.forEach(song => { song.p2Cursor = null }) - if(response && response.value){ + if (response && response.value) { response.value.forEach(idDiff => { - var id = idDiff.id |0 + var id = idDiff.id | 0 var diff = idDiff.diff var diffId = this.difficultyId.indexOf(diff) - if(diffId > 3){ + if (diffId > 3) { diffId = 3 } - if(diffId >= 0){ + if (diffId >= 0) { var index = 0 var currentSong = this.songs.find((song, i) => { index = i return song.id === id }) - if(currentSong){ + if (currentSong) { currentSong.p2Cursor = diffId - if(p2.session && currentSong.courses){ + if (p2.session && currentSong.courses) { this.setSelectedSong(index) this.state.move = 0 - if(this.state.screen !== "difficulty"){ - this.toSelectDifficulty({player: response.value.player}) + if (this.state.screen !== "difficulty") { + this.toSelectDifficulty({ player: response.value.player }) } this.search.enabled = false p2InSong = true @@ -3021,132 +3033,132 @@ class SongSelect{ }) } - if(!this.search.enabled && !p2InSong){ + if (!this.search.enabled && !p2InSong) { this.search.enabled = true } } - onsongsel(response){ - if(response && response.value){ + onsongsel(response) { + if (response && response.value) { var selected = false - if(response.type === "songsel" && "selected" in response.value){ + if (response.type === "songsel" && "selected" in response.value) { selected = response.value.selected } - if("fromRandom" in response.value && response.value.fromRandom === true){ + if ("fromRandom" in response.value && response.value.fromRandom === true) { this.lastRandom = true } - if("song" in response.value){ + if ("song" in response.value) { var song = +response.value.song - if(song >= 0 && song < this.songs.length){ - if(response.type === "catjump"){ + if (song >= 0 && song < this.songs.length) { + if (response.type === "catjump") { var moveBy = response.value.move - if(moveBy === -1 || moveBy === 1){ + if (moveBy === -1 || moveBy === 1) { this.setSelectedSong(song) - this.categoryJump(moveBy, {player: response.value.player}) + this.categoryJump(moveBy, { player: response.value.player }) } - }else if(!selected){ + } else if (!selected) { this.state.locked = true - if(this.state.screen === "difficulty"){ + if (this.state.screen === "difficulty") { this.toSongSelect(true) } var moveBy = song - this.selectedSong - if(moveBy){ - if(this.selectedSong < song){ + if (moveBy) { + if (this.selectedSong < song) { var altMoveBy = -this.mod(this.songs.length, this.selectedSong - song) - }else{ + } else { var altMoveBy = this.mod(this.songs.length, moveBy) } - if(Math.abs(altMoveBy) < Math.abs(moveBy)){ + if (Math.abs(altMoveBy) < Math.abs(moveBy)) { moveBy = altMoveBy } - this.moveToSong(moveBy, {player: response.value.player}) + this.moveToSong(moveBy, { player: response.value.player }) } - }else if(this.songs[song].courses){ + } else if (this.songs[song].courses) { this.setSelectedSong(song) this.state.move = 0 - if(this.state.screen !== "difficulty"){ + if (this.state.screen !== "difficulty") { this.playBgm(false) - this.toSelectDifficulty({player: response.value.player}) + this.toSelectDifficulty({ player: response.value.player }) } } } } } } - oncatjump(response){ - if(response && response.value){ - if("song" in response.value){ + oncatjump(response) { + if (response && response.value) { + if ("song" in response.value) { var song = +response.value.song - if(song >= 0 && song < this.songs.length){ + if (song >= 0 && song < this.songs.length) { this.state.locked = true } } } } - startP2(){ + startP2() { this.onusers(p2.getMessage("users")) - if(p2.session){ + if (p2.session) { this.onsongsel(p2.getMessage("songsel")) } pageEvents.add(p2, "message", response => { - if(response.type == "users"){ + if (response.type == "users") { this.onusers(response) } - if(p2.session && (response.type == "songsel" || response.type == "catjump")){ + if (p2.session && (response.type == "songsel" || response.type == "catjump")) { this.onsongsel(response) this.state.selLock = false } }) - if(p2.closed){ + if (p2.closed) { p2.open() } } - - mod(length, index){ + + mod(length, index) { return ((index % length) + length) % length } - - getLocalTitle(title, titleLang){ - if(titleLang){ - if(strings.id === "cn"){ - if(titleLang.cn){ + + getLocalTitle(title, titleLang) { + if (titleLang) { + if (strings.id === "cn") { + if (titleLang.cn) { return titleLang.cn } - if(titleLang.ja){ + if (titleLang.ja) { return titleLang.ja } return title } - for(var id in titleLang){ - if(id === "en" && strings.preferEn && !(strings.id in titleLang) && titleLang.en || id === strings.id && titleLang[id]){ + for (var id in titleLang) { + if (id === "en" && strings.preferEn && !(strings.id in titleLang) && titleLang.en || id === strings.id && titleLang[id]) { return titleLang[id] } } } return title } - - clearHash(){ - if(location.hash.toLowerCase().startsWith("#song=")){ + + clearHash() { + if (location.hash.toLowerCase().startsWith("#song=")) { p2.hash("") } } - - playSound(id, time, snd){ - if(!this.drumSounds && (id === "se_don" || id === "se_ka" || id === "se_cancel")){ + + playSound(id, time, snd) { + if (!this.drumSounds && (id === "se_don" || id === "se_ka" || id === "se_cancel")) { return } var ms = Date.now() + (time || 0) * 1000 - if(!(id in this.playedSounds) || ms > this.playedSounds[id] + 30){ + if (!(id in this.playedSounds) || ms > this.playedSounds[id] + 30) { assets.sounds[id + (snd ? "_p" + snd : "")].play(time) this.playedSounds[id] = ms } } - - getMS(){ + + getMS() { return Date.now() } - - clean(){ + + clean() { this.keyboard.clean() this.gamepad.clean() this.clearHash() @@ -3160,7 +3172,7 @@ class SongSelect{ this.nameplateCache.clean() this.search.clean() assets.sounds["bgm_songsel"].stop() - if(!this.bgmEnabled){ + if (!this.bgmEnabled) { snd.musicGain.fadeIn() setTimeout(() => { snd.buffer.loadSettings() @@ -3169,14 +3181,14 @@ class SongSelect{ this.redrawRunning = false this.endPreview() this.previewList.forEach(song => { - if(song){ + if (song) { song.preview_sound.clean() } }) pageEvents.remove(loader.screen, ["mousemove", "mouseleave", "mousedown", "touchstart"]) pageEvents.remove(this.canvas, ["touchend", "wheel"]) pageEvents.remove(p2, "message") - if(this.touchEnabled && fullScreenSupported){ + if (this.touchEnabled && fullScreenSupported) { pageEvents.remove(this.touchFullBtn, "click") delete this.touchFullBtn } @@ -3185,7 +3197,7 @@ class SongSelect{ delete this.canvas } - toDownload(){ + toDownload() { var jsZip = new JSZip() var zip = new jsZip() var song = this.songs[this.selectedSong] @@ -3196,38 +3208,38 @@ class SongSelect{ var musicBlob var lyricsBlob var blobs = [] - if(song.chart){ + if (song.chart) { var charts = [] - if(song.chart.separateDiff){ - for(var i in song.chart){ - if(song.chart[i] && i !== "separateDiff"){ + if (song.chart.separateDiff) { + for (var i in song.chart) { + if (song.chart[i] && i !== "separateDiff") { charts.push(song.chart[i]) } } - }else{ + } else { charts.push(song.chart) } charts.forEach(chart => { promises.push(chart.blob().then(blob => { var promise - if(!chartParsed){ + if (!chartParsed) { chartParsed = true - if(song.type === "tja"){ + if (song.type === "tja") { promise = readFile(blob, false, "utf-8").then(dataRaw => { var data = dataRaw ? dataRaw.replace(/\0/g, "").split("\n") : [] var tja = new ParseTja(data, "oni", 0, 0, true) - for(var diff in tja.metadata){ + for (var diff in tja.metadata) { var meta = tja.metadata[diff] - if(meta.wave){ + if (meta.wave) { musicFilename = meta.wave } } }) - }else if(song.type === "osu"){ + } else if (song.type === "osu") { promise = readFile(blob).then(dataRaw => { var data = dataRaw ? dataRaw.replace(/\0/g, "").split("\n") : [] var osu = new ParseOsu(data, "oni", 0, 0, true) - if(osu.generalInfo.AudioFilename){ + if (osu.generalInfo.AudioFilename) { musicFilename = osu.generalInfo.AudioFilename } }) @@ -3237,7 +3249,7 @@ class SongSelect{ name: chart.name, data: blob } - if(song.type === "tja" && !song.chart.separateDiff){ + if (song.type === "tja" && !song.chart.separateDiff) { chartBlob = outputBlob } blobs.push(outputBlob) @@ -3245,7 +3257,7 @@ class SongSelect{ })) }) } - if(song.music){ + if (song.music) { promises.push(song.music.blob().then(blob => { musicBlob = { name: song.music.name, @@ -3264,30 +3276,30 @@ class SongSelect{ // })) // } Promise.all(promises).then(() => { - if(musicFilename){ - if(musicBlob){ + if (musicFilename) { + if (musicBlob) { musicBlob.name = musicFilename } var filename = musicFilename var index = filename.lastIndexOf(".") - if(index !== -1){ + if (index !== -1) { filename = filename.slice(0, index) } - if(chartBlob){ + if (chartBlob) { chartBlob.name = filename + ".tja" } - if(lyricsBlob){ + if (lyricsBlob) { lyricsBlob.name = filename + ".vtt" } } blobs.forEach(blob => zip.file(blob.name, blob.data)) - }).then(() => zip.generateAsync({type: "blob"})).then(zip => { + }).then(() => zip.generateAsync({ type: "blob" })).then(zip => { var url = URL.createObjectURL(zip) var link = document.createElement("a") link.href = url - if("download" in HTMLAnchorElement.prototype){ + if ("download" in HTMLAnchorElement.prototype) { link.download = song.title + ".zip" - }else{ + } else { link.target = "_blank" } link.innerText = "." @@ -3322,4 +3334,19 @@ class SongSelect{ alert(text); }); } + toLeaderboard() { + if (!this.songs[this.selectedSong].id) { + return + } + // Default to first available difficulty if not in a valid difficulty selection + var selectedDiff = this.selectedDiff - this.diffOptions.length + if (selectedDiff < 0) { + selectedDiff = 3 // Default to oni + } + var diffId = this.difficultyId[selectedDiff] + + this.clean() + this.playSound("se_don") + new Leaderboard().display(this.songs[this.selectedSong].id, diffId) + } } diff --git a/public/src/views/leaderboard.html b/public/src/views/leaderboard.html new file mode 100644 index 0000000..8d99928 --- /dev/null +++ b/public/src/views/leaderboard.html @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/schema.py b/schema.py index a012b02..482c618 100644 --- a/schema.py +++ b/schema.py @@ -80,3 +80,14 @@ scores_save = { } } } + +leaderboard_submit = { + '$schema': 'http://json-schema.org/schema#', + 'type': 'object', + 'properties': { + 'song_id': {'type': 'number'}, + 'difficulty': {'type': 'string'}, + 'score': {'type': 'object'} + }, + 'required': ['song_id', 'difficulty', 'score'] +} diff --git a/templates/index.html b/templates/index.html index 5e1812a..e462e15 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,17 +1,20 @@ + 太鼓ウェブ - Taiko Web | (゚∀゚) - - + + - + @@ -24,14 +27,17 @@ +
{% if version.version and version.commit_short and version.commit %} - vLightNova 1.0.0 + vLightNova 1.1.0 {% else %} - vLightNova 1.0.0 + vLightNova + 1.1.0 {% endif %}
@@ -43,4 +49,5 @@ - + + \ No newline at end of file