4223 lines
140 KiB
Python
4223 lines
140 KiB
Python
# vim: set fileencoding=utf-8
|
|
from typing import Any, Dict, List, Optional, Tuple
|
|
from typing_extensions import Final
|
|
|
|
from bemani.backend.ess import EventLogHandler
|
|
from bemani.backend.sdvx.base import SoundVoltexBase
|
|
from bemani.backend.sdvx.gravitywars import SoundVoltexGravityWars
|
|
from bemani.common import ID, Profile, VersionConstants
|
|
from bemani.data import Score, UserID
|
|
from bemani.protocol import Node
|
|
|
|
|
|
class SoundVoltexHeavenlyHaven(
|
|
EventLogHandler,
|
|
SoundVoltexBase,
|
|
):
|
|
name: str = "SOUND VOLTEX IV HEAVENLY HAVEN"
|
|
version: int = VersionConstants.SDVX_HEAVENLY_HAVEN
|
|
|
|
GAME_LIMITED_LOCKED: Final[int] = 1
|
|
GAME_LIMITED_UNLOCKABLE: Final[int] = 2
|
|
GAME_LIMITED_UNLOCKED: Final[int] = 3
|
|
|
|
GAME_CURRENCY_PACKETS: Final[int] = 0
|
|
GAME_CURRENCY_BLOCKS: Final[int] = 1
|
|
|
|
GAME_CATALOG_TYPE_SONG: Final[int] = 0
|
|
GAME_CATALOG_TYPE_APPEAL_CARD: Final[int] = 1
|
|
GAME_CATALOG_TYPE_CREW: Final[int] = 4
|
|
|
|
GAME_CLEAR_TYPE_NO_PLAY: Final[int] = 0
|
|
GAME_CLEAR_TYPE_FAILED: Final[int] = 1
|
|
GAME_CLEAR_TYPE_CLEAR: Final[int] = 2
|
|
GAME_CLEAR_TYPE_HARD_CLEAR: Final[int] = 3
|
|
GAME_CLEAR_TYPE_ULTIMATE_CHAIN: Final[int] = 4
|
|
GAME_CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN: Final[int] = 5
|
|
|
|
GAME_GRADE_NO_PLAY: Final[int] = 0
|
|
GAME_GRADE_D: Final[int] = 1
|
|
GAME_GRADE_C: Final[int] = 2
|
|
GAME_GRADE_B: Final[int] = 3
|
|
GAME_GRADE_A: Final[int] = 4
|
|
GAME_GRADE_A_PLUS: Final[int] = 5
|
|
GAME_GRADE_AA: Final[int] = 6
|
|
GAME_GRADE_AA_PLUS: Final[int] = 7
|
|
GAME_GRADE_AAA: Final[int] = 8
|
|
GAME_GRADE_AAA_PLUS: Final[int] = 9
|
|
GAME_GRADE_S: Final[int] = 10
|
|
|
|
GAME_SKILL_NAME_ID_LV_01: Final[int] = 1
|
|
GAME_SKILL_NAME_ID_LV_02: Final[int] = 2
|
|
GAME_SKILL_NAME_ID_LV_03: Final[int] = 3
|
|
GAME_SKILL_NAME_ID_LV_04: Final[int] = 4
|
|
GAME_SKILL_NAME_ID_LV_05: Final[int] = 5
|
|
GAME_SKILL_NAME_ID_LV_06: Final[int] = 6
|
|
GAME_SKILL_NAME_ID_LV_07: Final[int] = 7
|
|
GAME_SKILL_NAME_ID_LV_08: Final[int] = 8
|
|
GAME_SKILL_NAME_ID_LV_09: Final[int] = 9
|
|
GAME_SKILL_NAME_ID_LV_10: Final[int] = 10
|
|
GAME_SKILL_NAME_ID_LV_11: Final[int] = 11
|
|
GAME_SKILL_NAME_ID_LV_INF: Final[int] = 12
|
|
GAME_SKILL_NAME_ID_KAC_6TH_BODY: Final[int] = 13
|
|
GAME_SKILL_NAME_ID_KAC_6TH_TECHNOLOGY: Final[int] = 14
|
|
GAME_SKILL_NAME_ID_KAC_6TH_HEART: Final[int] = 15
|
|
GAME_SKILL_NAME_ID_TENKAICHI: Final[int] = 16
|
|
GAME_SKILL_NAME_ID_MUSIC_FESTIVAL: Final[int] = 17
|
|
GAME_SKILL_NAME_ID_YELLOWTAIL: Final[int] = 18 # For the April Fool's day courses.
|
|
GAME_SKILL_NAME_ID_BMK2017: Final[int] = 19
|
|
GAME_SKILL_NAME_ID_KAC_7TH_TIGER: Final[int] = 20
|
|
GAME_SKILL_NAME_ID_KAC_7TH_WOLF: Final[int] = 21
|
|
GAME_SKILL_NAME_ID_RIKKA: Final[
|
|
int
|
|
] = 22 # For the course that ran from 1/18/2018-2/18/2018
|
|
GAME_SKILL_NAME_ID_KAC_8TH: Final[int] = 23
|
|
|
|
# Return the local2 service so that SDVX 4 and above will send certain packets.
|
|
extra_services: List[str] = [
|
|
"local2",
|
|
]
|
|
|
|
@classmethod
|
|
def get_settings(cls) -> Dict[str, Any]:
|
|
"""
|
|
Return all of our front-end modifiably settings.
|
|
"""
|
|
return {
|
|
"bools": [
|
|
{
|
|
"name": "Disable Online Matching",
|
|
"tip": "Disable online matching between games.",
|
|
"category": "game_config",
|
|
"setting": "disable_matching",
|
|
},
|
|
{
|
|
"name": "Force Song Unlock",
|
|
"tip": "Force unlock all songs.",
|
|
"category": "game_config",
|
|
"setting": "force_unlock_songs",
|
|
},
|
|
{
|
|
"name": "Force Appeal Card Unlock",
|
|
"tip": "Force unlock all appeal cards.",
|
|
"category": "game_config",
|
|
"setting": "force_unlock_cards",
|
|
},
|
|
{
|
|
"name": "Force Crew Card Unlock",
|
|
"tip": "Force unlock all crew and subcrew cards.",
|
|
"category": "game_config",
|
|
"setting": "force_unlock_crew",
|
|
},
|
|
{
|
|
"name": "50th Anniversary Celebration",
|
|
"tip": "Display the 50th anniversary screen in attract mode",
|
|
"category": "game_config",
|
|
"setting": "50th_anniversary",
|
|
},
|
|
],
|
|
}
|
|
|
|
def previous_version(self) -> Optional[SoundVoltexBase]:
|
|
return SoundVoltexGravityWars(self.data, self.config, self.model)
|
|
|
|
def __game_to_db_clear_type(self, clear_type: int) -> int:
|
|
return {
|
|
self.GAME_CLEAR_TYPE_NO_PLAY: self.CLEAR_TYPE_NO_PLAY,
|
|
self.GAME_CLEAR_TYPE_FAILED: self.CLEAR_TYPE_FAILED,
|
|
self.GAME_CLEAR_TYPE_CLEAR: self.CLEAR_TYPE_CLEAR,
|
|
self.GAME_CLEAR_TYPE_HARD_CLEAR: self.CLEAR_TYPE_HARD_CLEAR,
|
|
self.GAME_CLEAR_TYPE_ULTIMATE_CHAIN: self.CLEAR_TYPE_ULTIMATE_CHAIN,
|
|
self.GAME_CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN: self.CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN,
|
|
}[clear_type]
|
|
|
|
def __db_to_game_clear_type(self, clear_type: int) -> int:
|
|
return {
|
|
self.CLEAR_TYPE_NO_PLAY: self.GAME_CLEAR_TYPE_NO_PLAY,
|
|
self.CLEAR_TYPE_FAILED: self.GAME_CLEAR_TYPE_FAILED,
|
|
self.CLEAR_TYPE_CLEAR: self.GAME_CLEAR_TYPE_CLEAR,
|
|
self.CLEAR_TYPE_HARD_CLEAR: self.GAME_CLEAR_TYPE_HARD_CLEAR,
|
|
self.CLEAR_TYPE_ULTIMATE_CHAIN: self.GAME_CLEAR_TYPE_ULTIMATE_CHAIN,
|
|
self.CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN: self.GAME_CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN,
|
|
}[clear_type]
|
|
|
|
def __game_to_db_grade(self, grade: int) -> int:
|
|
return {
|
|
self.GAME_GRADE_NO_PLAY: self.GRADE_NO_PLAY,
|
|
self.GAME_GRADE_D: self.GRADE_D,
|
|
self.GAME_GRADE_C: self.GRADE_C,
|
|
self.GAME_GRADE_B: self.GRADE_B,
|
|
self.GAME_GRADE_A: self.GRADE_A,
|
|
self.GAME_GRADE_A_PLUS: self.GRADE_A_PLUS,
|
|
self.GAME_GRADE_AA: self.GRADE_AA,
|
|
self.GAME_GRADE_AA_PLUS: self.GRADE_AA_PLUS,
|
|
self.GAME_GRADE_AAA: self.GRADE_AAA,
|
|
self.GAME_GRADE_AAA_PLUS: self.GRADE_AAA_PLUS,
|
|
self.GAME_GRADE_S: self.GRADE_S,
|
|
}[grade]
|
|
|
|
def __db_to_game_grade(self, grade: int) -> int:
|
|
return {
|
|
self.GRADE_NO_PLAY: self.GAME_GRADE_NO_PLAY,
|
|
self.GRADE_D: self.GAME_GRADE_D,
|
|
self.GRADE_C: self.GAME_GRADE_C,
|
|
self.GRADE_B: self.GAME_GRADE_B,
|
|
self.GRADE_A: self.GAME_GRADE_A,
|
|
self.GRADE_A_PLUS: self.GAME_GRADE_A_PLUS,
|
|
self.GRADE_AA: self.GAME_GRADE_AA,
|
|
self.GRADE_AA_PLUS: self.GAME_GRADE_AA_PLUS,
|
|
self.GRADE_AAA: self.GAME_GRADE_AAA,
|
|
self.GRADE_AAA_PLUS: self.GAME_GRADE_AAA_PLUS,
|
|
self.GRADE_S: self.GAME_GRADE_S,
|
|
}[grade]
|
|
|
|
def handle_game_sv4_exception_request(self, request: Node) -> Node:
|
|
return Node.void("game")
|
|
|
|
def handle_game_sv4_lounge_request(self, request: Node) -> Node:
|
|
game = Node.void("game")
|
|
# Refresh interval in seconds.
|
|
game.add_child(Node.u32("interval", 10))
|
|
return game
|
|
|
|
def handle_game_sv4_entry_s_request(self, request: Node) -> Node:
|
|
game = Node.void("game")
|
|
# This should be created on the fly for a lobby that we're in.
|
|
game.add_child(Node.u32("entry_id", 1))
|
|
return game
|
|
|
|
def handle_game_sv4_entry_e_request(self, request: Node) -> Node:
|
|
# Lobby destroy method, eid node (u32) should be used
|
|
# to destroy any open lobbies.
|
|
return Node.void("game")
|
|
|
|
def __get_skill_analyzer_seasons(self) -> Dict[int, str]:
|
|
return {
|
|
0: "第1回 Aコース",
|
|
1: "第1回 Bコース",
|
|
2: "第1回 Cコース",
|
|
3: "第2回 Aコース",
|
|
4: "第2回 Bコース",
|
|
5: "第3回",
|
|
6: "第4回 Aコース",
|
|
7: "第4回 Bコース",
|
|
8: "第4回 Cコース",
|
|
9: "第5回",
|
|
10: "第6回 Aコース",
|
|
11: "第6回 Bコース",
|
|
12: "第6回 Cコース",
|
|
13: "The 6th KAC挑戦コース【体】",
|
|
14: "The 6th KAC挑戦コース【技】",
|
|
15: "The 6th KAC挑戦コース【心】",
|
|
16: "天下一 (梅)",
|
|
17: "天下一 (竹)",
|
|
18: "天下一 (松)",
|
|
19: "BEMANI MASTER KOREA 2017",
|
|
20: "The 7th KACチャレンジコース【猛虎】",
|
|
21: "The 7th KACチャレンジコース【餓狼】",
|
|
22: "The 8th KACチャレンジコース【阿修羅】",
|
|
23: "The 8th KACエンジョイコース【阿修羅】",
|
|
24: "第5回 Bコース",
|
|
}
|
|
|
|
def __get_skill_analyzer_skill_levels(self) -> Dict[int, str]:
|
|
return {
|
|
1: "SKILL ANALYZER Level.01",
|
|
2: "SKILL ANALYZER Level.02",
|
|
3: "SKILL ANALYZER Level.03",
|
|
4: "SKILL ANALYZER Level.04",
|
|
5: "SKILL ANALYZER Level.05",
|
|
6: "SKILL ANALYZER Level.06",
|
|
7: "SKILL ANALYZER Level.07",
|
|
8: "SKILL ANALYZER Level.08",
|
|
9: "SKILL ANALYZER Level.09",
|
|
10: "SKILL ANALYZER Level.10",
|
|
11: "SKILL ANALYZER Level.11",
|
|
12: "SKILL ANALYZER Level.∞",
|
|
}
|
|
|
|
def __get_skill_analyzer_skill_name_ids(self) -> Dict[int, int]:
|
|
return {
|
|
1: self.GAME_SKILL_NAME_ID_LV_01,
|
|
2: self.GAME_SKILL_NAME_ID_LV_02,
|
|
3: self.GAME_SKILL_NAME_ID_LV_03,
|
|
4: self.GAME_SKILL_NAME_ID_LV_04,
|
|
5: self.GAME_SKILL_NAME_ID_LV_05,
|
|
6: self.GAME_SKILL_NAME_ID_LV_06,
|
|
7: self.GAME_SKILL_NAME_ID_LV_07,
|
|
8: self.GAME_SKILL_NAME_ID_LV_08,
|
|
9: self.GAME_SKILL_NAME_ID_LV_09,
|
|
10: self.GAME_SKILL_NAME_ID_LV_10,
|
|
11: self.GAME_SKILL_NAME_ID_LV_11,
|
|
12: self.GAME_SKILL_NAME_ID_LV_INF,
|
|
}
|
|
|
|
def __get_skill_analyzer_courses(self) -> List[Dict[str, Any]]:
|
|
return [
|
|
# Skill LV.01
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 653,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 846,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 23,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 60,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 770,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 16,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 17,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 922,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 76,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 201,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 182,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 766,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 106,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 568,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 768,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 795,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 110,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 51,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 258,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 913,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 189,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 1025,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 914,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 186,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 600,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 915,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 671,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 1035,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 1014,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1033,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 1044,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 1176,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 1083,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 1049,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 367,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 1005,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 1,
|
|
"tracks": [
|
|
{
|
|
"id": 1190,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 636,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 1054,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.02
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 6,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 222,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 48,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 566,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 748,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 19,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 22,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 40,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 275,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 171,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 950,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 513,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 185,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 700,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 923,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 219,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 528,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 996,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 87,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 486,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 66,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 93,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 664,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 3,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 191,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 771,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 8,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 405,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 451,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 173,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 1074,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1095,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 930,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 1057,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1081,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 868,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 1076,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1002,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 916,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.03
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 775,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 684,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 778,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 523,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 921,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 218,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
# Skill course for Season ID 2 was removed due to removed songs.
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 90,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 557,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 843,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 317,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 882,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 531,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 161,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 291,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 970,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 674,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 216,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 434,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 590,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 898,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 152,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 353,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 896,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 39,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 1008,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 608,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 815,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 1086,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1122,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1026,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 1001,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1092,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1113,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 1004,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1111,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1090,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.04
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 757,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 480,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 758,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 467,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 456,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 107,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 67,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 544,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 9,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 449,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 506,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 962,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 136,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 534,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 640,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 630,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 647,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 785,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 781,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 623,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 540,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 104,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 521,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 342,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 485,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 359,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 834,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 966,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 983,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 967,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 1070,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1073,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1022,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 1075,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1123,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1029,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 1094,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1128,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1027,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.05
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 871,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 327,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 66,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 435,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 750,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 700,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 318,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 157,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 567,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 760,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1020,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 923,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 65,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 966,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 874,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 645,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 335,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 961,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 695,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 276,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 870,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 743,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 958,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 441,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 790,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 277,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 944,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 964,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 58,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1025,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 1040,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1200,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 895,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 1024,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1201,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1124,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 1007,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1220,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1067,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.06
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 713,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 40,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 33,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 230,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 827,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 146,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 239,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 375,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 94,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 80,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 678,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 928,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 856,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 488,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 968,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 172,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 262,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 781,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 998,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 885,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 400,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 301,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 879,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 62,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 897,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 2,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 986,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 898,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 962,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1032,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 1115,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1184,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1230,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 1154,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1114,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 891,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 1139,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 864,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1010,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.07
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 349,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 896,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 246,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 210,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 558,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 368,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 769,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 710,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 609,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 967,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 711,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 594,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 738,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 264,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 834,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 762,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 544,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 898,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 211,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 14,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 183,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 666,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 54,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 763,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 145,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 99,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 90,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 490,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 889,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1042,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 1156,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1138,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1091,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 1012,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1248,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 926,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 1134,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 919,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1250,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.08
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 690,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 380,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 492,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 603,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 278,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 557,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 357,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 562,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 612,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 26,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 22,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 503,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 945,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 639,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 644,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 521,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 572,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 173,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 659,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 749,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 251,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 361,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 744,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 831,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 372,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 747,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 872,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 971,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 752,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1062,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 336,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1199,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1197,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 955,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1037,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 812,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 596,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 902,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 844,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.09
|
|
# Skill course for Season ID 0 was removed due to removed songs.
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 295,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 742,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 302,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 322,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 759,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 607,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 599,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 122,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 946,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 394,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 228,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 124,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 456,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 852,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 252,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 918,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 63,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 47,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 917,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 959,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 912,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 576,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 943,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 359,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 497,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 948,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 954,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 841,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1087,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1112,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 761,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 765,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1006,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 737,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 887,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 933,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.10
|
|
{
|
|
"season_id": 0,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 833,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 858,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 229,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 1,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 333,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 871,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 259,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 2,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 779,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 817,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 362,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 961,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 967,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 993,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 625,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 214,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 365,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 966,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 876,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 506,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 641,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 463,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 712,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 390,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 655,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 707,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 8,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 922,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 166,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 670,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 1126,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1034,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 834,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 1217,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1041,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1078,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 1237,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1157,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 907,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 12,
|
|
"skill_level": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 1228,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 881,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1135,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.11
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 941,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 718,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 816,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 4,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 30,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 2,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 540,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 931,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 818,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 810,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 789,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 634,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 532,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 808,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 965,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 909,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 1013,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1035,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1107,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 173,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 151,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 362,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 11,
|
|
"skill_level": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 1060,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1062,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1222,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
# Skill LV.Inf
|
|
{
|
|
"season_id": 3,
|
|
"skill_level": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 654,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 360,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 1028,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 5,
|
|
"skill_level": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 709,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 374,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 1036,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 6,
|
|
"skill_level": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 551,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1032,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1099,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 7,
|
|
"skill_level": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 927,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 525,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 1100,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 9,
|
|
"skill_level": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 1102,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1148,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1185,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 24,
|
|
"skill_level": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 661,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 258,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 791,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 10,
|
|
"skill_level": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 679,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1178,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 1270,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
# 6th KAC
|
|
{
|
|
"season_id": 13,
|
|
"course_id": 1,
|
|
"course_name": "The 6th KAC挑戦コース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_6TH_BODY,
|
|
"course_type": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 806,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 971,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 913,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 14,
|
|
"course_id": 1,
|
|
"course_name": "The 6th KAC挑戦コース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_6TH_TECHNOLOGY,
|
|
"course_type": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 758,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 965,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 914,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 15,
|
|
"course_id": 1,
|
|
"course_name": "The 6th KAC挑戦コース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_6TH_HEART,
|
|
"course_type": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 814,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 964,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 915,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 13,
|
|
"course_id": 2,
|
|
"course_name": "The 6th KAC挑戦コース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_6TH_BODY,
|
|
"course_type": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 806,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 971,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 913,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 14,
|
|
"course_id": 2,
|
|
"course_name": "The 6th KAC挑戦コース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_6TH_TECHNOLOGY,
|
|
"course_type": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 758,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 965,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 914,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 15,
|
|
"course_id": 2,
|
|
"course_name": "The 6th KAC挑戦コース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_6TH_HEART,
|
|
"course_type": 2,
|
|
"tracks": [
|
|
{
|
|
"id": 814,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 964,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 915,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
# Tenkaichi courses.
|
|
{
|
|
"season_id": 16,
|
|
"course_id": 1,
|
|
"course_name": "天下一",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_TENKAICHI,
|
|
"course_type": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 625,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 697,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 708,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 17,
|
|
"course_id": 1,
|
|
"course_name": "天下一",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_TENKAICHI,
|
|
"course_type": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 625,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 697,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 708,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 18,
|
|
"course_id": 1,
|
|
"course_name": "天下一",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_TENKAICHI,
|
|
"course_type": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 625,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 697,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 708,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 16,
|
|
"course_id": 2,
|
|
"course_name": "天下一",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_MUSIC_FESTIVAL,
|
|
"course_type": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 362,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 360,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 927,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 17,
|
|
"course_id": 2,
|
|
"course_name": "天下一",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_MUSIC_FESTIVAL,
|
|
"course_type": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 362,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 360,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 927,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 18,
|
|
"course_id": 2,
|
|
"course_name": "天下一",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_MUSIC_FESTIVAL,
|
|
"course_type": 3,
|
|
"tracks": [
|
|
{
|
|
"id": 362,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 360,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 927,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
# BMK2017 courses
|
|
{
|
|
"season_id": 19,
|
|
"course_id": 1,
|
|
"course_name": "BEMANI MASTER KOREA",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_BMK2017,
|
|
"tracks": [
|
|
{
|
|
"id": 954,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 960,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 961,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
# 7th KAC
|
|
{
|
|
"season_id": 20,
|
|
"course_id": 1,
|
|
"course_name": "The 7th KACチャレンジコース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_7TH_TIGER,
|
|
"course_type": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 1149,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 367,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1102,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 21,
|
|
"course_id": 1,
|
|
"course_name": "The 7th KACチャレンジコース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_7TH_WOLF,
|
|
"course_type": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 1042,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 126,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 1101,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 20,
|
|
"course_id": 2,
|
|
"course_name": "The 7th KACチャレンジコース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_7TH_TIGER,
|
|
"course_type": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 1149,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 367,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1102,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 21,
|
|
"course_id": 2,
|
|
"course_name": "The 7th KACチャレンジコース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_7TH_WOLF,
|
|
"course_type": 4,
|
|
"tracks": [
|
|
{
|
|
"id": 1042,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 126,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1101,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
# 8th KAC
|
|
{
|
|
"season_id": 22,
|
|
"course_id": 1,
|
|
"course_name": "The 8th KACチャレンジコース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_8TH,
|
|
"course_type": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 1334,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
{
|
|
"id": 610,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 1033,
|
|
"type": self.CHART_TYPE_MAXIMUM,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"season_id": 23,
|
|
"course_id": 1,
|
|
"course_name": "The 8th KACエンジョイコース",
|
|
"skill_name_id": self.GAME_SKILL_NAME_ID_KAC_8TH,
|
|
"course_type": 5,
|
|
"tracks": [
|
|
{
|
|
"id": 1334,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 610,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 1033,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
def handle_game_sv4_common_request(self, request: Node) -> Node:
|
|
game = Node.void("game")
|
|
|
|
limited = Node.void("music_limited")
|
|
game.add_child(limited)
|
|
|
|
# Song unlock config
|
|
game_config = self.get_game_config()
|
|
if game_config.get_bool("force_unlock_songs"):
|
|
ids = set()
|
|
songs = self.data.local.music.get_all_songs(self.game, self.version)
|
|
for song in songs:
|
|
if song.data.get_int("limited") in (
|
|
self.GAME_LIMITED_LOCKED,
|
|
self.GAME_LIMITED_UNLOCKABLE,
|
|
):
|
|
ids.add((song.id, song.chart))
|
|
|
|
for songid, chart in ids:
|
|
info = Node.void("info")
|
|
limited.add_child(info)
|
|
info.add_child(Node.s32("music_id", songid))
|
|
info.add_child(Node.u8("music_type", chart))
|
|
info.add_child(Node.u8("limited", self.GAME_LIMITED_UNLOCKED))
|
|
|
|
# Catalog, maybe this is for the online store?
|
|
catalog = Node.void("catalog")
|
|
game.add_child(catalog)
|
|
|
|
for _item in []: # type: ignore
|
|
info = Node.void("info")
|
|
catalog.add_child(info)
|
|
info.add_child(Node.u8("catalog_type", 0))
|
|
info.add_child(Node.u32("catalog_id", 0))
|
|
info.add_child(Node.u32("discount_rate", 0))
|
|
|
|
# Event config
|
|
event = Node.void("event")
|
|
game.add_child(event)
|
|
|
|
def enable_event(eid: str) -> None:
|
|
evt = Node.void("info")
|
|
event.add_child(evt)
|
|
evt.add_child(Node.string("event_id", eid))
|
|
|
|
if not game_config.get_bool("disable_matching"):
|
|
# Matching enabled events
|
|
enable_event("MATCHING_MODE")
|
|
enable_event("MATCHING_MODE_FREE_IP")
|
|
enable_event("ICON_FLOOR_INFECTION")
|
|
enable_event("ICON_POLICY_BREAK")
|
|
enable_event("ACHIEVEMENT_ENABLE")
|
|
enable_event("VOLFORCE_ENABLE")
|
|
enable_event("CONTINUATION")
|
|
enable_event("TENKAICHI_MODE")
|
|
enable_event("SERIALCODE_JAPAN")
|
|
enable_event("DEMOGAME_PLAY")
|
|
enable_event("TOTAL_MEMORIAL_ENABLE")
|
|
enable_event("EVENT_IDS_SERIALCODE_TOHO_02")
|
|
if game_config.get_bool("50th_anniversary"):
|
|
enable_event("KONAMI_50TH_LOGO")
|
|
enable_event("KAC6TH_FINISH")
|
|
enable_event("KAC7TH_FINISH")
|
|
enable_event("KAC8TH_FINISH")
|
|
|
|
# An old collaboration event we don't support.
|
|
reitaisai = Node.void("reitaisai2018")
|
|
game.add_child(reitaisai)
|
|
|
|
# Volte factory, an older event we don't support.
|
|
volte_factory = Node.void("volte_factory")
|
|
game.add_child(volte_factory)
|
|
goods = Node.void("goods")
|
|
volte_factory.add_child(goods)
|
|
stock = Node.void("stock")
|
|
volte_factory.add_child(stock)
|
|
|
|
# I think this is a list of purchaseable appeal cards.
|
|
appealcard = Node.void("appealcard")
|
|
game.add_child(appealcard)
|
|
|
|
# Event parameters (we don't support story mode).
|
|
extend = Node.void("extend")
|
|
game.add_child(extend)
|
|
|
|
# Available skill courses
|
|
skill_course = Node.void("skill_course")
|
|
game.add_child(skill_course)
|
|
|
|
achievements = self.data.local.user.get_all_achievements(
|
|
self.game, self.version, achievementtype="course"
|
|
)
|
|
courserates: Dict[Tuple[int, int], Dict[str, int]] = {}
|
|
|
|
def getrates(season_id: int, course_id: int) -> Dict[str, int]:
|
|
if (course_id, season_id) in courserates:
|
|
return courserates[(course_id, season_id)]
|
|
else:
|
|
return {
|
|
"attempts": 0,
|
|
"clears": 0,
|
|
"total_score": 0,
|
|
}
|
|
|
|
for _, achievement in achievements:
|
|
course_id = achievement.id % 100
|
|
season_id = int(achievement.id / 100)
|
|
rate = getrates(season_id, course_id)
|
|
|
|
rate["attempts"] += 1
|
|
if achievement.data.get_int("clear_type") >= 2:
|
|
rate["clears"] += 1
|
|
rate["total_score"] = achievement.data.get_int("score")
|
|
courserates[(course_id, season_id)] = rate
|
|
|
|
seasons = self.__get_skill_analyzer_seasons()
|
|
skill_levels = self.__get_skill_analyzer_skill_levels()
|
|
courses = self.__get_skill_analyzer_courses()
|
|
skill_name_ids = self.__get_skill_analyzer_skill_name_ids()
|
|
for course in courses:
|
|
info = Node.void("info")
|
|
skill_course.add_child(info)
|
|
|
|
info.add_child(Node.s32("season_id", course["season_id"]))
|
|
info.add_child(Node.string("season_name", seasons[course["season_id"]]))
|
|
info.add_child(
|
|
Node.bool("season_new_flg", course["season_id"] in {10, 11, 12, 22, 23})
|
|
)
|
|
info.add_child(
|
|
Node.s16(
|
|
"course_id", course.get("course_id", course.get("skill_level", -1))
|
|
)
|
|
)
|
|
info.add_child(
|
|
Node.string(
|
|
"course_name",
|
|
course.get(
|
|
"course_name",
|
|
skill_levels.get(course.get("skill_level", -1), ""),
|
|
),
|
|
)
|
|
)
|
|
# Course type 0 is skill level courses. The course type is the same as the skill level (01-12).
|
|
# If skill level is specified as '0', then the course type shows up as 'OTHER' instead of Skill Lv.01-12.
|
|
# Course type 2 = KAC 6th.
|
|
# Course type 3 = TENKAICHI mode.
|
|
# Course type 4 = KAC 7th.
|
|
# Course type 5 = KAC 8th.
|
|
info.add_child(Node.s16("course_type", course.get("course_type", 0)))
|
|
info.add_child(Node.s16("skill_level", course.get("skill_level", 0)))
|
|
info.add_child(
|
|
Node.s16(
|
|
"skill_name_id",
|
|
course.get(
|
|
"skill_name_id",
|
|
skill_name_ids.get(course.get("skill_level", -1), 0),
|
|
),
|
|
)
|
|
)
|
|
info.add_child(
|
|
Node.bool(
|
|
"matching_assist",
|
|
course.get("skill_level", -1) >= 1
|
|
and course.get("skill_level", -1) <= 7,
|
|
)
|
|
)
|
|
|
|
# Calculate clear rate and average score
|
|
rate = getrates(
|
|
course["season_id"],
|
|
course.get("course_id", course.get("skill_level", -1)),
|
|
)
|
|
if rate["attempts"] > 0:
|
|
info.add_child(
|
|
Node.s32(
|
|
"clear_rate", int(100.0 * (rate["clears"] / rate["attempts"]))
|
|
)
|
|
)
|
|
info.add_child(
|
|
Node.u32("avg_score", rate["total_score"] // rate["attempts"])
|
|
)
|
|
else:
|
|
info.add_child(Node.s32("clear_rate", 0))
|
|
info.add_child(Node.u32("avg_score", 0))
|
|
|
|
for trackno, trackdata in enumerate(course["tracks"]):
|
|
track = Node.void("track")
|
|
info.add_child(track)
|
|
track.add_child(Node.s16("track_no", trackno))
|
|
track.add_child(Node.s32("music_id", trackdata["id"]))
|
|
track.add_child(Node.s8("music_type", trackdata["type"]))
|
|
|
|
# Museca link event that we don't support.
|
|
museca_link = Node.void("museca_link")
|
|
game.add_child(museca_link)
|
|
|
|
return game
|
|
|
|
def handle_game_sv4_shop_request(self, request: Node) -> Node:
|
|
self.update_machine_name(request.child_value("shopname"))
|
|
|
|
# Respond with number of milliseconds until next request
|
|
game = Node.void("game")
|
|
game.add_child(Node.u32("nxt_time", 1000 * 5 * 60))
|
|
return game
|
|
|
|
def handle_game_sv4_hiscore_request(self, request: Node) -> Node:
|
|
# Grab location for local scores
|
|
locid = ID.parse_machine_id(request.child_value("locid"))
|
|
|
|
game = Node.void("game")
|
|
|
|
# Now, grab global and local scores as well as clear rates
|
|
global_records = self.data.remote.music.get_all_records(self.game, self.version)
|
|
users = {
|
|
uid: prof
|
|
for (uid, prof) in self.data.local.user.get_all_profiles(
|
|
self.game, self.version
|
|
)
|
|
}
|
|
area_users = [uid for uid in users if users[uid].get_int("loc", -1) == locid]
|
|
area_records = self.data.local.music.get_all_records(
|
|
self.game, self.version, userlist=area_users
|
|
)
|
|
clears = self.get_clear_rates()
|
|
records: Dict[int, Dict[int, Dict[str, Tuple[UserID, Score]]]] = {}
|
|
|
|
missing_users = [
|
|
userid for (userid, _) in global_records if userid not in users
|
|
] + [userid for (userid, _) in area_records if userid not in users]
|
|
for userid, profile in self.get_any_profiles(missing_users):
|
|
users[userid] = profile
|
|
|
|
for userid, score in global_records:
|
|
if userid not in users:
|
|
raise Exception("Logic error, missing profile for user!")
|
|
if score.id not in records:
|
|
records[score.id] = {}
|
|
if score.chart not in records[score.id]:
|
|
records[score.id][score.chart] = {}
|
|
records[score.id][score.chart]["global"] = (userid, score)
|
|
|
|
for userid, score in area_records:
|
|
if userid not in users:
|
|
raise Exception("Logic error, missing profile for user!")
|
|
if score.id not in records:
|
|
records[score.id] = {}
|
|
if score.chart not in records[score.id]:
|
|
records[score.id][score.chart] = {}
|
|
records[score.id][score.chart]["area"] = (userid, score)
|
|
|
|
# Output it to the game
|
|
highscores = Node.void("sc")
|
|
game.add_child(highscores)
|
|
for musicid in records:
|
|
for chart in records[musicid]:
|
|
(globaluserid, globalscore) = records[musicid][chart]["global"]
|
|
|
|
global_profile = users[globaluserid]
|
|
if clears[musicid][chart]["total"] > 0:
|
|
clear_rate = float(clears[musicid][chart]["clears"]) / float(
|
|
clears[musicid][chart]["total"]
|
|
)
|
|
else:
|
|
clear_rate = 0.0
|
|
|
|
info = Node.void("d")
|
|
highscores.add_child(info)
|
|
info.add_child(Node.u32("id", musicid))
|
|
info.add_child(Node.u32("ty", chart))
|
|
info.add_child(
|
|
Node.string("a_sq", ID.format_extid(global_profile.extid))
|
|
)
|
|
info.add_child(Node.string("a_nm", global_profile.get_str("name")))
|
|
info.add_child(Node.u32("a_sc", globalscore.points))
|
|
info.add_child(Node.s32("cr", int(clear_rate * 10000)))
|
|
info.add_child(Node.s32("avg_sc", clears[musicid][chart]["average"]))
|
|
|
|
if "area" in records[musicid][chart]:
|
|
(localuserid, localscore) = records[musicid][chart]["area"]
|
|
local_profile = users[localuserid]
|
|
info.add_child(
|
|
Node.string("l_sq", ID.format_extid(local_profile.extid))
|
|
)
|
|
info.add_child(Node.string("l_nm", local_profile.get_str("name")))
|
|
info.add_child(Node.u32("l_sc", localscore.points))
|
|
|
|
return game
|
|
|
|
def handle_game_sv4_load_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
root = self.get_profile_by_refid(refid)
|
|
if root is not None:
|
|
return root
|
|
|
|
# Figure out if this user has an older profile or not
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
|
|
if userid is not None:
|
|
previous_game = self.previous_version()
|
|
else:
|
|
previous_game = None
|
|
|
|
if previous_game is not None:
|
|
profile = previous_game.get_profile(userid)
|
|
else:
|
|
profile = None
|
|
|
|
if profile is not None:
|
|
root = Node.void("game")
|
|
root.add_child(Node.u8("result", 2))
|
|
root.add_child(Node.string("name", profile.get_str("name")))
|
|
return root
|
|
else:
|
|
root = Node.void("game")
|
|
root.add_child(Node.u8("result", 1))
|
|
return root
|
|
|
|
def handle_game_sv4_frozen_request(self, request: Node) -> Node:
|
|
game = Node.void("game")
|
|
game.add_child(Node.u8("result", 0))
|
|
return game
|
|
|
|
def handle_game_sv4_new_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
name = request.child_value("name")
|
|
loc = ID.parse_machine_id(request.child_value("locid"))
|
|
self.new_profile_by_refid(refid, name, loc)
|
|
|
|
root = Node.void("game")
|
|
return root
|
|
|
|
def handle_game_sv4_load_m_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
|
|
if refid is not None:
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
else:
|
|
userid = None
|
|
|
|
if userid is not None:
|
|
scores = self.data.remote.music.get_scores(self.game, self.version, userid)
|
|
else:
|
|
scores = []
|
|
|
|
# Output to the game
|
|
game = Node.void("game")
|
|
music = Node.void("music")
|
|
game.add_child(music)
|
|
|
|
for score in scores:
|
|
info = Node.void("info")
|
|
music.add_child(info)
|
|
|
|
stats = score.data.get_dict("stats")
|
|
info.add_child(
|
|
Node.u32_array(
|
|
"param",
|
|
[
|
|
score.id,
|
|
score.chart,
|
|
score.points,
|
|
self.__db_to_game_clear_type(score.data.get_int("clear_type")),
|
|
self.__db_to_game_grade(score.data.get_int("grade")),
|
|
0, # 5: Any value
|
|
0, # 6: Any value
|
|
stats.get_int("btn_rate"),
|
|
stats.get_int("long_rate"),
|
|
stats.get_int("vol_rate"),
|
|
0, # 10: Any value
|
|
0, # 11: Another medal, perhaps old score medal?
|
|
0, # 12: Another grade, perhaps old score grade?
|
|
0, # 13: Any value
|
|
0, # 14: Any value
|
|
0, # 15: Any value
|
|
0, # 16: Another medal, perhaps old score medal?
|
|
0, # 17: Another grade, perhaps old score grade?
|
|
0, # 18: Any value
|
|
0, # 19: Any value
|
|
],
|
|
),
|
|
)
|
|
|
|
return game
|
|
|
|
def handle_game_sv4_load_r_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
game = Node.void("game")
|
|
|
|
if refid is not None:
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
else:
|
|
userid = None
|
|
|
|
if userid is not None:
|
|
links = self.data.local.user.get_links(self.game, self.version, userid)
|
|
index = 0
|
|
for link in links:
|
|
if link.type != "rival":
|
|
continue
|
|
other_profile = self.get_profile(link.other_userid)
|
|
if other_profile is None:
|
|
continue
|
|
|
|
# Base information about rival
|
|
rival = Node.void("rival")
|
|
game.add_child(rival)
|
|
rival.add_child(Node.s16("no", index))
|
|
rival.add_child(
|
|
Node.string("seq", ID.format_extid(other_profile.extid))
|
|
)
|
|
rival.add_child(Node.string("name", other_profile.get_str("name")))
|
|
|
|
# Keep track of index
|
|
index = index + 1
|
|
|
|
# Return scores for this user on random charts
|
|
scores = self.data.remote.music.get_scores(
|
|
self.game, self.version, link.other_userid
|
|
)
|
|
for score in scores:
|
|
music = Node.void("music")
|
|
rival.add_child(music)
|
|
music.add_child(
|
|
Node.u32_array(
|
|
"param",
|
|
[
|
|
score.id,
|
|
score.chart,
|
|
score.points,
|
|
self.__db_to_game_clear_type(
|
|
score.data.get_int("clear_type")
|
|
),
|
|
self.__db_to_game_grade(score.data.get_int("grade")),
|
|
],
|
|
)
|
|
)
|
|
|
|
return game
|
|
|
|
def handle_game_sv4_save_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
|
|
if refid is not None:
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
else:
|
|
userid = None
|
|
|
|
if userid is not None:
|
|
oldprofile = self.get_profile(userid)
|
|
newprofile = self.unformat_profile(userid, request, oldprofile)
|
|
else:
|
|
newprofile = None
|
|
|
|
if userid is not None and newprofile is not None:
|
|
self.put_profile(userid, newprofile)
|
|
|
|
return Node.void("game")
|
|
|
|
def handle_game_sv4_save_m_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
|
|
if refid is not None:
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
else:
|
|
userid = None
|
|
|
|
# Doesn't matter if userid is None here, that's an anonymous score
|
|
musicid = request.child_value("music_id")
|
|
chart = request.child_value("music_type")
|
|
points = request.child_value("score")
|
|
combo = request.child_value("max_chain")
|
|
clear_type = self.__game_to_db_clear_type(request.child_value("clear_type"))
|
|
grade = self.__game_to_db_grade(request.child_value("score_grade"))
|
|
stats = {
|
|
"btn_rate": request.child_value("btn_rate"),
|
|
"long_rate": request.child_value("long_rate"),
|
|
"vol_rate": request.child_value("vol_rate"),
|
|
"critical": request.child_value("critical"),
|
|
"near": request.child_value("near"),
|
|
"error": request.child_value("error"),
|
|
}
|
|
|
|
# Save the score
|
|
self.update_score(
|
|
userid,
|
|
musicid,
|
|
chart,
|
|
points,
|
|
clear_type,
|
|
grade,
|
|
combo,
|
|
stats,
|
|
)
|
|
|
|
# Return a blank response
|
|
return Node.void("game")
|
|
|
|
def handle_game_sv4_play_e_request(self, request: Node) -> Node:
|
|
return Node.void("game")
|
|
|
|
def handle_game_sv4_save_e_request(self, request: Node) -> Node:
|
|
# This has to do with Policy floor infection, but we don't
|
|
# implement multi-game support so meh.
|
|
game = Node.void("game")
|
|
|
|
pbc_infection = Node.void("pbc_infection")
|
|
game.add_child(pbc_infection)
|
|
for name in ["packet", "block", "coloris"]:
|
|
child = Node.void(name)
|
|
pbc_infection.add_child(child)
|
|
child.add_child(Node.s32("before", 0))
|
|
child.add_child(Node.s32("after", 0))
|
|
|
|
pb_infection = Node.void("pb_infection")
|
|
game.add_child(pb_infection)
|
|
for name in ["packet", "block"]:
|
|
child = Node.void(name)
|
|
pb_infection.add_child(child)
|
|
child.add_child(Node.s32("before", 0))
|
|
child.add_child(Node.s32("after", 0))
|
|
|
|
return game
|
|
|
|
def handle_game_sv4_play_s_request(self, request: Node) -> Node:
|
|
root = Node.void("game")
|
|
root.add_child(Node.u32("play_id", 1))
|
|
return root
|
|
|
|
def handle_game_sv4_buy_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
|
|
if refid is not None:
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
else:
|
|
userid = None
|
|
|
|
if userid is not None:
|
|
profile = self.get_profile(userid)
|
|
else:
|
|
profile = None
|
|
|
|
if userid is not None and profile is not None:
|
|
# Look up packets and blocks
|
|
packet = profile.get_int("packet")
|
|
block = profile.get_int("block")
|
|
|
|
# Add on any additional we earned this round
|
|
packet = packet + (request.child_value("earned_gamecoin_packet") or 0)
|
|
block = block + (request.child_value("earned_gamecoin_block") or 0)
|
|
|
|
currency_type = request.child_value("currency_type")
|
|
price = request.child_value("item/price")
|
|
if isinstance(price, list):
|
|
# Sometimes we end up buying more than one item at once
|
|
price = sum(price)
|
|
|
|
if currency_type == self.GAME_CURRENCY_PACKETS:
|
|
# This is a valid purchase
|
|
newpacket = packet - price
|
|
if newpacket < 0:
|
|
result = 1
|
|
else:
|
|
packet = newpacket
|
|
result = 0
|
|
elif currency_type == self.GAME_CURRENCY_BLOCKS:
|
|
# This is a valid purchase
|
|
newblock = block - price
|
|
if newblock < 0:
|
|
result = 1
|
|
else:
|
|
block = newblock
|
|
result = 0
|
|
else:
|
|
# Bad currency type
|
|
result = 1
|
|
|
|
if result == 0:
|
|
# Transaction is valid, update the profile with new packets and blocks
|
|
profile.replace_int("packet", packet)
|
|
profile.replace_int("block", block)
|
|
self.put_profile(userid, profile)
|
|
|
|
# If this was a song unlock, we should mark it as unlocked
|
|
item_type = request.child_value("item/item_type")
|
|
item_id = request.child_value("item/item_id")
|
|
param = request.child_value("item/param")
|
|
|
|
if not isinstance(item_type, list):
|
|
# Sometimes we buy multiple things at once. Make it easier by always assuming this.
|
|
item_type = [item_type]
|
|
item_id = [item_id]
|
|
param = [param]
|
|
|
|
for i in range(len(item_type)):
|
|
self.data.local.user.put_achievement(
|
|
self.game,
|
|
self.version,
|
|
userid,
|
|
item_id[i],
|
|
f"item_{item_type[i]}",
|
|
{
|
|
"param": param[i],
|
|
},
|
|
)
|
|
|
|
else:
|
|
# Unclear what to do here, return a bad response
|
|
packet = 0
|
|
block = 0
|
|
result = 1
|
|
|
|
game = Node.void("game")
|
|
game.add_child(Node.u32("gamecoin_packet", packet))
|
|
game.add_child(Node.u32("gamecoin_block", block))
|
|
game.add_child(Node.s8("result", result))
|
|
return game
|
|
|
|
def handle_game_sv4_save_c_request(self, request: Node) -> Node:
|
|
refid = request.child_value("refid")
|
|
|
|
if refid is not None:
|
|
userid = self.data.remote.user.from_refid(self.game, self.version, refid)
|
|
else:
|
|
userid = None
|
|
|
|
if userid is not None:
|
|
season_id = request.child_value("ssnid")
|
|
course_id = request.child_value("crsid")
|
|
clear_type = request.child_value("ct")
|
|
achievement_rate = request.child_value("ar")
|
|
grade = request.child_value("gr")
|
|
score = request.child_value("sc")
|
|
|
|
# Do not update the course achievement when old score is greater.
|
|
old = self.data.local.user.get_achievement(
|
|
self.game, self.version, userid, (season_id * 100) + course_id, "course"
|
|
)
|
|
if old is not None and old.get_int("score") > score:
|
|
return Node.void("game")
|
|
|
|
self.data.local.user.put_achievement(
|
|
self.game,
|
|
self.version,
|
|
userid,
|
|
(season_id * 100) + course_id,
|
|
"course",
|
|
{
|
|
"clear_type": clear_type,
|
|
"achievement_rate": achievement_rate,
|
|
"score": score,
|
|
"grade": grade,
|
|
},
|
|
)
|
|
|
|
# Return a blank response
|
|
return Node.void("game")
|
|
|
|
def format_profile(self, userid: UserID, profile: Profile) -> Node:
|
|
game = Node.void("game")
|
|
|
|
# Generic profile stuff
|
|
game.add_child(Node.string("name", profile.get_str("name")))
|
|
game.add_child(Node.string("code", ID.format_extid(profile.extid)))
|
|
game.add_child(Node.string("sdvx_id", ID.format_extid(profile.extid)))
|
|
game.add_child(Node.u16("appeal_id", profile.get_int("appealid")))
|
|
game.add_child(Node.s16("skill_base_id", profile.get_int("skill_base_id")))
|
|
game.add_child(Node.s16("skill_name_id", profile.get_int("skill_name_id")))
|
|
game.add_child(Node.u32("gamecoin_packet", profile.get_int("packet")))
|
|
game.add_child(Node.u32("gamecoin_block", profile.get_int("block")))
|
|
game.add_child(Node.u32("blaster_energy", profile.get_int("blaster_energy")))
|
|
game.add_child(Node.u32("blaster_count", profile.get_int("blaster_count")))
|
|
|
|
# Play statistics
|
|
statistics = self.get_play_statistics(userid)
|
|
game.add_child(Node.u32("play_count", statistics.total_plays))
|
|
game.add_child(Node.u32("today_count", statistics.today_plays))
|
|
game.add_child(Node.u32("play_chain", statistics.consecutive_days))
|
|
|
|
# Also exists but we don't support:
|
|
# - day_count: Number of days where this user had at least one play.
|
|
# - max_play_chain: Max consecutive days in a row where the user had at last one play.
|
|
# - week_count: Number of weeks here this user had at least one play.
|
|
# - week_play_count: Number of plays in the last week (I think).
|
|
# - week_chain: Number of weeks in a row where the user had at least one play in that week.
|
|
# - max_week_chain: Maximum number of weeks in a row where the user had at least one play in that week.
|
|
|
|
# Player options and last touched song.
|
|
lastdict = profile.get_dict("last")
|
|
game.add_child(Node.s32("last_music_id", lastdict.get_int("music_id", -1)))
|
|
game.add_child(Node.u8("last_music_type", lastdict.get_int("music_type")))
|
|
game.add_child(Node.u8("sort_type", lastdict.get_int("sort_type")))
|
|
game.add_child(Node.u8("narrow_down", lastdict.get_int("narrow_down")))
|
|
game.add_child(Node.u8("headphone", lastdict.get_int("headphone")))
|
|
game.add_child(Node.u8("gauge_option", lastdict.get_int("gauge_option")))
|
|
game.add_child(Node.u8("ars_option", lastdict.get_int("ars_option")))
|
|
game.add_child(Node.u8("notes_option", lastdict.get_int("notes_option")))
|
|
game.add_child(Node.u8("early_late_disp", lastdict.get_int("early_late_disp")))
|
|
game.add_child(Node.u8("eff_c_left", lastdict.get_int("eff_c_left")))
|
|
game.add_child(Node.u8("eff_c_right", lastdict.get_int("eff_c_right", 1)))
|
|
game.add_child(Node.u32("lanespeed", lastdict.get_int("lanespeed")))
|
|
game.add_child(Node.s32("hispeed", lastdict.get_int("hispeed")))
|
|
game.add_child(Node.s32("draw_adjust", lastdict.get_int("draw_adjust")))
|
|
|
|
# Item unlocks
|
|
itemnode = Node.void("item")
|
|
game.add_child(itemnode)
|
|
|
|
game_config = self.get_game_config()
|
|
achievements = self.data.local.user.get_achievements(
|
|
self.game, self.version, userid
|
|
)
|
|
|
|
for item in achievements:
|
|
if item.type[:5] != "item_":
|
|
continue
|
|
itemtype = int(item.type[5:])
|
|
|
|
if (
|
|
game_config.get_bool("force_unlock_songs")
|
|
and itemtype == self.GAME_CATALOG_TYPE_SONG
|
|
):
|
|
# Don't echo unlocked songs, we will add all of them later
|
|
continue
|
|
if (
|
|
game_config.get_bool("force_unlock_cards")
|
|
and itemtype == self.GAME_CATALOG_TYPE_APPEAL_CARD
|
|
):
|
|
# Don't echo unlocked appeal cards, we will add all of them later
|
|
continue
|
|
if (
|
|
game_config.get_bool("force_unlock_crew")
|
|
and itemtype == self.GAME_CATALOG_TYPE_CREW
|
|
):
|
|
# Don't echo unlocked crew, we will add all of them later
|
|
continue
|
|
|
|
info = Node.void("info")
|
|
itemnode.add_child(info)
|
|
info.add_child(Node.u8("type", itemtype))
|
|
info.add_child(Node.u32("id", item.id))
|
|
info.add_child(Node.u32("param", item.data.get_int("param")))
|
|
|
|
if game_config.get_bool("force_unlock_songs"):
|
|
ids: Dict[int, int] = {}
|
|
songs = self.data.local.music.get_all_songs(self.game, self.version)
|
|
for song in songs:
|
|
if song.id not in ids:
|
|
ids[song.id] = 0
|
|
|
|
if song.data.get_int("difficulty") > 0:
|
|
ids[song.id] = ids[song.id] | (1 << song.chart)
|
|
|
|
for itemid in ids:
|
|
if ids[itemid] == 0:
|
|
continue
|
|
|
|
info = Node.void("info")
|
|
itemnode.add_child(info)
|
|
info.add_child(Node.u8("type", self.GAME_CATALOG_TYPE_SONG))
|
|
info.add_child(Node.u32("id", itemid))
|
|
info.add_child(Node.u32("param", ids[itemid]))
|
|
|
|
if game_config.get_bool("force_unlock_cards"):
|
|
catalog = self.data.local.game.get_items(self.game, self.version)
|
|
for unlock in catalog:
|
|
if unlock.type != "appealcard":
|
|
continue
|
|
|
|
info = Node.void("info")
|
|
itemnode.add_child(info)
|
|
info.add_child(Node.u8("type", self.GAME_CATALOG_TYPE_APPEAL_CARD))
|
|
info.add_child(Node.u32("id", unlock.id))
|
|
info.add_child(Node.u32("param", 1))
|
|
|
|
if game_config.get_bool("force_unlock_crew"):
|
|
for crewid in range(1, 999):
|
|
info = Node.void("info")
|
|
itemnode.add_child(info)
|
|
info.add_child(Node.u8("type", self.GAME_CATALOG_TYPE_CREW))
|
|
info.add_child(Node.u32("id", crewid))
|
|
info.add_child(Node.u32("param", 1))
|
|
|
|
# Skill courses
|
|
skill = Node.void("skill")
|
|
game.add_child(skill)
|
|
skill_level = 0
|
|
|
|
for course in achievements:
|
|
if course.type != "course":
|
|
continue
|
|
|
|
course_id = course.id % 100
|
|
season_id = int(course.id / 100)
|
|
|
|
if course.data.get_int("clear_type") >= 2:
|
|
# The user cleared this, lets take the highest level clear for this
|
|
courselist = [
|
|
c
|
|
for c in self.__get_skill_analyzer_courses()
|
|
if c.get("course_id", c.get("skill_level", -1)) == course_id
|
|
and c["season_id"] == season_id
|
|
]
|
|
if len(courselist) > 0:
|
|
skill_level = max(skill_level, courselist[0]["skill_level"])
|
|
|
|
course_node = Node.void("course")
|
|
skill.add_child(course_node)
|
|
course_node.add_child(Node.s16("ssnid", season_id))
|
|
course_node.add_child(Node.s16("crsid", course_id))
|
|
course_node.add_child(Node.s32("sc", course.data.get_int("score")))
|
|
course_node.add_child(Node.s16("ct", course.data.get_int("clear_type")))
|
|
course_node.add_child(Node.s16("gr", course.data.get_int("grade")))
|
|
course_node.add_child(
|
|
Node.s16("ar", course.data.get_int("achievement_rate"))
|
|
)
|
|
course_node.add_child(Node.s16("cnt", 1))
|
|
|
|
# Calculated skill level
|
|
game.add_child(Node.s16("skill_level", skill_level))
|
|
|
|
# Game parameters
|
|
paramnode = Node.void("param")
|
|
game.add_child(paramnode)
|
|
|
|
for param in achievements:
|
|
if param.type[:6] != "param_":
|
|
continue
|
|
paramtype = int(param.type[6:])
|
|
|
|
info = Node.void("info")
|
|
paramnode.add_child(info)
|
|
info.add_child(Node.s32("id", param.id))
|
|
info.add_child(Node.s32("type", paramtype))
|
|
info.add_child(
|
|
Node.s32_array("param", param.data["param"])
|
|
) # This looks to be variable, so no validation on length
|
|
|
|
# Infection nodes, we don't support these but it here for posterity.
|
|
pbc_infection = Node.void("pbc_infection")
|
|
game.add_child(pbc_infection)
|
|
for name in ["packet", "block", "coloris"]:
|
|
child = Node.void(name)
|
|
pbc_infection.add_child(child)
|
|
child.add_child(Node.s32("before", 0))
|
|
child.add_child(Node.s32("after", 0))
|
|
|
|
pb_infection = Node.void("pb_infection")
|
|
game.add_child(pb_infection)
|
|
for name in ["packet", "block"]:
|
|
child = Node.void(name)
|
|
pb_infection.add_child(child)
|
|
child.add_child(Node.s32("before", 0))
|
|
child.add_child(Node.s32("after", 0))
|
|
|
|
return game
|
|
|
|
def unformat_profile(
|
|
self, userid: UserID, request: Node, oldprofile: Profile
|
|
) -> Profile:
|
|
newprofile = oldprofile.clone()
|
|
|
|
# Update blaster energy and in-game currencies
|
|
earned_gamecoin_packet = request.child_value("earned_gamecoin_packet")
|
|
if earned_gamecoin_packet is not None:
|
|
newprofile.replace_int(
|
|
"packet", newprofile.get_int("packet") + earned_gamecoin_packet
|
|
)
|
|
earned_gamecoin_block = request.child_value("earned_gamecoin_block")
|
|
if earned_gamecoin_block is not None:
|
|
newprofile.replace_int(
|
|
"block", newprofile.get_int("block") + earned_gamecoin_block
|
|
)
|
|
earned_blaster_energy = request.child_value("earned_blaster_energy")
|
|
if earned_blaster_energy is not None:
|
|
newprofile.replace_int(
|
|
"blaster_energy",
|
|
newprofile.get_int("blaster_energy") + earned_blaster_energy,
|
|
)
|
|
|
|
# Miscelaneous profile stuff
|
|
newprofile.replace_int("blaster_count", request.child_value("blaster_count"))
|
|
newprofile.replace_int("appealid", request.child_value("appeal_id"))
|
|
newprofile.replace_int("skill_level", request.child_value("skill_level"))
|
|
newprofile.replace_int("skill_base_id", request.child_value("skill_base_id"))
|
|
newprofile.replace_int("skill_name_id", request.child_value("skill_name_id"))
|
|
|
|
# Update user's unlock status if we aren't force unlocked
|
|
game_config = self.get_game_config()
|
|
|
|
if request.child("item") is not None:
|
|
for child in request.child("item").children:
|
|
if child.name != "info":
|
|
continue
|
|
|
|
item_id = child.child_value("id")
|
|
item_type = child.child_value("type")
|
|
param = child.child_value("param")
|
|
|
|
if (
|
|
game_config.get_bool("force_unlock_cards")
|
|
and item_type == self.GAME_CATALOG_TYPE_APPEAL_CARD
|
|
):
|
|
# Don't save back appeal cards because they were force unlocked
|
|
continue
|
|
if (
|
|
game_config.get_bool("force_unlock_songs")
|
|
and item_type == self.GAME_CATALOG_TYPE_SONG
|
|
):
|
|
# Don't save back songs, because they were force unlocked
|
|
continue
|
|
if (
|
|
game_config.get_bool("force_unlock_crew")
|
|
and item_type == self.GAME_CATALOG_TYPE_CREW
|
|
):
|
|
# Don't save back crew, because they were force unlocked
|
|
continue
|
|
|
|
self.data.local.user.put_achievement(
|
|
self.game,
|
|
self.version,
|
|
userid,
|
|
item_id,
|
|
f"item_{item_type}",
|
|
{
|
|
"param": param,
|
|
},
|
|
)
|
|
|
|
# Update params
|
|
if request.child("param") is not None:
|
|
for child in request.child("param").children:
|
|
if child.name != "info":
|
|
continue
|
|
|
|
param_id = child.child_value("id")
|
|
param_type = child.child_value("type")
|
|
param_param = child.child_value("param")
|
|
self.data.local.user.put_achievement(
|
|
self.game,
|
|
self.version,
|
|
userid,
|
|
param_id,
|
|
f"param_{param_type}",
|
|
{
|
|
"param": param_param,
|
|
},
|
|
)
|
|
|
|
# Grab last information and player options.
|
|
lastdict = newprofile.get_dict("last")
|
|
lastdict.replace_int("music_id", request.child_value("music_id"))
|
|
lastdict.replace_int("music_type", request.child_value("music_type"))
|
|
lastdict.replace_int("sort_type", request.child_value("sort_type"))
|
|
lastdict.replace_int("narrow_down", request.child_value("narrow_down"))
|
|
lastdict.replace_int("headphone", request.child_value("headphone"))
|
|
lastdict.replace_int("gauge_option", request.child_value("gauge_option"))
|
|
lastdict.replace_int("ars_option", request.child_value("ars_option"))
|
|
lastdict.replace_int("notes_option", request.child_value("notes_option"))
|
|
lastdict.replace_int("early_late_disp", request.child_value("early_late_disp"))
|
|
lastdict.replace_int("eff_c_left", request.child_value("eff_c_left"))
|
|
lastdict.replace_int("eff_c_right", request.child_value("eff_c_right"))
|
|
lastdict.replace_int("lanespeed", request.child_value("lanespeed"))
|
|
lastdict.replace_int("hispeed", request.child_value("hispeed"))
|
|
lastdict.replace_int("draw_adjust", request.child_value("draw_adjust"))
|
|
|
|
# Save back last information gleaned from results
|
|
newprofile.replace_dict("last", lastdict)
|
|
|
|
# Keep track of play statistics
|
|
self.update_play_statistics(userid)
|
|
|
|
return newprofile
|