2544 lines
83 KiB
Python
2544 lines
83 KiB
Python
# vim: set fileencoding=utf-8
|
|
from typing import Any, Dict, List, Optional
|
|
from typing_extensions import Final
|
|
|
|
from bemani.backend.ess import EventLogHandler
|
|
from bemani.backend.sdvx.base import SoundVoltexBase
|
|
from bemani.backend.sdvx.booth import SoundVoltexBooth
|
|
from bemani.common import Profile, VersionConstants, ID
|
|
from bemani.data import UserID
|
|
from bemani.protocol import Node
|
|
|
|
|
|
class SoundVoltexInfiniteInfection(
|
|
EventLogHandler,
|
|
SoundVoltexBase,
|
|
):
|
|
|
|
name: str = "SOUND VOLTEX II -infinite infection-"
|
|
version: int = VersionConstants.SDVX_INFINITE_INFECTION
|
|
|
|
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_CLEAR_TYPE_NO_CLEAR: Final[int] = 1
|
|
GAME_CLEAR_TYPE_CLEAR: Final[int] = 2
|
|
GAME_CLEAR_TYPE_HARD_CLEAR: Final[int] = 5
|
|
GAME_CLEAR_TYPE_ULTIMATE_CHAIN: Final[int] = 3
|
|
GAME_CLEAR_TYPE_PERFECT_ULTIMATE_CHAIN: Final[int] = 4
|
|
|
|
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_AA: Final[int] = 5
|
|
GAME_GRADE_AAA: Final[int] = 6
|
|
|
|
GAME_CATALOG_TYPE_SONG: Final[int] = 0
|
|
GAME_CATALOG_TYPE_APPEAL_CARD: Final[int] = 1
|
|
GAME_CATALOG_TYPE_SPECIAL_SONG: Final[int] = 2
|
|
|
|
GAME_GAUGE_TYPE_SKILL: Final[int] = 1
|
|
|
|
@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",
|
|
},
|
|
],
|
|
"ints": [
|
|
{
|
|
"name": "BEMANI Stadium Event Phase",
|
|
"tip": "BEMANI Stadium event phase for all players.",
|
|
"category": "game_config",
|
|
"setting": "bemani_stadium",
|
|
"values": {
|
|
0: "No Event",
|
|
1: "BEMANI Stadium",
|
|
2: "BEMANI iseki",
|
|
},
|
|
},
|
|
],
|
|
}
|
|
|
|
def previous_version(self) -> Optional[SoundVoltexBase]:
|
|
return SoundVoltexBooth(self.data, self.config, self.model)
|
|
|
|
def __game_to_db_clear_type(self, clear_type: int) -> int:
|
|
return {
|
|
self.GAME_CLEAR_TYPE_NO_CLEAR: 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_CLEAR,
|
|
self.CLEAR_TYPE_FAILED: self.GAME_CLEAR_TYPE_NO_CLEAR,
|
|
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_AA: self.GRADE_AA,
|
|
self.GAME_GRADE_AAA: self.GRADE_AAA,
|
|
}[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,
|
|
self.GRADE_AA: self.GAME_GRADE_AA,
|
|
self.GRADE_AA_PLUS: self.GAME_GRADE_AA,
|
|
self.GRADE_AAA: self.GAME_GRADE_AAA,
|
|
self.GRADE_AAA_PLUS: self.GAME_GRADE_AAA,
|
|
self.GRADE_S: self.GAME_GRADE_AAA,
|
|
}[grade]
|
|
|
|
def __get_skill_analyzer_seasons(self) -> Dict[int, str]:
|
|
return {
|
|
6: "SKILL ANALYZER 第6回 (2013/12/06)",
|
|
7: "SKILL ANALYZER 第7回 (2014/01/10)",
|
|
8: "SKILL ANALYZER 第8回 (2014/02/06)",
|
|
9: "SKILL ANALYZER 第9回 (2014/03/06)",
|
|
10: "SKILL ANALYZER 第10回 (2014/04/04)",
|
|
11: "SKILL ANALYZER 第11回 (2014/05/01)",
|
|
12: "SKILL ANALYZER 第12回 (2014/06/05)",
|
|
13: "SKILL ANALYZER 第13回 (2014/07/04)",
|
|
14: "SKILL ANALYZER 第14回 (2014/08/01)",
|
|
}
|
|
|
|
def __get_skill_analyzer_skill_levels(self) -> Dict[int, str]:
|
|
return {
|
|
0: "Skill LEVEL 01 岳翔",
|
|
1: "Skill LEVEL 02 流星",
|
|
2: "Skill LEVEL 03 月衝",
|
|
3: "Skill LEVEL 04 瞬光",
|
|
4: "Skill LEVEL 05 天極",
|
|
5: "Skill LEVEL 06 烈風",
|
|
6: "Skill LEVEL 07 雷電",
|
|
7: "Skill LEVEL 08 麗華",
|
|
8: "Skill LEVEL 09 魔騎士",
|
|
9: "Skill LEVEL 10 剛力羅",
|
|
10: "Skill LEVEL 11 或帝滅斗",
|
|
11: "Skill LEVEL ∞(12) 暴龍天",
|
|
}
|
|
|
|
def __get_skill_analyzer_courses(self) -> List[Dict[str, Any]]:
|
|
return [
|
|
{
|
|
"level": 0,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 109,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 24,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 245,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 22,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 313,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 7,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 4,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 39,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 322,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 134,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 87,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 314,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 126,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 59,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 23,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 86,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 128,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 2,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 256,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 255,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 246,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 96,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 139,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 216,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 244,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 250,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 180,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 6,
|
|
"tracks": [
|
|
{
|
|
"id": 7,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 214,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 126,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 54,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 221,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 51,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 6,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 111,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 183,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 56,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 333,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 10,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 134,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 343,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 75,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 36,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 369,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 224,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 90,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 323,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 128,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 85,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 344,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 241,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 251,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 139,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 341,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 346,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 116,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 302,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 7,
|
|
"tracks": [
|
|
{
|
|
"id": 19,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 329,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 289,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 54,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 221,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 51,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 6,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 111,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 183,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 56,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 333,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 10,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 134,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 343,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 75,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 36,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 369,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 224,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 90,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 323,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 128,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 85,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 344,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 241,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 251,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 139,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 341,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 346,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 116,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 302,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 8,
|
|
"tracks": [
|
|
{
|
|
"id": 19,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 329,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 289,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 60,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 87,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 328,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 278,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 313,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 41,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 90,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 80,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 295,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 45,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 44,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 326,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 258,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 340,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 23,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 90,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 115,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 288,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 57,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 267,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 246,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 304,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 155,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 373,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 122,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 359,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 247,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 9,
|
|
"tracks": [
|
|
{
|
|
"id": 221,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 229,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 363,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 365,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 328,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 51,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 126,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 111,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 41,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 15,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 322,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 10,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 259,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 299,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 22,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 258,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 23,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 66,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 62,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 85,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 288,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 78,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 311,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 71,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 87,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 341,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 173,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 63,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 228,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 166,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 10,
|
|
"tracks": [
|
|
{
|
|
"id": 155,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 229,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 384,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 54,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 365,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 374,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 126,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 22,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 183,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 56,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 39,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 10,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 369,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 299,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 222,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 103,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 158,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 74,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 262,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 128,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 79,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 264,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 71,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 192,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 253,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 299,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 341,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 58,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 343,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 269,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 11,
|
|
"tracks": [
|
|
{
|
|
"id": 116,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 289,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 376,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 189,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 245,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 367,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 278,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 340,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 183,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 426,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 349,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 322,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 342,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 190,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 222,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 158,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 352,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 212,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 275,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 198,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 331,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 184,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 345,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 218,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 268,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 299,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 373,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 244,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 414,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 269,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 12,
|
|
"tracks": [
|
|
{
|
|
"id": 408,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 376,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 362,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 189,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 219,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 367,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 278,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 340,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 313,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 90,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 223,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 322,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 299,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 407,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 77,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 36,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 92,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 337,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 8,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 375,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 426,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 401,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 345,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 290,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 432,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 72,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 373,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 125,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 302,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 252,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 13,
|
|
"tracks": [
|
|
{
|
|
"id": 247,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 437,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 342,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 0,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 228,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 374,
|
|
"type": self.CHART_TYPE_NOVICE,
|
|
},
|
|
{
|
|
"id": 24,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 1,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 76,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 8,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 309,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 2,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 412,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 155,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 99,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 3,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 269,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 24,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 171,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 4,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 258,
|
|
"type": self.CHART_TYPE_ADVANCED,
|
|
},
|
|
{
|
|
"id": 92,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 34,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 5,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 42,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 275,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 480,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 6,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 170,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 264,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 307,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 7,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 253,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 72,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 430,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 8,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 63,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 343,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 220,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 9,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 413,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 437,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 362,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 10,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 258,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 374,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 360,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"level": 11,
|
|
"season_id": 14,
|
|
"tracks": [
|
|
{
|
|
"id": 366,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
{
|
|
"id": 126,
|
|
"type": self.CHART_TYPE_INFINITE,
|
|
},
|
|
{
|
|
"id": 367,
|
|
"type": self.CHART_TYPE_EXHAUST,
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
def handle_game_2_exception_request(self, request: Node) -> Node:
|
|
return Node.void("game_2")
|
|
|
|
def handle_game_2_play_e_request(self, request: Node) -> Node:
|
|
return Node.void("game_2")
|
|
|
|
def handle_game_2_save_e_request(self, request: Node) -> Node:
|
|
# This has to do with Policy Break against ReflecBeat and
|
|
# floor infection, but we don't implement multi-game support so meh.
|
|
return Node.void("game_2")
|
|
|
|
def handle_game_2_lounge_request(self, request: Node) -> Node:
|
|
game = Node.void("game_2")
|
|
# Refresh interval in seconds.
|
|
game.add_child(Node.u32("interval", 10))
|
|
return game
|
|
|
|
def handle_game_2_entry_s_request(self, request: Node) -> Node:
|
|
game = Node.void("game_2")
|
|
# 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_2_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_2")
|
|
|
|
def handle_game_2_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_2")
|
|
game.add_child(Node.u32("nxt_time", 1000 * 5 * 60))
|
|
return game
|
|
|
|
def handle_game_2_common_request(self, request: Node) -> Node:
|
|
game = Node.void("game_2")
|
|
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))
|
|
|
|
# Event config
|
|
event = Node.void("event")
|
|
game.add_child(event)
|
|
|
|
def enable_event(eid: int) -> None:
|
|
evt = Node.void("info")
|
|
event.add_child(evt)
|
|
evt.add_child(Node.u32("event_id", eid))
|
|
|
|
if not game_config.get_bool("disable_matching"):
|
|
enable_event(1) # Matching enabled
|
|
enable_event(2) # BEMANI Academy
|
|
enable_event(3) # Floor Infection
|
|
enable_event(6) # Skill Analyzer
|
|
enable_event(9) # Policy Break
|
|
enable_event(14) # Enable pages on Skill Analyzer
|
|
|
|
stadium = game_config.get_int("bemani_stadium")
|
|
if stadium == 1:
|
|
enable_event(18) # BEMANI Stadium (mutually exclusive with BEMANI iseki)
|
|
if stadium == 2:
|
|
enable_event(51) # BEMANI iseki (mutually exclusive with BEMANI Stadium)
|
|
|
|
# In-game purchases catalog config (this isn't necessary for SDVX 2 to work).
|
|
catalog = Node.void("catalog")
|
|
game.add_child(catalog)
|
|
songunlocks = self.data.local.game.get_items(self.game, self.version)
|
|
for unlock in songunlocks:
|
|
if unlock.type == "song_unlock":
|
|
info = Node.void("info")
|
|
catalog.add_child(info)
|
|
info.add_child(Node.u8("catalog_type", self.GAME_CATALOG_TYPE_SONG))
|
|
info.add_child(Node.u32("catalog_id", unlock.id))
|
|
info.add_child(Node.u32("currency_type", self.GAME_CURRENCY_BLOCKS))
|
|
info.add_child(Node.u32("price", unlock.data.get_int("blocks")))
|
|
elif unlock.type == "special_unlock":
|
|
info = Node.void("info")
|
|
catalog.add_child(info)
|
|
info.add_child(
|
|
Node.u8("catalog_type", self.GAME_CATALOG_TYPE_SPECIAL_SONG)
|
|
)
|
|
info.add_child(Node.u32("catalog_id", unlock.id))
|
|
info.add_child(Node.u32("currency_type", self.GAME_CURRENCY_BLOCKS))
|
|
info.add_child(Node.u32("price", unlock.data.get_int("blocks")))
|
|
|
|
# Skill Analyzer config
|
|
skill_course = Node.void("skill_course")
|
|
game.add_child(skill_course)
|
|
|
|
seasons = self.__get_skill_analyzer_seasons()
|
|
skillnames = self.__get_skill_analyzer_skill_levels()
|
|
last_season = max(seasons.keys())
|
|
for course in self.__get_skill_analyzer_courses():
|
|
info = Node.void("info")
|
|
skill_course.add_child(info)
|
|
info.add_child(Node.s16("course_id", course["level"]))
|
|
info.add_child(Node.s16("level", course["level"]))
|
|
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"] == last_season)
|
|
)
|
|
info.add_child(Node.string("course_name", skillnames[course["level"]]))
|
|
info.add_child(Node.s16("course_type", 0))
|
|
info.add_child(Node.s16("skill_name_id", course["level"]))
|
|
info.add_child(Node.bool("matching_assist", course["level"] <= 6))
|
|
info.add_child(Node.s16("gauge_type", self.GAME_GAUGE_TYPE_SKILL))
|
|
info.add_child(Node.s16("paseli_type", 0))
|
|
|
|
trackno = 0
|
|
for trackdata in 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"]))
|
|
trackno = trackno + 1
|
|
|
|
return game
|
|
|
|
def handle_game_2_hiscore_request(self, request: Node) -> Node:
|
|
# Grab location for local scores
|
|
locid = ID.parse_machine_id(request.child_value("locid"))
|
|
|
|
# Start the response packet
|
|
game = Node.void("game_2")
|
|
|
|
# First, grab hit chart
|
|
playcounts = self.data.local.music.get_hit_chart(self.game, self.version, 1024)
|
|
|
|
hitchart = Node.void("hitchart")
|
|
game.add_child(hitchart)
|
|
for (songid, count) in playcounts:
|
|
info = Node.void("info")
|
|
hitchart.add_child(info)
|
|
info.add_child(Node.u32("id", songid))
|
|
info.add_child(Node.u32("cnt", count))
|
|
|
|
# Now, grab user records
|
|
records = self.data.remote.music.get_all_records(self.game, self.version)
|
|
missing_users = [userid for (userid, _) in records]
|
|
users = {
|
|
userid: profile
|
|
for (userid, profile) in self.get_any_profiles(missing_users)
|
|
}
|
|
|
|
hiscore_allover = Node.void("hiscore_allover")
|
|
game.add_child(hiscore_allover)
|
|
|
|
# Output records
|
|
for (userid, score) in records:
|
|
info = Node.void("info")
|
|
|
|
if userid not in users:
|
|
raise Exception("Logic error, missing profile for user!")
|
|
profile = users[userid]
|
|
|
|
info.add_child(Node.u32("id", score.id))
|
|
info.add_child(Node.u32("type", score.chart))
|
|
info.add_child(Node.string("name", profile.get_str("name")))
|
|
info.add_child(Node.string("code", ID.format_extid(profile.extid)))
|
|
info.add_child(Node.u32("score", score.points))
|
|
|
|
# Add to global scores
|
|
hiscore_allover.add_child(info)
|
|
|
|
# Now, grab local records
|
|
area_users = [
|
|
uid
|
|
for (uid, prof) in self.data.local.user.get_all_profiles(
|
|
self.game, self.version
|
|
)
|
|
if prof.get_int("loc", -1) == locid
|
|
]
|
|
records = self.data.local.music.get_all_records(
|
|
self.game, self.version, userlist=area_users
|
|
)
|
|
missing_users = [userid for (userid, _) in records if userid not in users]
|
|
for (userid, profile) in self.get_any_profiles(missing_users):
|
|
users[userid] = profile
|
|
|
|
hiscore_location = Node.void("hiscore_location")
|
|
game.add_child(hiscore_location)
|
|
|
|
# Output records
|
|
for (userid, score) in records:
|
|
info = Node.void("info")
|
|
|
|
if userid not in users:
|
|
raise Exception("Logic error, missing profile for user!")
|
|
profile = users[userid]
|
|
|
|
info.add_child(Node.u32("id", score.id))
|
|
info.add_child(Node.u32("type", score.chart))
|
|
info.add_child(Node.string("name", profile.get_str("name")))
|
|
info.add_child(Node.string("code", ID.format_extid(profile.extid)))
|
|
info.add_child(Node.u32("score", score.points))
|
|
|
|
# Add to local scores
|
|
hiscore_location.add_child(info)
|
|
|
|
# Now, grab clear rates
|
|
clear_rate = Node.void("clear_rate")
|
|
game.add_child(clear_rate)
|
|
|
|
clears = self.get_clear_rates()
|
|
for songid in clears:
|
|
for chart in clears[songid]:
|
|
if clears[songid][chart]["total"] > 0:
|
|
rate = float(clears[songid][chart]["clears"]) / float(
|
|
clears[songid][chart]["total"]
|
|
)
|
|
dnode = Node.void("d")
|
|
clear_rate.add_child(dnode)
|
|
dnode.add_child(Node.u32("id", songid))
|
|
dnode.add_child(Node.u32("type", chart))
|
|
dnode.add_child(Node.s16("cr", int(rate * 10000)))
|
|
|
|
return game
|
|
|
|
def handle_game_2_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_2")
|
|
return root
|
|
|
|
def handle_game_2_frozen_request(self, request: Node) -> Node:
|
|
game = Node.void("game_2")
|
|
game.add_child(Node.u8("result", 0))
|
|
return game
|
|
|
|
def handle_game_2_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_2")
|
|
root.add_child(Node.u8("result", 2))
|
|
root.add_child(Node.string("name", profile.get_str("name")))
|
|
return root
|
|
else:
|
|
root = Node.void("game_2")
|
|
root.add_child(Node.u8("result", 1))
|
|
return root
|
|
|
|
def handle_game_2_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_2")
|
|
|
|
def handle_game_2_load_m_request(self, request: Node) -> Node:
|
|
refid = request.child_value("dataid")
|
|
|
|
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_2")
|
|
new = Node.void("new")
|
|
game.add_child(new)
|
|
|
|
for score in scores:
|
|
music = Node.void("music")
|
|
new.add_child(music)
|
|
music.add_child(Node.u32("music_id", score.id))
|
|
music.add_child(Node.u32("music_type", score.chart))
|
|
music.add_child(Node.u32("score", score.points))
|
|
music.add_child(Node.u32("cnt", score.plays))
|
|
music.add_child(
|
|
Node.u32(
|
|
"clear_type",
|
|
self.__db_to_game_clear_type(score.data.get_int("clear_type")),
|
|
)
|
|
)
|
|
music.add_child(
|
|
Node.u32(
|
|
"score_grade", self.__db_to_game_grade(score.data.get_int("grade"))
|
|
)
|
|
)
|
|
stats = score.data.get_dict("stats")
|
|
music.add_child(Node.u32("btn_rate", stats.get_int("btn_rate")))
|
|
music.add_child(Node.u32("long_rate", stats.get_int("long_rate")))
|
|
music.add_child(Node.u32("vol_rate", stats.get_int("vol_rate")))
|
|
|
|
return game
|
|
|
|
def handle_game_2_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_2")
|
|
|
|
def handle_game_2_save_c_request(self, request: Node) -> Node:
|
|
refid = request.child_value("dataid")
|
|
|
|
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:
|
|
course_id = request.child_value("crsid")
|
|
clear_type = request.child_value("ct")
|
|
achievement_rate = request.child_value("ar")
|
|
season_id = request.child_value("ssnid")
|
|
|
|
# Do not update the course achievement when old achievement rate 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("achievement_rate") > achievement_rate:
|
|
return Node.void("game_2")
|
|
|
|
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,
|
|
},
|
|
)
|
|
|
|
# Return a blank response
|
|
return Node.void("game_2")
|
|
|
|
def handle_game_2_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("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_type")
|
|
item_id = request.child_value("item_id")
|
|
param = request.child_value("param")
|
|
|
|
self.data.local.user.put_achievement(
|
|
self.game,
|
|
self.version,
|
|
userid,
|
|
item_id,
|
|
f"item_{item_type}",
|
|
{
|
|
"param": param,
|
|
},
|
|
)
|
|
|
|
else:
|
|
# Unclear what to do here, return a bad response
|
|
packet = 0
|
|
block = 0
|
|
result = 1
|
|
|
|
game = Node.void("game_2")
|
|
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 format_profile(self, userid: UserID, profile: Profile) -> Node:
|
|
game = Node.void("game_2")
|
|
|
|
# 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.u32("gamecoin_packet", profile.get_int("packet")))
|
|
game.add_child(Node.u32("gamecoin_block", profile.get_int("block")))
|
|
game.add_child(Node.s16("skill_name_id", profile.get_int("skill_name_id", -1)))
|
|
game.add_child(
|
|
Node.s32_array("hidden_param", profile.get_int_array("hidden_param", 20))
|
|
)
|
|
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("daily_count", statistics.today_plays))
|
|
game.add_child(Node.u32("play_chain", statistics.consecutive_days))
|
|
|
|
# Last played stuff
|
|
if "last" in profile:
|
|
lastdict = profile.get_dict("last")
|
|
last = Node.void("last")
|
|
game.add_child(last)
|
|
last.add_child(Node.s32("music_id", lastdict.get_int("music_id", -1)))
|
|
last.add_child(Node.u8("music_type", lastdict.get_int("music_type")))
|
|
last.add_child(Node.u8("sort_type", lastdict.get_int("sort_type")))
|
|
last.add_child(Node.u8("narrow_down", lastdict.get_int("narrow_down")))
|
|
last.add_child(Node.u8("headphone", lastdict.get_int("headphone")))
|
|
last.add_child(Node.u8("hispeed", lastdict.get_int("hispeed", 8)))
|
|
last.add_child(Node.u16("appeal_id", lastdict.get_int("appeal_id", 1001)))
|
|
last.add_child(Node.u16("comment_id", lastdict.get_int("comment_id")))
|
|
last.add_child(Node.u8("gauge_option", lastdict.get_int("gauge_option")))
|
|
|
|
# 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 itemtype == self.GAME_CATALOG_TYPE_APPEAL_CARD:
|
|
# Type 1 is appeal cards, and the game saves this for non-default cards but
|
|
# we take care of this below.
|
|
continue
|
|
if itemtype == self.GAME_CATALOG_TYPE_SONG and game_config.get_bool(
|
|
"force_unlock_songs"
|
|
):
|
|
# We will echo this below in the force unlock song section
|
|
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]))
|
|
|
|
# Appeal card unlocks
|
|
appealcard = Node.void("appealcard")
|
|
game.add_child(appealcard)
|
|
|
|
if not game_config.get_bool("force_unlock_cards"):
|
|
for card in achievements:
|
|
if card.type != "appealcard":
|
|
continue
|
|
|
|
info = Node.void("info")
|
|
appealcard.add_child(info)
|
|
info.add_child(Node.u32("id", card.id))
|
|
info.add_child(Node.u32("count", card.data.get_int("count")))
|
|
else:
|
|
catalog = self.data.local.game.get_items(self.game, self.version)
|
|
for unlock in catalog:
|
|
if unlock.type != "appealcard":
|
|
continue
|
|
info = Node.void("info")
|
|
appealcard.add_child(info)
|
|
info.add_child(Node.u32("id", unlock.id))
|
|
info.add_child(Node.u32("count", 0))
|
|
|
|
# Skill courses
|
|
skill = Node.void("skill")
|
|
game.add_child(skill)
|
|
course_all = Node.void("course_all")
|
|
skill.add_child(course_all)
|
|
|
|
for course in achievements:
|
|
if course.type != "course":
|
|
continue
|
|
|
|
course_id = course.id % 100
|
|
season_id = int(course.id / 100)
|
|
|
|
info = Node.void("d")
|
|
course_all.add_child(info)
|
|
info.add_child(Node.s16("crsid", course_id))
|
|
info.add_child(Node.s16("ct", course.data.get_int("clear_type")))
|
|
info.add_child(Node.s16("ar", course.data.get_int("achievement_rate")))
|
|
info.add_child(Node.s32("ssnid", season_id))
|
|
|
|
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 stuff
|
|
newprofile.replace_int("blaster_count", request.child_value("blaster_count"))
|
|
newprofile.replace_int("skill_name_id", request.child_value("skill_name_id"))
|
|
newprofile.replace_int_array(
|
|
"hidden_param", 20, request.child_value("hidden_param")
|
|
)
|
|
|
|
# Update user's unlock status if we aren't force unlocked
|
|
game_config = self.get_game_config()
|
|
if not game_config.get_bool("force_unlock_cards"):
|
|
for child in request.child("appealcard").children:
|
|
if child.name != "info":
|
|
continue
|
|
|
|
appealid = child.child_value("id")
|
|
count = child.child_value("count")
|
|
self.data.local.user.put_achievement(
|
|
self.game,
|
|
self.version,
|
|
userid,
|
|
appealid,
|
|
"appealcard",
|
|
{
|
|
"count": count,
|
|
},
|
|
)
|
|
|
|
if not game_config.get_bool("force_unlock_songs"):
|
|
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")
|
|
self.data.local.user.put_achievement(
|
|
self.game,
|
|
self.version,
|
|
userid,
|
|
item_id,
|
|
f"item_{item_type}",
|
|
{
|
|
"param": param,
|
|
},
|
|
)
|
|
|
|
# Grab last information.
|
|
lastdict = newprofile.get_dict("last")
|
|
lastdict.replace_int("headphone", request.child_value("headphone"))
|
|
lastdict.replace_int("hispeed", request.child_value("hispeed"))
|
|
lastdict.replace_int("appeal_id", request.child_value("appeal_id"))
|
|
lastdict.replace_int("comment_id", request.child_value("comment_id"))
|
|
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("gauge_option", request.child_value("gauge_option"))
|
|
|
|
# Save back last information gleaned from results
|
|
newprofile.replace_dict("last", lastdict)
|
|
|
|
# Keep track of play statistics
|
|
self.update_play_statistics(userid)
|
|
|
|
return newprofile
|