From 8465294b382d5f8787e815b6c18306096d7b5434 Mon Sep 17 00:00:00 2001 From: vvo <> Date: Mon, 14 Oct 2024 22:42:28 +0800 Subject: [PATCH] world league --- README.md | 44 +-- data/world.ts | 101 +++++-- handlers/ddrworld.ts | 163 +++++++++++- index.ts | 2 +- models/ddrworld.ts | 36 +-- webui/css/datatables.css | 499 +++++++++++++++++++++++++++++++++++ webui/js/common.js | 125 +++++++++ webui/js/flaredata.js | 86 ++++++ webui/js/profile_details.js | 206 ++++----------- webui/profile_details.pug | 1 + webui/profile_flare data.pug | 84 ++++++ webui/profile_music data.pug | 1 + 12 files changed, 1125 insertions(+), 223 deletions(-) create mode 100644 webui/css/datatables.css create mode 100644 webui/js/common.js create mode 100644 webui/js/flaredata.js create mode 100644 webui/profile_flare data.pug diff --git a/README.md b/README.md index 5f0bf31..b93ec51 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # DanceDanceRevolution -**Plugin Version:** fork-mdx-3.0.1 +**Plugin Version:** fork-mdx-3.0.2 **Supported game versions:** WORLD (2024091000) @@ -28,6 +28,27 @@ musicdb.xml Usage Guide Changelog =========== +### fork-mdx-3.0.2 + +- WORLD LEAGUE + - I did my best emulating what I understand how WORLD LEAGUE works, so my apologies if there's something that isn't accurately implemented. But this is how it works right now: + - Promotion and demotion borders are determined by the league score of the player in rank 1. If you play alone on your server, you'll automatically be rank 1 all the time. + - Bronze class promotion border is set to >= 50% of the rank 1's score. + - Silver class promotion and demotion borders are set to >= 65% and <= 15% of the rank 1's score, respectively. + - Gold class demotion border is set to <= 15% as well. + - League info and period is defined in data/world.ts:LEAGUE_WORLD. + - League period ends after 'end' datetime. + - Promotion/demotion occurs after 'summary' datetime. + - Class benefits will apply depending on your class. + - Note: Since difficulty level info isn't revealed until the songs are officially released, I cannot add them to the list yet. I will update this plugin with the correct song info once they are released officially. +- Privilege of early play: this filter now displays applicable songs (Grand Prix advanced play songs) +- WebUI stuff + - Flare Data Page: displays your top 30 songs for Classic, White and Gold. +- Fixes + - Rewrote getLastGhostId function. + - Fixed "So What" and "Akatsuki" diffLv mix up. + + ### fork-mdx-3.0.1 - Support for 2024091000. @@ -58,24 +79,13 @@ Changelog - ghostdata saving and loading (WIP, idk what ghost is) -### fork-mdx-3.0.0a - -- Flare skill song unlock event - - Added event data (ddr@asphyxia/data/world.ts:EVENTS_WORLD) - - Fixes crashes on Flare Skill rank up (at least until Mercury, haven't tested higher than that yet.) -- musicdata_load - - Put your musicdb.xml on 'ddr@asphyxia/data' folder. Tested with A3 musicdb.xml - - Added musicdata for new WORLD songs (ddr@asphyxia/data/world.ts:SONGS_WORLD) - - To do: =========== 1. Look for more missing features -2. Refactor getLastGhostId -3. Refactor hiscore code -4. More WebUI stuff -5. Figure out unknown values in score_str -6. Rival loading and figure out unknown values in rival record_str -7. Proper loading of Flare skill in-game (make sure to include only top 30 scores from classic, white and gold) +2. Refactor hiscore code +3. More WebUI stuff +4. Figure out unknown values in score_str +5. Rival loading and figure out unknown values in rival record_str +6. Proper loading of Flare skill in-game (make sure to include only top 30 scores from classic, white and gold) diff --git a/data/world.ts b/data/world.ts index 5bf124e..1c7dd6b 100644 --- a/data/world.ts +++ b/data/world.ts @@ -20,7 +20,7 @@ export const SONGS_WORLD = [ { mcode: 38706, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [1, 4, 9, 13, 0, 0, 4, 9, 13, 0] }, { mcode: 38705, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [2, 6, 10, 13, 0, 0, 6, 10, 13, 0] }, { mcode: 38727, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [3, 7, 11, 14, 0, 0, 7, 11, 14, 0] }, - { mcode: 38739, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 5, 9, 12, 15, 0, 5, 9, 12, 15] }, + { mcode: 38739, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [3, 5, 9, 12, 15, 0, 5, 9, 12, 15] }, { mcode: 38664, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [3, 7, 9, 12, 0, 0, 7, 9, 12, 0] }, { mcode: 38670, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [4, 7, 10, 13, 0, 0, 7, 10, 13, 0] }, { mcode: 38680, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [3, 6, 11, 14, 0, 0, 6, 11, 14, 0] }, @@ -43,16 +43,19 @@ export const SONGS_WORLD = [ { mcode: 38744, limited_ary: [2, 2, 2, 2, -1, -1, 2, 2, 2, -1], diffLv: [4, 7, 13, 17, 0, 0, 7, 13, 17, 0] }, { mcode: 38747, limited_ary: [2, 2, 2, 2, -1, -1, 2, 2, 2, -1], diffLv: [4, 10, 15, 18, 0, 0, 10, 15, 18, 0] }, { mcode: 38748, limited_ary: [2, 2, 2, 2, -1, -1, 2, 2, 2, -1], diffLv: [4, 9, 13, 16, 0, 0, 9, 13, 16, 0] }, - { mcode: 38734, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [2, 2, 7, 11, 13, 0, 2, 7, 11, 14] }, - { mcode: 38749, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 6, 10, 13, 8, 0, 6, 10, 13, 9] }, + { mcode: 38749, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [2, 2, 7, 11, 13, 0, 2, 7, 11, 14] }, + { mcode: 38734, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 6, 10, 13, 8, 0, 6, 10, 13, 9] }, - { mcode: 38737, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 6, 11, 13, 16, 0, 6, 11, 13, 16] }, - { mcode: 38738, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [2, 5, 8, 12, 17, 5, 8, 12, 17] }, + { mcode: 38737, limited_ary: [2, 2, 2, 2, 2, -1, 2, 2, 2, 2], diffLv: [3, 6, 11, 13, 16, 0, 6, 11, 13, 16] }, + { mcode: 38738, limited_ary: [2, 2, 2, 2, 2, -1, 2, 2, 2, 2], diffLv: [2, 5, 8, 12, 17, 5, 8, 12, 17] }, - { mcode: 37222, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [2, 4, 10, 13, 0, 0, 4, 9, 13, 0] }, - { mcode: 37604, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [2, 6, 9, 12, 14, 0, 5, 9, 12, 14] }, + { mcode: 37222, limited_ary: [2, 2, 2, 2, -1, -1, 2, 2, 2, -1], diffLv: [2, 4, 10, 13, 0, 0, 4, 9, 13, 0] }, + { mcode: 37604, limited_ary: [2, 2, 2, 2, 2, -1, 2, 2, 2, 2], diffLv: [2, 6, 9, 12, 14, 0, 5, 9, 12, 14] }, { mcode: 37234, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [1, 3, 7, 11, 0, 0, 3, 7, 11, 0] }, - { mcode: 37363, limited_ary: [0, 0, 0, 0, -1, -1, 0, 0, 0, -1], diffLv: [2, 5, 9, 13, 0, 0, 5, 9, 13, 0] } + { mcode: 37363, limited_ary: [2, 2, 2, 2, -1, -1, 2, 2, 2, -1], diffLv: [2, 5, 9, 13, 0, 0, 5, 9, 13, 0] } + + // songs that have yet to release. unknown difficulty lvls. + // { mcode: 38622, limited_ary: [], diffLv: [] } ] @@ -205,20 +208,21 @@ export const SONGS_OVERRIDE_WORLD = [ { mcode: 38652, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [2, 6, 10, 15, 17, 0, 6, 10, 15, 17] }, { mcode: 37251, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [6, 10, 12, 15, 18, 0, 10, 11, 16, 17] }, - { mcode: 38212, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 7, 10, 15, 16, 0, 8, 11, 15, 16] }, - { mcode: 38295, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 7, 11, 14, 17, 0, 7, 11, 14, 17] }, - { mcode: 38258, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [2, 6, 10, 14, 16, 0, 6, 11, 14, 16] }, - { mcode: 38263, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [4, 7, 11, 14, 16, 0, 8, 12, 15, 16] }, - { mcode: 38195, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [5, 7, 10, 13, 17, 0, 7, 10, 13, 17] }, - { mcode: 38420, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [4, 8, 12, 15, 17, 0, 8, 12, 15, 17] }, - { mcode: 38405, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 6, 9, 13, 17, 0, 5, 9, 14, 17] }, - { mcode: 38442, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [3, 8, 13, 16, 18, 0, 8, 13, 16, 18] }, - { mcode: 38436, limited_ary: [0, 0, 0, 0, 0, -1, 0, 0, 0, 0], diffLv: [4, 7, 11, 14, 17, 0, 7, 11, 14, 17] } + { mcode: 38212, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [3, 7, 10, 15, 16, 0, 8, 11, 15, 16] }, + { mcode: 38295, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [3, 7, 11, 14, 17, 0, 7, 11, 14, 17] }, + { mcode: 38258, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [2, 6, 10, 14, 16, 0, 6, 11, 14, 16] }, + { mcode: 38263, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [4, 7, 11, 14, 16, 0, 8, 12, 15, 16] }, + { mcode: 38195, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [5, 7, 10, 13, 17, 0, 7, 10, 13, 17] }, + { mcode: 38420, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [4, 8, 12, 15, 17, 0, 8, 12, 15, 17] }, + { mcode: 38405, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [3, 6, 9, 13, 17, 0, 5, 9, 14, 17] }, + { mcode: 38442, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [3, 8, 13, 16, 18, 0, 8, 13, 16, 18] }, + { mcode: 38436, limited_ary: [0, 0, 0, 0, 2, -1, 0, 0, 0, 2], diffLv: [4, 7, 11, 14, 17, 0, 7, 11, 14, 17] } ] export const EVENTS_WORLD = [ { id: 89, no: 0, cond: 0, rwrd: 0, type: 9999 }, { id: 96, no: 0, cond: 0, rwrd: 0, type: 9999 }, + { id: 101, no: 0, cond: 0, rwrd: 0, type: 9999 }, { id: 1, no: 1, cond: 1, rwrd: 38667, type: 70 }, { id: 2, no: 1, cond: 1, rwrd: 38667, type: 71 }, { id: 3, no: 1, cond: 1, rwrd: 38667, type: 72 }, { id: 4, no: 1, cond: 1, rwrd: 38667, type: 73 }, { id: 5, no: 1, cond: 1, rwrd: 38661, type: 70 }, { id: 6, no: 1, cond: 1, rwrd: 38661, type: 71 }, { id: 7, no: 1, cond: 1, rwrd: 38661, type: 72 }, { id: 8, no: 1, cond: 1, rwrd: 38661, type: 73 }, @@ -248,5 +252,64 @@ export const EVENTS_WORLD = [ { id: 86, no: 0, cond: 1, rwrd: 38747, type: 17, comp: 0, save: 1 }, { id: 87, no: 0, cond: 1, rwrd: 38748, type: 17, comp: 0, save: 1 }, { id: 88, no: 0, cond: 1, rwrd: 1189, type: 201, save: 1 }, - { id: 89, no: 0, cond: 1, rwrd: 1188, type: 201, save: 1 } -] \ No newline at end of file + { id: 89, no: 0, cond: 1, rwrd: 1188, type: 201, save: 1 }, + { id: 90, no: 0, cond: 1, rwrd: 38737, type: 50 }, + { id: 91, no: 0, cond: 1, rwrd: 38737, type: 52 }, + { id: 92, no: 0, cond: 1, rwrd: 38738, type: 50 }, + { id: 93, no: 0, cond: 1, rwrd: 38738, type: 52 }, + { id: 94, no: 0, cond: 1, rwrd: 38212, type: 52 }, + { id: 95, no: 0, cond: 1, rwrd: 38295, type: 52 }, + { id: 96, no: 0, cond: 1, rwrd: 38258, type: 52 }, + { id: 97, no: 0, cond: 1, rwrd: 38263, type: 52 }, + { id: 98, no: 0, cond: 1, rwrd: 38195, type: 52 }, + { id: 99, no: 0, cond: 1, rwrd: 38739, type: 52 }, + { id: 100, no: 0, cond: 1, rwrd: 38420, type: 52 }, + { id: 101, no: 0, cond: 1, rwrd: 38405, type: 52 }, + { id: 102, no: 0, cond: 1, rwrd: 38442, type: 52 }, + { id: 103, no: 0, cond: 1, rwrd: 37222, type: 50 }, + { id: 104, no: 0, cond: 1, rwrd: 37604, type: 50 }, + { id: 105, no: 0, cond: 1, rwrd: 37604, type: 52 }, + { id: 106, no: 0, cond: 1, rwrd: 37234, type: 50 }, + { id: 107, no: 0, cond: 1, rwrd: 37363, type: 50 }, + { id: 108, no: 0, cond: 1, rwrd: 38436, type: 52 } +] + +export const LEAGUE_WORLD = [ + { + id: 1, + name: "第1回 WORLD LEAGUE", + name_eng: "The 1st WORLD LEAGUE", + start: BigInt(Date.parse('8 Oct 2024 01:00:00 GMT')), + end: BigInt(Date.parse('6 Nov 2024 08:00:00 GMT')), + summary: BigInt(Date.parse('6 Nov 2024 09:00:00 GMT')), + advanceBorder: [0, 0, 0] + } +] + +export const LOCKED_SONGS = [ + { + unlock_date: BigInt(Date.parse("1 Jul 2024 01:00:00 GMT")), + ids: [38583], + ids_cha: [] + }, + { + unlock_date: BigInt(Date.parse("31 Jul 2024 01:00:00 GMT")), + ids: [38591, 38593, 38597, 38592, 38598, 38595, 38596, 38594, 38599], + ids_cha: [38591] + }, + { + unlock_date: BigInt(Date.parse("30 Aug 2024 01:00:00 GMT")), + ids: [], + ids_cha: [38625, 38626, 38627] + }, + { + unlock_date: BigInt(Date.parse("29 Nov 2024 01:00:00 GMT")), + ids: [38632, 38618, 38619, 38637, 38639, 38638], + ids_cha: [38102, 38517] + }, + { + unlock_date: BigInt(Date.parse("27 Dec 2024 01:00:00 GMT")), + ids: [38644, 38647, 38645, 38651, 38648, 38650, 38646, 38649], + ids_cha: [38138, 38017] + } +]; diff --git a/handlers/ddrworld.ts b/handlers/ddrworld.ts index ee67e76..968cddf 100644 --- a/handlers/ddrworld.ts +++ b/handlers/ddrworld.ts @@ -1,14 +1,10 @@ import { Profile } from "../models/profile"; -import { ProfileWorld, ScoreWorld, EventWorld, GhostWorld, RivalWorld, HiScoreWorld } from "../models/ddrworld"; -import { SONGS_WORLD, SONGS_OVERRIDE_WORLD, EVENTS_WORLD } from "../data/world"; +import { ProfileWorld, ScoreWorld, EventWorld, GhostWorld, RivalWorld, HiScoreWorld, LeagueWorld } from "../models/ddrworld"; +import { SONGS_WORLD, SONGS_OVERRIDE_WORLD, EVENTS_WORLD, LEAGUE_WORLD, LOCKED_SONGS } from "../data/world"; -// needs to be faster function getLastGhostId(ghost: any) { - return ghost.reduce(function(a, b) { - let aId = (a && !a.ghostId) ? 0 : a.ghostId - let bId = (!b.ghostId) ? 0 : b.ghostId - return (a && aId > bId) ? aId : bId - }) + if(ghost.length > 0) return ghost.filter(a => (a.ghostId !== undefined)).sort((a, b) => b.ghostId - a.ghostId)[0].ghostId + else return 0 } async function saveScores(refid: string, hiScoreInfo: any, songId: number, style: number, difficulty: number, rank: number, clearKind: number, score: number, exScore: number, maxCombo: number, flareForce: number, ghostSize: number, ghost: string) { @@ -375,6 +371,22 @@ export const playerdatasave: EPR = async (info, data, send) => { }) } } + + let leagueData = $(data).element('data.league.current') + if(leagueData) { + let leagueId = leagueData.number("league_id") + let score = leagueData.number("score") + let playCount = leagueData.number("playcount") + let leagueExist = await DB.FindOne(refid, {collection: 'league3', id: leagueId}) + + await DB.Upsert(refid, { collection: "league3", id: leagueId }, { + $set: { + class: ((leagueExist.class === 0) ? 1 : leagueExist.class), + score: score, + playCount: playCount + } + }) + } } return send.object({ @@ -548,6 +560,118 @@ export const playerdataload: EPR = async (info, data, send) => { } } + let leagueData = {} + let curLeague = LEAGUE_WORLD[0] + let league = await DB.FindOne(refid, {collection: 'league3', id: curLeague.id}) + if(!league) { + let leagueClass = 0 + let prevLeague = await DB.FindOne(refid, {collection: 'league3', id: curLeague.id - 1}) + if(prevLeague) leagueClass = prevLeague['class'] + await DB.Upsert(refid, { collection: "league3", id: curLeague.id }, { + collection: "league3", + + id: curLeague.id, + class: leagueClass, + score: 0, + playCount: 0, + ended: false, + }) + } + league = await DB.FindOne(refid, {collection: 'league3', id: curLeague.id}) + if(league) { + let leagueAll = await DB.Find(null, {collection: 'league3', id: curLeague.id, class: league['class']}) + let joinNum = leagueAll.length + let resultClass = league['class'] + let promoteScore = 0 + let promoteRank = 0 + let demoteScore = 0 + let demoteRank = 0 + let leagueStatus = 0 + let leagueScores = leagueAll.map(a => a['score']).sort((a, b) => b - a) + if(leagueScores[0] > 0) { + if(league['class'] === 1) { + promoteScore = Math.round(leagueScores[0] / 2) + leagueScores = leagueScores.concat([promoteScore]).sort((a, b) => b - a) + promoteRank = leagueScores.findIndex(s => s === promoteScore) + 1 + joinNum += ((joinNum < 2) ? 2 : 1) + } else if(league['class'] === 2) { + promoteScore = Math.round(leagueScores[0] - (leagueScores[0] - (35 / 100 * leagueScores[0]))) + demoteScore = Math.round(leagueScores[0] - (leagueScores[0] - (85 / 100 * leagueScores[0]))) + leagueScores = leagueScores.concat([promoteScore, demoteScore]).sort((a, b) => b - a) + promoteRank = leagueScores.findIndex(s => s === promoteScore) + 1 + demoteScore = leagueScores.findIndex(s => s === demoteScore) + 1 + joinNum += 2 + } else if(league['class'] === 3) { + demoteScore = Math.round(leagueScores[0] - (leagueScores[0] - (85 / 100 * leagueScores[0]))) + leagueScores = leagueScores.concat([demoteScore]).sort((a, b) => b - a) + demoteRank = leagueScores.findIndex(s => s === demoteScore) + 1 + joinNum += ((joinNum < 2) ? 2 : 1) + } + } + let rank = leagueScores.findIndex(s => s === league['score']) + 1 + let leagueClass = (league['class'] === 0) ? 1 : league['class'] + + if(leagueClass === 1 && league['score'] >= promoteScore) resultClass += 1 + else if(leagueClass === 2) { + if(league['score'] >= promoteScore) resultClass += 1 + else if(league['score'] < demoteScore) resultClass -= 1 + } + else if(leagueClass === 3 && league['score'] < demoteScore) resultClass -= 1 + + if(BigInt(Date.now()) >= curLeague.start) leagueStatus = 1 + if(BigInt(Date.now()) >= curLeague.end) leagueStatus = 2 + if(BigInt(Date.now()) >= curLeague.summary) { + leagueStatus = 0 + if(!league['ended']) await DB.Upsert(refid, {collection: 'league3', id: curLeague.id}, {$set: {ended: true, class: resultClass}}) + } + leagueData = { + league_class: K.ITEM("s32", (BigInt(Date.now()) >= curLeague.summary && !league['ended']) ? resultClass : league['class']), + current: { + league_id: K.ITEM("s32", curLeague.id), + league_name: K.ITEM("str", Buffer.from(curLeague.name, 'utf8').toString('base64')), + league_name_eng: K.ITEM("str", Buffer.from(curLeague.name_eng, 'utf8').toString('base64')), + starttime: K.ITEM("u64", curLeague.start), + endtime: K.ITEM("u64", curLeague.end), + summarytime: K.ITEM("u64", curLeague.summary), + league_status: K.ITEM("s32", leagueStatus), + league_class: K.ITEM("s32", leagueClass), + result_league_class: K.ITEM("s32", resultClass), + rank: K.ITEM("s32", rank), + score: K.ITEM("s32", league['score']), + playcount: K.ITEM("s32", league['playCount']), + advance_border: K.ITEM("s32", curLeague.advanceBorder[leagueClass - 1]), + join_num: K.ITEM("s32", joinNum), + promote_rank: K.ITEM("s32", promoteRank), + promote_score: K.ITEM("s32", promoteScore), + demote_rank: K.ITEM("s32", demoteRank), + demote_score: K.ITEM("s32", demoteScore), + ranking_score: K.ITEM("s32", league['score']) + }, + result: (BigInt(Date.now()) >= curLeague.summary && !league['ended']) ? [ + { + league_id: K.ITEM("s32", curLeague.id), + league_name: K.ITEM("str", Buffer.from(curLeague.name, 'utf8').toString('base64')), + league_name_eng: K.ITEM("str", Buffer.from(curLeague.name_eng, 'utf8').toString('base64')), + starttime: K.ITEM("u64", curLeague.start), + endtime: K.ITEM("u64", curLeague.end), + summarytime: K.ITEM("u64", curLeague.summary), + league_status: K.ITEM("s32", 1), + league_class: K.ITEM("s32", league['class']), + result_league_class: K.ITEM("s32", resultClass), + rank: K.ITEM("s32", rank), + score: K.ITEM("s32", league['score']), + playcount: K.ITEM("s32", league['playCount']), + advance_border: K.ITEM("s32", curLeague.advanceBorder[leagueClass - 1]), + join_num: K.ITEM("s32", joinNum), + promote_rank: K.ITEM("s32", promoteRank), + promote_score: K.ITEM("s32", promoteScore), + demote_rank: K.ITEM("s32", demoteRank), + demote_score: K.ITEM("s32", demoteScore) + } + ] : [] + } + } + // test if(IO.Exists('data/test.json')) { let bufTest = await IO.ReadFile('data/test.json') @@ -638,7 +762,8 @@ export const playerdataload: EPR = async (info, data, send) => { }, rival: [], score: scoreFin, - event: eventFin + event: eventFin, + league: leagueData }); } }; @@ -664,7 +789,25 @@ export const musicdataload: EPR = async (info, data, send) => { for(const [index, diff] of difficultyArr.entries()) { limited = ((index % 5 === 4) && limitedCha) ? limitedCha : limited - limited = (limitedAry) ? limitedAry[index] : limited + limited = (limitedAry.length > 0) ? limitedAry[index] : limited + + if($(music).number('series') === 20 && overrideIndex === -1) { + limited = 0 + for(const ls in LOCKED_SONGS) { + if(index % 5 < 4) { + if(LOCKED_SONGS[ls].ids.includes($(music).number('mcode')) && BigInt(Date.now()) < LOCKED_SONGS[ls].unlock_date) { + limited = 1 + break + } + } else if(index % 5 === 4) { + if(LOCKED_SONGS[ls].ids_cha.includes($(music).number('mcode')) && BigInt(Date.now()) < LOCKED_SONGS[ls].unlock_date) { + limited = 1 + break + } + } + } + } + musicList.push({ music_str: K.ITEM('str', $(music).number('mcode') + ',' + ((index > 4) ? '1,' : '0,') + (index % 5) + ',' + limited + ',' + diff) }) diff --git a/index.ts b/index.ts index 9f12c60..c0d5205 100644 --- a/index.ts +++ b/index.ts @@ -5,7 +5,7 @@ import { usergamedata_send } from "./handlers/usergamedata_send"; import { musicdataload, playerdatanew, playerdatasave, playerdataload, rivaldataload, ghostdataload, taboowordcheck, minidump } from "./handlers/ddrworld"; import { CommonOffset, OptionOffset, Profile } from "./models/profile"; import { ProfileWorld } from "./models/ddrworld"; -import { SONGS_WORLD, SONGS_OVERRIDE_WORLD } from "./data/world" +import { SONGS_WORLD, SONGS_OVERRIDE_WORLD, LEAGUE_WORLD } from "./data/world" export function register() { R.GameCode("MDX"); diff --git a/models/ddrworld.ts b/models/ddrworld.ts index 3c5b0cb..c39759d 100644 --- a/models/ddrworld.ts +++ b/models/ddrworld.ts @@ -59,6 +59,16 @@ export interface EventWorld { saveData: number; } +export interface LeagueWorld { + collection: "league3"; + + id: number, + class: number, + score: number, + playCount: number, + ended: boolean +} + export interface ProfileWorld { collection: "profile3"; @@ -126,30 +136,4 @@ export interface ProfileWorld { cgTipsGimmick: number; cgTipsAdvance: number; cgGuideScene: number; - - - - singleGrade?: number; - doubleGrade?: number; - - events?: {}; - - usergamedata?: { - COMMON?: { - strdata?: string; - bindata?: string; - }; - OPTION?: { - strdata?: string; - bindata?: string; - }; - LAST?: { - strdata?: string; - bindata?: string; - }; - RIVAL?: { - strdata?: string; - bindata?: string; - }; - }; } diff --git a/webui/css/datatables.css b/webui/css/datatables.css new file mode 100644 index 0000000..2f97118 --- /dev/null +++ b/webui/css/datatables.css @@ -0,0 +1,499 @@ +/* + * This combined file was created by the DataTables downloader builder: + * https://datatables.net/download + * + * To rebuild or modify this file with the latest versions of the included + * software please visit: + * https://datatables.net/download/#bm/dt-1.11.3/fh-3.2.0/r-2.2.9/sc-2.0.5 + * + * Included libraries: + * DataTables 1.11.3, FixedHeader 3.2.0, Responsive 2.2.9, Scroller 2.0.5 + */ + +@charset "UTF-8"; +td.dt-control { + background: url("https://www.datatables.net/examples/resources/details_open.png") no-repeat center center; + cursor: pointer; +} + +tr.dt-hasChild td.dt-control { + background: url("https://www.datatables.net/examples/resources/details_close.png") no-repeat center center; +} + +table.dataTable th.dt-left, +table.dataTable td.dt-left { + text-align: left; +} +table.dataTable th.dt-center, +table.dataTable td.dt-center, +table.dataTable td.dataTables_empty { + text-align: center; +} +table.dataTable th.dt-right, +table.dataTable td.dt-right { + text-align: right; +} +table.dataTable th.dt-justify, +table.dataTable td.dt-justify { + text-align: justify; +} +table.dataTable th.dt-nowrap, +table.dataTable td.dt-nowrap { + white-space: nowrap; +} +table.dataTable thead th.dt-head-left, +table.dataTable thead td.dt-head-left, +table.dataTable tfoot th.dt-head-left, +table.dataTable tfoot td.dt-head-left { + text-align: left; +} +table.dataTable thead th.dt-head-center, +table.dataTable thead td.dt-head-center, +table.dataTable tfoot th.dt-head-center, +table.dataTable tfoot td.dt-head-center { + text-align: center; +} +table.dataTable thead th.dt-head-right, +table.dataTable thead td.dt-head-right, +table.dataTable tfoot th.dt-head-right, +table.dataTable tfoot td.dt-head-right { + text-align: right; +} +table.dataTable thead th.dt-head-justify, +table.dataTable thead td.dt-head-justify, +table.dataTable tfoot th.dt-head-justify, +table.dataTable tfoot td.dt-head-justify { + text-align: justify; +} +table.dataTable thead th.dt-head-nowrap, +table.dataTable thead td.dt-head-nowrap, +table.dataTable tfoot th.dt-head-nowrap, +table.dataTable tfoot td.dt-head-nowrap { + white-space: nowrap; +} +table.dataTable tbody th.dt-body-left, +table.dataTable tbody td.dt-body-left { + text-align: left; +} +table.dataTable tbody th.dt-body-center, +table.dataTable tbody td.dt-body-center { + text-align: center; +} +table.dataTable tbody th.dt-body-right, +table.dataTable tbody td.dt-body-right { + text-align: right; +} +table.dataTable tbody th.dt-body-justify, +table.dataTable tbody td.dt-body-justify { + text-align: justify; +} +table.dataTable tbody th.dt-body-nowrap, +table.dataTable tbody td.dt-body-nowrap { + white-space: nowrap; +} + +/*! DataTables Bulma integration + * ©2020 SpryMedia Ltd - datatables.net/license + */ +table.dataTable { + clear: both; + margin-top: 6px !important; + margin-bottom: 6px !important; + max-width: none !important; + border-collapse: separate !important; + border-spacing: 0; +} +table.dataTable td, +table.dataTable th { + -webkit-box-sizing: content-box; + box-sizing: content-box; +} +table.dataTable td.dataTables_empty, +table.dataTable th.dataTables_empty { + text-align: center; +} +table.dataTable.nowrap th, +table.dataTable.nowrap td { + white-space: nowrap; +} + +div.dataTables_wrapper div.dataTables_length label { + font-weight: normal; + text-align: left; + white-space: nowrap; +} +div.dataTables_wrapper div.dataTables_length div { + vertical-align: middle; +} +div.dataTables_wrapper div.dataTables_length select { + width: auto; + display: inline-block; + vertical-align: middle; +} +div.dataTables_wrapper div.dataTables_filter { + text-align: right; +} +div.dataTables_wrapper div.dataTables_filter label { + font-weight: normal; + white-space: nowrap; + text-align: left; +} +div.dataTables_wrapper div.dataTables_filter input { + margin-left: 0.5em; + width: auto; + vertical-align: middle; +} +div.dataTables_wrapper div.dataTables_info { + padding-top: 0.5em; +} +div.dataTables_wrapper div.dataTables_paginate ul { + justify-content: flex-end; + list-style: none; + margin: 0; +} +div.dataTables_wrapper div.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 200px; + margin-left: -100px; + margin-top: -26px; + text-align: center; + padding: 1em 0; +} + +table.dataTable > thead > tr > th:active, +table.dataTable > thead > tr > td:active { + outline: none; +} +table.dataTable > thead > tr > th:not(.sorting_disabled), +table.dataTable > thead > tr > td:not(.sorting_disabled) { + padding-right: 30px; +} +table.dataTable > thead .sorting, +table.dataTable > thead .sorting_asc, +table.dataTable > thead .sorting_desc, +table.dataTable > thead .sorting_asc_disabled, +table.dataTable > thead .sorting_desc_disabled { + cursor: pointer; + position: relative; +} +table.dataTable > thead .sorting:before, table.dataTable > thead .sorting:after, +table.dataTable > thead .sorting_asc:before, +table.dataTable > thead .sorting_asc:after, +table.dataTable > thead .sorting_desc:before, +table.dataTable > thead .sorting_desc:after, +table.dataTable > thead .sorting_asc_disabled:before, +table.dataTable > thead .sorting_asc_disabled:after, +table.dataTable > thead .sorting_desc_disabled:before, +table.dataTable > thead .sorting_desc_disabled:after { + position: absolute; + bottom: 0.7em; + display: block; + opacity: 0.3; +} +table.dataTable > thead .sorting:before, +table.dataTable > thead .sorting_asc:before, +table.dataTable > thead .sorting_desc:before, +table.dataTable > thead .sorting_asc_disabled:before, +table.dataTable > thead .sorting_desc_disabled:before { + right: 1em; + content: "↑"; +} +table.dataTable > thead .sorting:after, +table.dataTable > thead .sorting_asc:after, +table.dataTable > thead .sorting_desc:after, +table.dataTable > thead .sorting_asc_disabled:after, +table.dataTable > thead .sorting_desc_disabled:after { + right: 0.5em; + content: "↓"; +} +table.dataTable > thead .sorting_asc:before, +table.dataTable > thead .sorting_desc:after { + opacity: 1; +} +table.dataTable > thead .sorting_asc_disabled:before, +table.dataTable > thead .sorting_desc_disabled:after { + opacity: 0; +} + +div.dataTables_scrollHead table.dataTable { + margin-bottom: 0 !important; +} + +div.dataTables_scrollBody table { + border-top: none; + margin-top: 0 !important; + margin-bottom: 0 !important; +} +div.dataTables_scrollBody table thead .sorting:before, +div.dataTables_scrollBody table thead .sorting_asc:before, +div.dataTables_scrollBody table thead .sorting_desc:before, +div.dataTables_scrollBody table thead .sorting:after, +div.dataTables_scrollBody table thead .sorting_asc:after, +div.dataTables_scrollBody table thead .sorting_desc:after { + display: none; +} +div.dataTables_scrollBody table tbody tr:first-child th, +div.dataTables_scrollBody table tbody tr:first-child td { + border-top: none; +} + +div.dataTables_scrollFoot > .dataTables_scrollFootInner { + box-sizing: content-box; +} +div.dataTables_scrollFoot > .dataTables_scrollFootInner > table { + margin-top: 0 !important; + border-top: none; +} + + +table.dataTable.fixedHeader-floating, +table.dataTable.fixedHeader-locked { + background-color: white; + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +table.dataTable.fixedHeader-locked { + position: absolute !important; +} + +@media print { + table.fixedHeader-floating { + display: none; + } +} +.table td, +.table th { + padding: 7px 11px !important; +} + + +table.dataTable.dtr-inline.collapsed > tbody > tr > td.child, +table.dataTable.dtr-inline.collapsed > tbody > tr > th.child, +table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty { + cursor: default !important; +} +table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before, +table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before, +table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before { + display: none !important; +} +table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control, +table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control { + position: relative; + padding-left: 30px; + cursor: pointer; +} +table.dataTable.dtr-inline.collapsed > tbody > tr > td.dtr-control:before, +table.dataTable.dtr-inline.collapsed > tbody > tr > th.dtr-control:before { + top: 50%; + left: 5px; + height: 1em; + width: 1em; + margin-top: -9px; + display: block; + position: absolute; + color: white; + border: 0.15em solid white; + border-radius: 1em; + box-shadow: 0 0 0.2em #444; + box-sizing: content-box; + text-align: center; + text-indent: 0 !important; + font-family: "Courier New", Courier, monospace; + line-height: 1em; + content: "+"; + background-color: #00D1B2; +} +table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td.dtr-control:before, +table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th.dtr-control:before { + content: "-"; + background-color: #d33333; +} +table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control, +table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control { + padding-left: 27px; +} +table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td.dtr-control:before, +table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th.dtr-control:before { + left: 4px; + height: 14px; + width: 14px; + border-radius: 14px; + line-height: 14px; + text-indent: 3px; +} +table.dataTable.dtr-column > tbody > tr > td.dtr-control, +table.dataTable.dtr-column > tbody > tr > th.dtr-control, +table.dataTable.dtr-column > tbody > tr > td.control, +table.dataTable.dtr-column > tbody > tr > th.control { + position: relative; + cursor: pointer; +} +table.dataTable.dtr-column > tbody > tr > td.dtr-control:before, +table.dataTable.dtr-column > tbody > tr > th.dtr-control:before, +table.dataTable.dtr-column > tbody > tr > td.control:before, +table.dataTable.dtr-column > tbody > tr > th.control:before { + top: 50%; + left: 50%; + height: 0.8em; + width: 0.8em; + margin-top: -0.5em; + margin-left: -0.5em; + display: block; + position: absolute; + color: white; + border: 0.15em solid white; + border-radius: 1em; + box-shadow: 0 0 0.2em #444; + box-sizing: content-box; + text-align: center; + text-indent: 0 !important; + font-family: "Courier New", Courier, monospace; + line-height: 1em; + content: "+"; + background-color: #00D1B2; +} +table.dataTable.dtr-column > tbody > tr.parent td.dtr-control:before, +table.dataTable.dtr-column > tbody > tr.parent th.dtr-control:before, +table.dataTable.dtr-column > tbody > tr.parent td.control:before, +table.dataTable.dtr-column > tbody > tr.parent th.control:before { + content: "-"; + background-color: #d33333; +} +table.dataTable > tbody > tr.child { + padding: 0.5em 1em; +} +table.dataTable > tbody > tr.child:hover { + background: transparent !important; +} +table.dataTable > tbody > tr.child ul.dtr-details { + display: inline-block; + list-style-type: none; + margin: 0; + padding: 0; +} +table.dataTable > tbody > tr.child ul.dtr-details > li { + border-bottom: 1px solid #efefef; + padding: 0.5em 0; +} +table.dataTable > tbody > tr.child ul.dtr-details > li:first-child { + padding-top: 0; +} +table.dataTable > tbody > tr.child ul.dtr-details > li:last-child { + border-bottom: none; +} +table.dataTable > tbody > tr.child span.dtr-title { + display: inline-block; + min-width: 75px; + font-weight: bold; +} +div.dtr-modal { + position: fixed; + box-sizing: border-box; + top: 0; + left: 0; + height: 100%; + width: 100%; + z-index: 100; + padding: 10em 1em; +} +div.dtr-modal div.dtr-modal-display { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + width: 50%; + height: 50%; + overflow: auto; + margin: auto; + z-index: 102; + overflow: auto; + background-color: #f5f5f7; + border: 1px solid black; + border-radius: 0.5em; + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6); +} +div.dtr-modal div.dtr-modal-content { + position: relative; + padding: 1em; +} +div.dtr-modal div.dtr-modal-close { + position: absolute; + top: 6px; + right: 6px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 12; +} +div.dtr-modal div.dtr-modal-close:hover { + background-color: #eaeaea; +} +div.dtr-modal div.dtr-modal-background { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 101; + background: rgba(0, 0, 0, 0.6); +} + +@media screen and (max-width: 767px) { + div.dtr-modal div.dtr-modal-display { + width: 95%; + } +} +table.dataTable > tbody > tr.child ul { + font-size: 1em; +} + +div.modal-content { + padding: 20px; + background: white; + border-radius: 5px; +} + + +div.dts { + display: block !important; +} +div.dts tbody th, +div.dts tbody td { + white-space: nowrap; +} +div.dts div.dts_loading { + z-index: 1; +} +div.dts div.dts_label { + position: absolute; + right: 10px; + background: rgba(0, 0, 0, 0.8); + color: white; + box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5); + text-align: right; + border-radius: 3px; + padding: 0.4em; + z-index: 2; + display: none; +} +div.dts div.dataTables_scrollBody { + background: repeating-linear-gradient(45deg, #edeeff, #edeeff 10px, white 10px, white 20px); +} +div.dts div.dataTables_scrollBody table { + z-index: 2; +} +div.dts div.dataTables_paginate, +div.dts div.dataTables_length { + display: none; +} + + diff --git a/webui/js/common.js b/webui/js/common.js new file mode 100644 index 0000000..ec60cde --- /dev/null +++ b/webui/js/common.js @@ -0,0 +1,125 @@ +let flareMatrix = { + "1": [145, 153, 162, 171, 179, 188, 197, 205, 214, 223, 232], + "2": [155, 164, 182, 192, 201, 210, 220, 220, 229, 238, 248], + "3": [170, 180, 190, 200, 210, 221, 231, 241, 251, 261, 272], + "4": [185, 196, 207, 218, 229, 240, 251, 262, 273, 284, 296], + "5": [205, 217, 229, 241, 254, 266, 278, 291, 303, 315, 328], + "6": [230, 243, 257, 271, 285, 299, 312, 326, 340, 354, 368], + "7": [255, 270, 285, 300, 316, 331, 346, 362, 377, 392, 408], + "8": [290, 307, 324, 342, 359, 377, 394, 411, 429, 446, 464], + "9": [335, 355, 375, 395, 415, 435, 455, 475, 495, 515, 536], + "10": [400, 424, 448, 472, 496, 520, 544, 568, 592, 616, 640], + "11": [465, 492, 520, 548, 576, 604, 632, 660, 688, 716, 744], + "12": [510, 540, 571, 601, 632, 663, 693, 724, 754, 785, 816], + "13": [545, 577, 610, 643, 675, 708, 741, 773, 806, 839, 872], + "14": [575, 609, 644, 678, 713, 747, 782, 816, 851, 885, 920], + "15": [600, 636, 672, 708, 744, 780, 816, 852, 888, 924, 960], + "16": [620, 657, 694, 731, 768, 806, 843, 880, 917, 954, 992], + "17": [635, 673, 711, 749, 787, 825, 863, 901, 939, 977, 1016], + "18": [650, 689, 728, 767, 806, 845, 884, 923, 962, 1001, 1040], + "19": [665, 704, 744, 784, 824, 864, 904, 944, 984, 1024, 1064] +} +let flareSkill = [ + ["NONE", 0, 500, 1000, 1500], + ["MERCURY", 2000, 3000, 4000, 5000], + ["VENUS", 6000, 7000, 8000, 9000], + ["EARTH", 10000, 11500, 13000, 14500], + ["MARS", 16000, 18000, 20000, 22000], + ["JUPITER", 24000, 26500, 29000, 31500], + ["SATURN", 34000, 36750, 39500, 42250], + ["URANUS", 45000, 48750, 52500, 56250], + ["NEPTUNE", 60000, 63750, 67500, 71250], + ["SUN", 75000, 78750, 82500, 86250], + ["WORLD", 90000] +] +let area = ["Unknown", "Hokkaido", "Aomori", "Iwate", "Miyagi", "Akita", "Yamagata", "Fukushima", "Ibaraki", "Tochigi", "Gunma", "Saitama", "Chiba", "Tokyo", "Kanagawa", "Niigata", "Toyama", "Ishikawa", "Fukui", "Yamanashi", + "Nagano", "Gifu", "Shizuoka", "Aichi", "Mie", "Shiga", "Kyoto", "Osaka", "Hyogo", "Nara", "Wakayama", "Tottori", "Shimane", "Okayama", "Hiroshima", "Yamaguchi", "Tokushima", "Kagawa", "Ehime", "Kochi", "Fukuoka", "Saga", + "Nagasaki", "Kumamoto", "Oita", "Miyazaki", "Kagoshima", "Okinawa", "Hong Kong", "Korea", "Taiwan", "USA", "Europe", "Overseas", "Alaska", "Alabama", "Arkansas", "Arizona", "California", "Colorado", "Connecticut", "Delaware", + "Florida", "Georgia", "Hawaii", "Iowa", "Idaho", "Illinois", "Indiana", "Kansas", "Kentucky", "Louisiana", "Massachusetts", "Maryland", "Maine", "Michigan", "Minnesota", "Missouri", "Mississippi", "Montana", "Nebraska", + "North Carolina", "North Dakota", "New Hampshire", "New Jersey", "New Mexico", "Nevada", "New York", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", + "Virginia", "Vermont", "Washington", "Wisconsin", "West Virginia", "Wyoming", "Washington D.C.", "Japan", "Canada", "Singapore", "Thailand", "Australia", "New Zealand", "UK", "Italy", "Spain", "Germany", "France", "Portugal", "Indonesia", + "Philippines" +] + +async function getFlareInfo(scores) { + let flareData = {} + let mdbData = [] + + let flareTopScores = {'sg': [], 'db': []} + let totalSgFlare = 0 + let totalDbFlare = 0 + + let classicSgTop30 = [] + let classicSgFlare = 0 + let classicDbTop30 = [] + let classicDbFlare = 0 + + let whiteSgTop30 = [] + let whiteSgFlare = 0 + let whiteDbTop30 = [] + let whiteDbFlare = 0 + + let goldSgTop30 = [] + let goldSgFlare = 0 + let goldDbTop30 = [] + let goldDbFlare = 0 + + await emit('getMDB', {}).then( + function(response) { + mdbData = response.data.mdb + } + ) + if(mdbData !== undefined) { + scores.forEach(score => { + let songIndex = mdbData.findIndex(m => m.mcode === score.songId) + if(songIndex > -1 && score.songId != 38707 && score.flareForce >= 0) { + if(score.style === 0) { + flareTopScores.sg.push({ + flare: flareMatrix[mdbData[songIndex]['diffLv'][score.difficulty]][score.flareForce], + title: mdbData[songIndex]['title'], + difficulty: mdbData[songIndex]['diffLv'][score.difficulty], + series: mdbData[songIndex]['series'] + }) + } else { + flareTopScores.db.push({ + flare: flareMatrix[mdbData[songIndex]['diffLv'][score.difficulty]][score.flareForce], + title: mdbData[songIndex]['title'], + difficulty: mdbData[songIndex]['diffLv'][score.difficulty + 5], + series: mdbData[songIndex]['series'] + }) + } + } + }) + + flareData.classicSgTop30 = flareTopScores.sg.filter(ft => ft.series <= 13).sort((a, b) => b.flare - a.flare) + if(flareData.classicSgTop30.length > 30) flareData.classicSgTop30.slice(0, 30) + flareData.classicSgFlare = flareData.classicSgTop30.reduce((n, {flare}) => n + flare, 0) + + flareData.whiteSgTop30 = flareTopScores.sg.filter(ft => ft.series >= 14 && ft.series <= 17).sort((a, b) => b.flare - a.flare) + if(flareData.whiteSgTop30.length > 30) flareData.whiteSgTop30.slice(0, 30) + flareData.whiteSgFlare = flareData.whiteSgTop30.reduce((n, {flare}) => n + flare, 0) + + flareData.goldSgTop30 = flareTopScores.sg.filter(ft => ft.series >= 18).sort((a, b) => b.flare - a.flare) + if(flareData.goldSgTop30.length > 30) flareData.goldSgTop30.slice(0, 30) + flareData.goldSgFlare = flareData.goldSgTop30.reduce((n, {flare}) => n + flare, 0) + + flareData.totalSgFlare = flareData.classicSgTop30.concat(flareData.whiteSgTop30, flareData.goldSgTop30).reduce((n, {flare}) => n + flare, 0) + + + flareData.classicDbTop30 = flareTopScores.db.filter(ft => ft.series <= 13).sort((a, b) => b.flare - a.flare) + if(flareData.classicDbTop30.length > 30) flareData.classicDbTop30.slice(0, 30) + flareData.classicDbFlare = flareData.classicDbTop30.reduce((n, {flare}) => n + flare, 0) + + flareData.whiteDbTop30 = flareTopScores.db.filter(ft => ft.series >= 14 && ft.series <= 17).sort((a, b) => b.flare - a.flare) + if(flareData.whiteDbTop30.length > 30) flareData.whiteDbTop30.slice(0, 30) + flareData.whiteDbFlare = flareData.whiteDbTop30.reduce((n, {flare}) => n + flare, 0) + + flareData.goldDbTop30 = flareTopScores.db.filter(ft => ft.series >= 18).sort((a, b) => b.flare - a.flare) + if(flareData.goldDbTop30.length > 30) flareData.goldDbTop30.slice(0, 30) + flareData.goldDbFlare = flareData.goldDbTop30.reduce((n, {flare}) => n + flare, 0) + + flareData.totalDbFlare = flareData.classicDbTop30.concat(flareData.whiteDbTop30, flareData.goldDbTop30).reduce((n, {flare}) => n + flare, 0) + + return flareData + } +} \ No newline at end of file diff --git a/webui/js/flaredata.js b/webui/js/flaredata.js new file mode 100644 index 0000000..d9fe9a1 --- /dev/null +++ b/webui/js/flaredata.js @@ -0,0 +1,86 @@ +let flareData = {} +let totalFlare = 0 +let classicTop30 = [] +let classicFlare = [] +let whiteTop30 = [] +let whiteFlare = [] +let goldTop30 = [] +let goldFlare = [] + +async function populateTables() { + if(parseInt($('#style_select').val()) === 0) { + totalFlare = flareData.totalSgFlare + classicTop30 = flareData.classicSgTop30 + classicFlare = flareData.classicSgFlare + whiteTop30 = flareData.whiteSgTop30 + whiteFlare = flareData.whiteSgFlare + goldTop30 = flareData.goldSgTop30 + goldFlare = flareData.goldSgFlare + } else { + totalFlare = flareData.totalDbFlare + classicTop30 = flareData.classicDbTop30 + classicFlare = flareData.classicDbFlare + whiteTop30 = flareData.whiteDbTop30 + whiteFlare = flareData.whiteDbFlare + goldTop30 = flareData.goldDbTop30 + goldFlare = flareData.goldDbFlare + } + + if(classicTop30.length === 0) $("tbody#classic_flare").append($("").append($("").append('No qualified scores.'))) + if(whiteTop30.length === 0) $("tbody#white_flare").append($("").append($("").append('No qualified scores.'))) + if(goldTop30.length === 0) $("tbody#gold_flare").append($("").append($("").append('No qualified scores.'))) + + for(const index in classicTop30) { + $("tbody#classic_flare").append( + $("").append( + $("").append(parseInt(index) + 1) + ).append( + $("").append(classicTop30[index].title) + ).append( + $("").append(classicTop30[index].difficulty) + ).append( + $("").append(classicTop30[index].flare) + ) + ) + } + for(const index in whiteTop30) { + $("tbody#white_flare").append( + $("").append( + $("").append(parseInt(index) + 1) + ).append( + $("").append(whiteTop30[index].title) + ).append( + $("").append(whiteTop30[index].difficulty) + ).append( + $("").append(whiteTop30[index].flare) + ) + ) + } + for(const index in goldTop30) { + $("tbody#gold_flare").append( + $("").append( + $("").append(parseInt(index) + 1) + ).append( + $("").append(goldTop30[index].title) + ).append( + $("").append(goldTop30[index].difficulty) + ).append( + $("").append(goldTop30[index].flare) + ) + ) + } +} + +$(document).ready(async function() { + let scores = JSON.parse(document.getElementById("score-pass").innerText) + flareData = await getFlareInfo(scores); + await populateTables() + + $('#style_select').change(async function() { + $("#classic_flare tr").remove() + $("#white_flare tr").remove() + $("#gold_flare tr").remove() + console.log("Removed") + await populateTables() + }) +}) \ No newline at end of file diff --git a/webui/js/profile_details.js b/webui/js/profile_details.js index 14182e7..d80fed1 100644 --- a/webui/js/profile_details.js +++ b/webui/js/profile_details.js @@ -1,168 +1,74 @@ -let flareMatrix = { - "1": [145, 153, 162, 171, 179, 188, 197, 205, 214, 223, 232], - "2": [155, 164, 182, 192, 201, 210, 220, 220, 229, 238, 248], - "3": [170, 180, 190, 200, 210, 221, 231, 241, 251, 261, 272], - "4": [185, 196, 207, 218, 229, 240, 251, 262, 273, 284, 296], - "5": [205, 217, 229, 241, 254, 266, 278, 291, 303, 315, 328], - "6": [230, 243, 257, 271, 285, 299, 312, 326, 340, 354, 368], - "7": [255, 270, 285, 300, 316, 331, 346, 362, 377, 392, 408], - "8": [290, 307, 324, 342, 359, 377, 394, 411, 429, 446, 464], - "9": [335, 355, 375, 395, 415, 435, 455, 475, 495, 515, 536], - "10": [400, 424, 448, 472, 496, 520, 544, 568, 592, 616, 640], - "11": [465, 492, 520, 548, 576, 604, 632, 660, 688, 716, 744], - "12": [510, 540, 571, 601, 632, 663, 693, 724, 754, 785, 816], - "13": [545, 577, 610, 643, 675, 708, 741, 773, 806, 839, 872], - "14": [575, 609, 644, 678, 713, 747, 782, 816, 851, 885, 920], - "15": [600, 636, 672, 708, 744, 780, 816, 852, 888, 924, 960], - "16": [620, 657, 694, 731, 768, 806, 843, 880, 917, 954, 992], - "17": [635, 673, 711, 749, 787, 825, 863, 901, 939, 977, 1016], - "18": [650, 689, 728, 767, 806, 845, 884, 923, 962, 1001, 1040], - "19": [665, 704, 744, 784, 824, 864, 904, 944, 984, 1024, 1064] -} -let flareSkill = [ - ["NONE", 0, 500, 1000, 1500], - ["MERCURY", 2000, 3000, 4000, 5000], - ["VENUS", 6000, 7000, 8000, 9000], - ["EARTH", 10000, 11500, 13000, 14500], - ["MARS", 16000, 18000, 20000, 22000], - ["JUPITER", 24000, 26500, 29000, 31500], - ["SATURN", 34000, 36750, 39500, 42250], - ["URANUS", 45000, 48750, 52500, 56250], - ["NEPTUNE", 60000, 63750, 67500, 71250], - ["SUN", 75000, 78750, 82500, 86250], - ["WORLD", 90000] -] -let area = ["Unknown", "Hokkaido", "Aomori", "Iwate", "Miyagi", "Akita", "Yamagata", "Fukushima", "Ibaraki", "Tochigi", "Gunma", "Saitama", "Chiba", "Tokyo", "Kanagawa", "Niigata", "Toyama", "Ishikawa", "Fukui", "Yamanashi", - "Nagano", "Gifu", "Shizuoka", "Aichi", "Mie", "Shiga", "Kyoto", "Osaka", "Hyogo", "Nara", "Wakayama", "Tottori", "Shimane", "Okayama", "Hiroshima", "Yamaguchi", "Tokushima", "Kagawa", "Ehime", "Kochi", "Fukuoka", "Saga", - "Nagasaki", "Kumamoto", "Oita", "Miyazaki", "Kagoshima", "Okinawa", "Hong Kong", "Korea", "Taiwan", "USA", "Europe", "Overseas", "Alaska", "Alabama", "Arkansas", "Arizona", "California", "Colorado", "Connecticut", "Delaware", - "Florida", "Georgia", "Hawaii", "Iowa", "Idaho", "Illinois", "Indiana", "Kansas", "Kentucky", "Louisiana", "Massachusetts", "Maryland", "Maine", "Michigan", "Minnesota", "Missouri", "Mississippi", "Montana", "Nebraska", - "North Carolina", "North Dakota", "New Hampshire", "New Jersey", "New Mexico", "Nevada", "New York", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", - "Virginia", "Vermont", "Washington", "Wisconsin", "West Virginia", "Wyoming", "Washington D.C.", "Japan", "Canada", "Singapore", "Thailand", "Australia", "New Zealand", "UK", "Italy", "Spain", "Germany", "France", "Portugal", "Indonesia", - "Philippines" -] - $(document).ready(async function() { // classic 1-13 white 14-17 gold 18-21 let profile = JSON.parse(document.getElementById("profile3-pass").innerText) let scores = JSON.parse(document.getElementById("score-pass").innerText) - let mdbData = [] - let flareTopScores = {'sg': [], 'db': []} - let totalSgFlare = 0 - let totalDbFlare = 0 - let classicSgTop30 = [] - let classicSgFlare = 0 - let classicDbTop30 = [] - let classicDbFlare = 0 - - let whiteSgTop30 = [] - let whiteSgFlare = 0 - let whiteDbTop30 = [] - let whiteDbFlare = 0 - - let goldSgTop30 = [] - let goldSgFlare = 0 - let goldDbTop30 = [] - let goldDbFlare = 0 - - await emit('getMDB', {}).then( - function(response) { - mdbData = response.data.mdb - } - ) $("#area").append( $("").append(area[profile.area]) ) - if(mdbData !== undefined) { - scores.forEach(score => { - let songIndex = mdbData.findIndex(m => m.mcode === score.songId) - if(songIndex > -1 && score.songId != 38707 && score.flareForce >= 0) { - if(score.style === 0) { - flareTopScores.sg.push({ - flare: flareMatrix[mdbData[songIndex]['diffLv'][score.difficulty]][score.flareForce], - series: mdbData[songIndex]['series'] - }) - } else { - flareTopScores.db.push({ - flare: flareMatrix[mdbData[songIndex]['diffLv'][score.difficulty]][score.flareForce], - series: mdbData[songIndex]['series'] - }) + + let flareData = await getFlareInfo(scores) + + let totalSgFlare = flareData.totalSgFlare + let totalDbFlare = flareData.totalDbFlare + + let classicSgTop30 = flareData.classicSgTop30 + let classicSgFlare = flareData.classicSgFlare + let classicDbTop30 = flareData.classicDbTop30 + let classicDbFlare = flareData.classicDbFlare + + let whiteSgTop30 = flareData.whiteSgTop30 + let whiteSgFlare = flareData.whiteSgFlare + let whiteDbTop30 = flareData.whiteDbTop30 + let whiteDbFlare = flareData.whiteDbFlare + + let goldSgTop30 = flareData.goldSgTop30 + let goldSgFlare = flareData.goldSgFlare + let goldDbTop30 = flareData.goldDbTop30 + let goldDbFlare = flareData.goldDbFlare + + let skillGet = false + let sgSkill = '' + let dbSkill = '' + let skillPlus = '+++' + flareSkill.forEach(fs => { + if(!skillGet) { + for(let sctr = 1; sctr < fs.length; sctr++) { + if(totalSgFlare >= fs[sctr]) { + sgSkill = fs[0] + if(sctr > 1) sgSkill = sgSkill + skillPlus.substring(0, sctr - 1) } + else skillGet = true } - }) + } + }) + console.log(sgSkill + " (" + totalSgFlare + ")") - classicSgTop30 = flareTopScores.sg.filter(ft => ft.series <= 13).sort((a, b) => b.flare - a.flare) - if(classicSgTop30.length > 30) classicSgTop30.slice(0, 30) - classicSgFlare = classicSgTop30.reduce((n, {flare}) => n + flare, 0) - - whiteSgTop30 = flareTopScores.sg.filter(ft => ft.series >= 14 && ft.series <= 17).sort((a, b) => b.flare - a.flare) - if(whiteSgTop30.length > 30) whiteSgTop30.slice(0, 30) - whiteSgFlare = whiteSgTop30.reduce((n, {flare}) => n + flare, 0) - - goldSgTop30 = flareTopScores.sg.filter(ft => ft.series >= 18).sort((a, b) => b.flare - a.flare) - if(goldSgTop30.length > 30) goldSgTop30.slice(0, 30) - goldSgFlare = goldSgTop30.reduce((n, {flare}) => n + flare, 0) - - totalSgFlare = classicSgTop30.concat(whiteSgTop30, goldSgTop30).reduce((n, {flare}) => n + flare, 0) - - - classicDbTop30 = flareTopScores.db.filter(ft => ft.series <= 13).sort((a, b) => b.flare - a.flare) - if(classicDbTop30.length > 30) classicDbTop30.slice(0, 30) - classicDbFlare = classicDbTop30.reduce((n, {flare}) => n + flare, 0) - - whiteDbTop30 = flareTopScores.db.filter(ft => ft.series >= 14 && ft.series <= 17).sort((a, b) => b.flare - a.flare) - if(whiteDbTop30.length > 30) whiteDbTop30.slice(0, 30) - whiteDbFlare = whiteDbTop30.reduce((n, {flare}) => n + flare, 0) - - goldDbTop30 = flareTopScores.db.filter(ft => ft.series >= 18).sort((a, b) => b.flare - a.flare) - if(goldDbTop30.length > 30) goldDbTop30.slice(0, 30) - goldDbFlare = goldDbTop30.reduce((n, {flare}) => n + flare, 0) - - totalDbFlare = classicDbTop30.concat(whiteDbTop30, goldDbTop30).reduce((n, {flare}) => n + flare, 0) - - let skillGet = false - let sgSkill = '' - let dbSkill = '' - let skillPlus = '+++' - flareSkill.forEach(fs => { - if(!skillGet) { - for(let sctr = 1; sctr < fs.length; sctr++) { - if(totalSgFlare >= fs[sctr]) { - sgSkill = fs[0] - if(sctr > 1) sgSkill = sgSkill + skillPlus.substring(0, sctr - 1) - } - else skillGet = true + skillGet = false + flareSkill.forEach(fs => { + if(!skillGet) { + for(let sctr = 1; sctr < fs.length; sctr++) { + if(totalDbFlare >= fs[sctr]) { + dbSkill = fs[0] + if(sctr > 1) dbSkill = dbSkill + skillPlus.substring(0, sctr - 1) } + else skillGet = true } - }) - console.log(sgSkill + " (" + totalSgFlare + ")") + } + }) + console.log(dbSkill + " (" + totalDbFlare + ")") - skillGet = false - flareSkill.forEach(fs => { - if(!skillGet) { - for(let sctr = 1; sctr < fs.length; sctr++) { - if(totalDbFlare >= fs[sctr]) { - dbSkill = fs[0] - if(sctr > 1) dbSkill = dbSkill + skillPlus.substring(0, sctr - 1) - } - else skillGet = true - } - } - }) - console.log(dbSkill + " (" + totalDbFlare + ")") + $("#skillrank").append( + $("").append(sgSkill) + ).append( + $("").append(dbSkill) + ) - $("#skillrank").append( - $("").append(sgSkill) - ).append( - $("").append(dbSkill) - ) - - $("#skilltotal").append( - $("").append(totalSgFlare) - ).append( - $("").append(totalDbFlare) - ) - } + $("#skilltotal").append( + $("").append(totalSgFlare) + ).append( + $("").append(totalDbFlare) + ) $("#skillclassic").append( $("").append(classicSgFlare + ' (' + classicSgTop30.length + ' / 30)') diff --git a/webui/profile_details.pug b/webui/profile_details.pug index 5d650b0..ce2ce60 100644 --- a/webui/profile_details.pug +++ b/webui/profile_details.pug @@ -54,3 +54,4 @@ if profile3 div(hidden id='profile3-pass') !{JSON.stringify(profile3)} div(hidden id='score-pass') !{JSON.stringify(score3)} script(src="static/js/profile_details.js") + script(src="static/js/common.js") diff --git a/webui/profile_flare data.pug b/webui/profile_flare data.pug new file mode 100644 index 0000000..413a38b --- /dev/null +++ b/webui/profile_flare data.pug @@ -0,0 +1,84 @@ +//DATA// + profile: DB.FindOne(refid, { collection: "profile" }) + profile3: DB.FindOne(refid, { collection: "profile3" }) + score3: DB.Find(refid, { collection: "score3" }) + +- + +if profile3 + div + .card + .card-header + p.card-header-title + span.icon + i.mdi.mdi-filter + | Filter Results + .card-content + .score-filter + .field.is-horizontal.has-addons + .field-label.is-normal + label.label Chart Style + .field-body + .control + .select + select(id="style_select" value=0) + option(value=0) SINGLE + option(value=1) DOUBLE + + .card + .card-header + p.card-header-title + span.icon + i.mdi.mdi-fire + | Classic + + .card-content + table + thead + tr + th(style="width:10%") # + th(style="width:60%") Title + th(style="width:15%") Difficulty + th(style="width:15%") Flare Skill + tbody#classic_flare + + .card + .card-header + p.card-header-title + span.icon + i.mdi.mdi-fire + | White + + .card-content + table + thead + tr + th(style="width:10%") # + th(style="width:60%") Title + th(style="width:15%") Difficulty + th(style="width:15%") Flare Skill + tbody#white_flare + + .card + .card-header + p.card-header-title + span.icon + i.mdi.mdi-fire + | Gold + + .card-content + table + thead + tr + th(style="width:10%") # + th(style="width:60%") Title + th(style="width:15%") Difficulty + th(style="width:15%") Flare Skill + tbody#gold_flare + + + + div(hidden id='profile3-pass') !{JSON.stringify(profile3)} + div(hidden id='score-pass') !{JSON.stringify(score3)} + script(src="static/js/flaredata.js") + script(src="static/js/common.js") diff --git a/webui/profile_music data.pug b/webui/profile_music data.pug index 9092cd9..763d63a 100644 --- a/webui/profile_music data.pug +++ b/webui/profile_music data.pug @@ -3,6 +3,7 @@ score3: DB.Find(refid, { collection: "score3" }) - +link(rel="stylesheet" href="static/css/datatables.css") if profile3 div