[Enhance] New skills

- For Arcaea 6.0.3
- Add support for `skill_chinatsu` and `skill_intruder`.
- Add support for the invasion toggle (toggle intruder's skill states).

Note that the invasion toggle in 4 states, which is different from the official server.
This commit is contained in:
Lost-MSth
2024-11-25 15:29:11 +08:00
parent a6c26dedfe
commit 3f5281582c
12 changed files with 251 additions and 45 deletions

View File

@@ -12,7 +12,7 @@ class Config:
SONG_FILE_HASH_PRE_CALCULATE = True SONG_FILE_HASH_PRE_CALCULATE = True
GAME_API_PREFIX = '/autumnequinox/33' # str | list[str] GAME_API_PREFIX = '/coldwind/35' # 6.0.0 '/fallingleaves/34' # str | list[str]
OLD_GAME_API_PREFIX = [] # str | list[str] OLD_GAME_API_PREFIX = [] # str | list[str]
ALLOW_APPVERSION = [] # list[str] ALLOW_APPVERSION = [] # list[str]
@@ -86,6 +86,9 @@ class Config:
BEST30_WEIGHT = 1 / 40 BEST30_WEIGHT = 1 / 40
RECENT10_WEIGHT = 1 / 40 RECENT10_WEIGHT = 1 / 40
INVASION_START_WEIGHT = 0.1
INVASION_HARD_WEIGHT = 0.1
MAX_FRIEND_COUNT = 50 MAX_FRIEND_COUNT = 50
WORLD_MAP_FOLDER_PATH = './database/map/' WORLD_MAP_FOLDER_PATH = './database/map/'

View File

@@ -1,7 +1,7 @@
from .config_manager import Config from .config_manager import Config
ARCAEA_SERVER_VERSION = 'v2.12.0.1' ARCAEA_SERVER_VERSION = 'v2.12.0.2'
ARCAEA_DATABASE_VERSION = 'v2.12.0.1' ARCAEA_DATABASE_VERSION = 'v2.12.0.2'
ARCAEA_LOG_DATBASE_VERSION = 'v1.1' ARCAEA_LOG_DATBASE_VERSION = 'v1.1'
@@ -11,6 +11,10 @@ class Constant:
MAX_STAMINA = 12 MAX_STAMINA = 12
# INSIGHT_STATES = [x for x in range(7)]
INSIGHT_TOGGLE_STATES = [3, 4, 5, 6]
# DEFAULT_INSIGHT_STATE = Config.DEFAULT_INSIGHT_STATE
STAMINA_RECOVER_TICK = 1800000 STAMINA_RECOVER_TICK = 1800000
FRAGSTAM_RECOVER_TICK = 23 * 3600 * 1000 FRAGSTAM_RECOVER_TICK = 23 * 3600 * 1000
@@ -40,6 +44,8 @@ class Constant:
BEST30_WEIGHT = Config.BEST30_WEIGHT BEST30_WEIGHT = Config.BEST30_WEIGHT
RECENT10_WEIGHT = Config.RECENT10_WEIGHT RECENT10_WEIGHT = Config.RECENT10_WEIGHT
INVASION_START_WEIGHT = Config.INVASION_START_WEIGHT
INVASION_HARD_WEIGHT = Config.INVASION_HARD_WEIGHT
WORLD_MAP_FOLDER_PATH = Config.WORLD_MAP_FOLDER_PATH WORLD_MAP_FOLDER_PATH = Config.WORLD_MAP_FOLDER_PATH
SONG_FILE_FOLDER_PATH = Config.SONG_FILE_FOLDER_PATH SONG_FILE_FOLDER_PATH = Config.SONG_FILE_FOLDER_PATH

View File

@@ -1,5 +1,6 @@
from base64 import b64encode from base64 import b64encode
from os import urandom from os import urandom
from random import choices
from time import time from time import time
from .bgtask import BGTask, logdb_execute from .bgtask import BGTask, logdb_execute
@@ -244,10 +245,14 @@ class UserPlay(UserScore):
self.course_play: 'CoursePlay' = None self.course_play: 'CoursePlay' = None
self.combo_interval_bonus: int = None # 不能给 None 以外的默认值 self.combo_interval_bonus: int = None # 不能给 None 以外的默认值
self.hp_interval_bonus: int = None # 不能给 None 以外的默认值
self.skill_cytusii_flag: str = None self.skill_cytusii_flag: str = None
self.skill_chinatsu_flag: str = None
self.highest_health: int = None self.highest_health: int = None
self.lowest_health: int = None self.lowest_health: int = None
self.invasion_flag: int = None # 1: invasion_start, 2: invasion_hard
def to_dict(self) -> dict: def to_dict(self) -> dict:
# 不能super # 不能super
if self.is_world_mode is None or self.course_play_state is None: if self.is_world_mode is None or self.course_play_state is None:
@@ -288,6 +293,9 @@ class UserPlay(UserScore):
return False return False
x = x + str(self.combo_interval_bonus) x = x + str(self.combo_interval_bonus)
if self.hp_interval_bonus is not None and self.hp_interval_bonus < 0:
return False
y = f'{self.user.user_id}{self.song_hash}' y = f'{self.user.user_id}{self.song_hash}'
checksum = md5(x+md5(y)) checksum = md5(x+md5(y))
@@ -326,16 +334,27 @@ class UserPlay(UserScore):
self.prog_boost_multiply = int(x[10]) self.prog_boost_multiply = int(x[10])
self.beyond_boost_gauge_usage = int(x[11]) self.beyond_boost_gauge_usage = int(x[11])
self.skill_cytusii_flag = x[12] self.skill_cytusii_flag = x[12]
self.skill_chinatsu_flag = x[13]
self.invasion_flag = x[14]
self.is_world_mode = True self.is_world_mode = True
self.course_play_state = -1 self.course_play_state = -1
def set_play_state_for_world(self, stamina_multiply: int = 1, fragment_multiply: int = 100, prog_boost_multiply: int = 0, beyond_boost_gauge_usage: int = 0, skill_cytusii_flag: str = None) -> None: def set_play_state_for_world(
self,
stamina_multiply: int = 1,
fragment_multiply: int = 100,
prog_boost_multiply: int = 0,
beyond_boost_gauge_usage: int = 0,
skill_cytusii_flag: str = None,
skill_chinatsu_flag: str = None
) -> None:
self.song_token = b64encode(urandom(64)).decode() self.song_token = b64encode(urandom(64)).decode()
self.stamina_multiply = int(stamina_multiply) self.stamina_multiply = int(stamina_multiply)
self.fragment_multiply = int(fragment_multiply) self.fragment_multiply = int(fragment_multiply)
self.prog_boost_multiply = int(prog_boost_multiply) self.prog_boost_multiply = int(prog_boost_multiply)
self.beyond_boost_gauge_usage = int(beyond_boost_gauge_usage) self.beyond_boost_gauge_usage = int(beyond_boost_gauge_usage)
self.skill_cytusii_flag = skill_cytusii_flag self.skill_cytusii_flag = skill_cytusii_flag
self.skill_chinatsu_flag = skill_chinatsu_flag
if self.prog_boost_multiply != 0 or self.beyond_boost_gauge_usage != 0: if self.prog_boost_multiply != 0 or self.beyond_boost_gauge_usage != 0:
self.c.execute('''select prog_boost, beyond_boost_gauge from user where user_id=:a''', { self.c.execute('''select prog_boost, beyond_boost_gauge from user where user_id=:a''', {
'a': self.user.user_id}) 'a': self.user.user_id})
@@ -346,10 +365,6 @@ class UserPlay(UserScore):
# 注意偷懒了没判断是否是beyond图 # 注意偷懒了没判断是否是beyond图
self.beyond_boost_gauge_usage = 0 self.beyond_boost_gauge_usage = 0
self.clear_play_state()
self.c.execute('''insert into songplay_token values(:t,:a,:b,:c,'',-1,0,0,:d,:e,:f,:g,:h)''', {
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty, 'd': self.stamina_multiply, 'e': self.fragment_multiply, 'f': self.prog_boost_multiply, 'g': self.beyond_boost_gauge_usage, 'h': self.skill_cytusii_flag, 't': self.song_token})
self.user.select_user_about_current_map() self.user.select_user_about_current_map()
self.user.current_map.select_map_info() self.user.current_map.select_map_info()
@@ -360,13 +375,23 @@ class UserPlay(UserScore):
self.user.select_user_about_character() self.user.select_user_about_character()
if not self.user.is_skill_sealed: if not self.user.is_skill_sealed:
self.user.character.select_character_info() self.user.character.select_character_info()
if self.user.character.skill_id_displayed == 'skill_fatalis': # invasion 扔骰子
_flag = choices([0, 1, 2], [
max(1 - Constant.INVASION_START_WEIGHT - Constant.INVASION_HARD_WEIGHT, 0), Constant.INVASION_START_WEIGHT, Constant.INVASION_HARD_WEIGHT])[0]
if self.user.is_insight_enabled and _flag != 0:
self.invasion_flag = _flag
elif self.user.character.skill_id_displayed == 'skill_fatalis':
# 特殊判断hikari fatalis的双倍体力消耗 # 特殊判断hikari fatalis的双倍体力消耗
self.user.stamina.stamina -= self.user.current_map.stamina_cost * \ self.user.stamina.stamina -= self.user.current_map.stamina_cost * \
self.stamina_multiply * 2 self.stamina_multiply * 2
self.user.stamina.update() self.user.stamina.update()
return None return None
self.clear_play_state()
self.c.execute('''insert into songplay_token values(:t,:a,:b,:c,'',-1,0,0,:d,:e,:f,:g,:h,:i,:j)''', {
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty, 'd': self.stamina_multiply, 'e': self.fragment_multiply, 'f': self.prog_boost_multiply, 'g': self.beyond_boost_gauge_usage, 'h': self.skill_cytusii_flag, 'i': self.skill_chinatsu_flag, 'j': self.invasion_flag, 't': self.song_token})
self.user.stamina.stamina -= self.user.current_map.stamina_cost * self.stamina_multiply self.user.stamina.stamina -= self.user.current_map.stamina_cost * self.stamina_multiply
self.user.stamina.update() self.user.stamina.update()
@@ -380,8 +405,8 @@ class UserPlay(UserScore):
self.course_play.score = 0 self.course_play.score = 0
self.course_play.clear_type = 3 # 设置为PM即最大值 self.course_play.clear_type = 3 # 设置为PM即最大值
self.c.execute('''insert into songplay_token values(?,?,?,?,?,?,?,?,1,100,0,0,"")''', (self.song_token, self.user.user_id, self.song.song_id, self.c.execute('''insert into songplay_token values(?,?,?,?,?,?,?,?,1,100,0,0,"","",0)''', (self.song_token, self.user.user_id, self.song.song_id,
self.song.difficulty, self.course_play.course_id, self.course_play_state, self.course_play.score, self.course_play.clear_type)) self.song.difficulty, self.course_play.course_id, self.course_play_state, self.course_play.score, self.course_play.clear_type))
self.user.select_user_about_stamina() self.user.select_user_about_stamina()
if use_course_skip_purchase: if use_course_skip_purchase:
x = ItemCore(self.c) x = ItemCore(self.c)

View File

@@ -326,6 +326,8 @@ class UserInfo(User):
self.current_map: 'Map' = None self.current_map: 'Map' = None
self.stamina: 'UserStamina' = None self.stamina: 'UserStamina' = None
self.insight_state: int = None
self.__cores: list = None self.__cores: list = None
self.__packs: list = None self.__packs: list = None
self.__singles: list = None self.__singles: list = None
@@ -336,6 +338,12 @@ class UserInfo(User):
self.curr_available_maps: list = None self.curr_available_maps: list = None
self.__course_banners: list = None self.__course_banners: list = None
@property
def is_insight_enabled(self) -> bool:
if self.insight_state is None:
self.select_user_one_column('insight_state', 4, int)
return self.insight_state == 3 or self.insight_state == 5
@property @property
def cores(self) -> list: def cores(self) -> list:
if self.__cores is None: if self.__cores is None:
@@ -547,6 +555,7 @@ class UserInfo(User):
# 'custom_banner': 'online_banner_2024_06', # 'custom_banner': 'online_banner_2024_06',
# 'subscription_multiplier': 114, # 'subscription_multiplier': 114,
# 'memory_boost_ticket': 5, # 'memory_boost_ticket': 5,
'insight_state': self.insight_state, # 0~2 不可选3 技能激活4 未激活5 激活可选6 未激活可选
} }
def from_list(self, x: list) -> 'UserInfo': def from_list(self, x: list) -> 'UserInfo':
@@ -591,6 +600,8 @@ class UserInfo(User):
self.mp_notification_enabled = x[37] == 1 self.mp_notification_enabled = x[37] == 1
self.insight_state = x[38]
return self return self
def select_user(self) -> None: def select_user(self) -> None:
@@ -795,6 +806,19 @@ class UserOnline(UserInfo):
self.c.execute('''update user set favorite_character = :a where user_id = :b''', self.c.execute('''update user set favorite_character = :a where user_id = :b''',
{'a': self.favorite_character.character_id, 'b': self.user_id}) {'a': self.favorite_character.character_id, 'b': self.user_id})
def toggle_invasion(self) -> None:
self.c.execute(
'''select insight_state from user where user_id = ?''', (self.user_id,))
x = self.c.fetchone()
if not x:
raise NoData('No user.', 108, -3)
self.insight_state = x[0]
rq = Constant.INSIGHT_TOGGLE_STATES
self.insight_state = rq[(rq.index(self.insight_state) + 1) % len(rq)]
self.c.execute(
'''update user set insight_state = ? where user_id = ?''', (self.insight_state, self.user_id))
class UserChanger(UserInfo, UserRegister): class UserChanger(UserInfo, UserRegister):

View File

@@ -4,7 +4,7 @@ from json import load
from random import randint from random import randint
from time import time from time import time
from .character import Character from .character import Character, UserCharacter
from .constant import Constant from .constant import Constant
from .error import InputError, MapLocked, NoData from .error import InputError, MapLocked, NoData
from .item import ItemFactory from .item import ItemFactory
@@ -133,6 +133,7 @@ class Map:
self.chain_info: dict = None self.chain_info: dict = None
# self.requires: list[dict] = None # self.requires: list[dict] = None
self.requires_any: 'list[dict]' = None
self.disable_over: bool = None self.disable_over: bool = None
self.new_law: str = None self.new_law: str = None
@@ -188,6 +189,8 @@ class Map:
r['disable_over'] = self.disable_over r['disable_over'] = self.disable_over
if self.new_law is not None and self.new_law != '': if self.new_law is not None and self.new_law != '':
r['new_law'] = self.new_law r['new_law'] = self.new_law
if self.requires_any:
r['requires_any'] = self.requires_any
return r return r
def from_dict(self, raw_dict: dict) -> 'Map': def from_dict(self, raw_dict: dict) -> 'Map':
@@ -216,6 +219,7 @@ class Map:
self.disable_over = raw_dict.get('disable_over') self.disable_over = raw_dict.get('disable_over')
self.new_law = raw_dict.get('new_law') self.new_law = raw_dict.get('new_law')
self.requires_any = raw_dict.get('requires_any')
return self return self
def select_map_info(self): def select_map_info(self):
@@ -474,7 +478,8 @@ class WorldSkillMixin:
'skill_ilith_ivy': self._skill_ilith_ivy, 'skill_ilith_ivy': self._skill_ilith_ivy,
'ilith_awakened_skill': self._ilith_awakened_skill, 'ilith_awakened_skill': self._ilith_awakened_skill,
'skill_hikari_vanessa': self._skill_hikari_vanessa, 'skill_hikari_vanessa': self._skill_hikari_vanessa,
'skill_mithra': self._skill_mithra 'skill_mithra': self._skill_mithra,
'skill_chinatsu': self._skill_chinatsu,
} }
if self.user_play.beyond_gauge == 0 and self.character_used.character_id == 35 and self.character_used.skill_id_displayed: if self.user_play.beyond_gauge == 0 and self.character_used.character_id == 35 and self.character_used.skill_id_displayed:
self._special_tempest() self._special_tempest()
@@ -492,6 +497,7 @@ class WorldSkillMixin:
'luna_uncap': self._luna_uncap, 'luna_uncap': self._luna_uncap,
'skill_kanae_uncap': self._skill_kanae_uncap, 'skill_kanae_uncap': self._skill_kanae_uncap,
'skill_eto_hoppe': self._skill_eto_hoppe, 'skill_eto_hoppe': self._skill_eto_hoppe,
'skill_intruder': self._skill_intruder,
} }
if self.character_used.skill_id_displayed in factory_dict: if self.character_used.skill_id_displayed in factory_dict:
factory_dict[self.character_used.skill_id_displayed]() factory_dict[self.character_used.skill_id_displayed]()
@@ -630,9 +636,11 @@ class WorldSkillMixin:
kanae 觉醒技能,保存世界模式 progress 并在下次结算 kanae 觉醒技能,保存世界模式 progress 并在下次结算
直接加减在 progress 最后 直接加减在 progress 最后
技能存储 base_progress * PROG / 50下一次消耗全部存储值无视技能和搭档但需要非技能隐藏状态 技能存储 base_progress * PROG / 50下一次消耗全部存储值无视技能和搭档但需要非技能隐藏状态
6.0 更新:需要体力消耗才存
''' '''
self.kanae_stored_progress = self.progress_normalized if self.user.current_map.stamina_cost > 0:
self.user.current_map.reclimb(self.final_progress) self.kanae_stored_progress = self.progress_normalized
self.user.current_map.reclimb(self.final_progress)
def _skill_eto_hoppe(self) -> None: def _skill_eto_hoppe(self) -> None:
''' '''
@@ -642,6 +650,26 @@ class WorldSkillMixin:
self.character_bonus_progress_normalized = self.progress_normalized self.character_bonus_progress_normalized = self.progress_normalized
self.user.current_map.reclimb(self.final_progress) self.user.current_map.reclimb(self.final_progress)
def _skill_chinatsu(self) -> None:
'''
chinatsu 技能hp 超过时提高搭档能力值
'''
_flag = self.user_play.skill_chinatsu_flag
if not self.user_play.hp_interval_bonus or not _flag:
return
x = _flag[:min(len(_flag), self.user_play.hp_interval_bonus)]
self.over_skill_increase = x.count('2') * 5
self.prog_skill_increase = x.count('1') * 5
def _skill_intruder(self) -> None:
'''
intruder 技能,夺舍后世界进度翻倍
'''
if self.user_play.invasion_flag:
self.character_bonus_progress_normalized = self.progress_normalized
self.user.current_map.reclimb(self.final_progress)
class BaseWorldPlay(WorldSkillMixin): class BaseWorldPlay(WorldSkillMixin):
''' '''
@@ -690,9 +718,13 @@ class BaseWorldPlay(WorldSkillMixin):
'world_mode_locked_end_ts': self.user.world_mode_locked_end_ts, 'world_mode_locked_end_ts': self.user.world_mode_locked_end_ts,
'beyond_boost_gauge': self.user.beyond_boost_gauge, 'beyond_boost_gauge': self.user.beyond_boost_gauge,
# 'wpaid': 'helloworld', # world play id ??? # 'wpaid': 'helloworld', # world play id ???
# progress_before_sub_boost 'progress_before_sub_boost': self.final_progress,
# progress_sub_boost_amount 'progress_sub_boost_amount': 0,
# subscription_multiply # 'subscription_multiply'
# lephon_final: bool dynamic map info
# lephon_active: bool dynamic map info
# 'steps_modified': False,
} }
if self.character_used.skill_id_displayed == 'skill_maya': if self.character_used.skill_id_displayed == 'skill_maya':
@@ -751,6 +783,11 @@ class BaseWorldPlay(WorldSkillMixin):
if self.user_play.beyond_gauge == 0 and self.user.kanae_stored_prog > 0: if self.user_play.beyond_gauge == 0 and self.user.kanae_stored_prog > 0:
# 实在不想拆开了,在这里判断一下,注意这段不会在 BeyondWorldPlay 中执行 # 实在不想拆开了,在这里判断一下,注意这段不会在 BeyondWorldPlay 中执行
self.kanae_added_progress = self.user.kanae_stored_prog self.kanae_added_progress = self.user.kanae_stored_prog
if self.user_play.invasion_flag: # not None and != 0
# 这里硬编码了搭档 id 72
self.character_used = UserCharacter(self.c, 72, self.user)
self.character_used.select_character_info()
else: else:
self.character_used.character_id = self.user.character.character_id self.character_used.character_id = self.user.character.character_id
self.character_used.level.level = self.user.character.level.level self.character_used.level.level = self.user.character.level.level
@@ -808,6 +845,7 @@ class WorldPlay(BaseWorldPlay):
def to_dict(self) -> dict: def to_dict(self) -> dict:
r = super().to_dict() r = super().to_dict()
# 基础进度加上搭档倍数 不带 character_bonus_progress 但是带 kanae 技能 # 基础进度加上搭档倍数 不带 character_bonus_progress 但是带 kanae 技能
r['progress_partial_after_stat'] = self.progress_normalized r['progress_partial_after_stat'] = self.progress_normalized
@@ -932,6 +970,7 @@ class BeyondWorldPlay(BaseWorldPlay):
r['char_stats']['over_skill_increase'] = self.over_skill_increase r['char_stats']['over_skill_increase'] = self.over_skill_increase
r["user_map"]["steps"] = len(self.user.current_map.steps_for_climbing) r["user_map"]["steps"] = len(self.user.current_map.steps_for_climbing)
r['affinity_multiply'] = self.affinity_multiplier r['affinity_multiply'] = self.affinity_multiplier
if self.user_play.beyond_boost_gauge_usage != 0: if self.user_play.beyond_boost_gauge_usage != 0:
r['beyond_boost_gauge_usage'] = self.user_play.beyond_boost_gauge_usage r['beyond_boost_gauge_usage'] = self.user_play.beyond_boost_gauge_usage

View File

@@ -1,45 +1,45 @@
class InitData: class InitData:
char = ['hikari', 'tairitsu', 'kou', 'sapphire', 'lethe', 'hikari&tairitsu(reunion)', 'Tairitsu(Axium)', 'Tairitsu(Grievous Lady)', 'stella', 'Hikari & Fisica', 'ilith', 'eto', 'luna', 'shirabe', 'Hikari(Zero)', 'Hikari(Fracture)', 'Hikari(Summer)', 'Tairitsu(Summer)', 'Tairitsu & Trin', char = ['hikari', 'tairitsu', 'kou', 'sapphire', 'lethe', 'hikari&tairitsu(reunion)', 'Tairitsu(Axium)', 'Tairitsu(Grievous Lady)', 'stella', 'Hikari & Fisica', 'ilith', 'eto', 'luna', 'shirabe', 'Hikari(Zero)', 'Hikari(Fracture)', 'Hikari(Summer)', 'Tairitsu(Summer)', 'Tairitsu & Trin',
'ayu', 'Eto & Luna', 'yume', 'Seine & Hikari', 'saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'haruna', 'nono', 'MTA-XXX', 'MDA-21', 'kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'sia', 'DORO*C', 'Tairitsu(Tempest)', 'brillante', 'Ilith(Summer)', 'etude', 'Alice & Tenniel', 'Luna & Mia', 'areus', 'seele', 'isabelle', 'mir', 'lagrange', 'linka', 'nami', 'Saya & Elizabeth', 'lily', 'kanae(midsummer)', 'alice&tenniel(minuet)', 'tairitsu(elegy)', 'marija', 'vita', 'hikari(fatalis)', 'saki', 'setsuna', 'amane', 'kou(winter)', 'lagrange(aria)', 'lethe(apophenia)', 'shama(UNiVERSE)', 'milk(UNiVERSE)', 'shikoku', 'mika yurisaki', 'Mithra Tercera', 'Toa Kozukata', 'Nami(Twilight)', 'Ilith & Ivy', 'Hikari & Vanessa', 'Maya', 'Insight(Ascendant - 8th Seeker)', 'Luin', 'Vita(Cadenza)', 'Ai-chan', 'Luna & Ilot', 'Eto & Hoppe'] 'ayu', 'Eto & Luna', 'yume', 'Seine & Hikari', 'saya', 'Tairitsu & Chuni Penguin', 'Chuni Penguin', 'haruna', 'nono', 'MTA-XXX', 'MDA-21', 'kanae', 'Hikari(Fantasia)', 'Tairitsu(Sonata)', 'sia', 'DORO*C', 'Tairitsu(Tempest)', 'brillante', 'Ilith(Summer)', 'etude', 'Alice & Tenniel', 'Luna & Mia', 'areus', 'seele', 'isabelle', 'mir', 'lagrange', 'linka', 'nami', 'Saya & Elizabeth', 'lily', 'kanae(midsummer)', 'alice&tenniel(minuet)', 'tairitsu(elegy)', 'marija', 'vita', 'hikari(fatalis)', 'saki', 'setsuna', 'amane', 'kou(winter)', 'lagrange(aria)', 'lethe(apophenia)', 'shama(UNiVERSE)', 'milk(UNiVERSE)', 'shikoku', 'mika yurisaki', 'Mithra Tercera', 'Toa Kozukata', 'Nami(Twilight)', 'Ilith & Ivy', 'Hikari & Vanessa', 'Maya', 'Insight(Ascendant - 8th Seeker)', 'Luin', 'Vita(Cadenza)', 'Ai-chan', 'Luna & Ilot', 'Eto & Hoppe', 'Forlorn(Ascendant - 6th Seeker)', 'Chinatsu', 'Tsumugi']
skill_id = ['gauge_easy', '', '', '', 'note_mirror', 'skill_reunion', '', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere', skill_id = ['gauge_easy', '', '', '', 'note_mirror', 'skill_reunion', '', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere',
'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', '', '', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', '', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange', 'gauge_safe_10', 'frags_nami', 'skill_elizabeth', 'skill_lily', 'skill_kanae_midsummer', '', '', 'visual_ghost_skynotes', 'skill_vita', 'skill_fatalis', 'frags_ongeki_slash', 'frags_ongeki_hard', 'skill_amane', 'skill_kou_winter', '', 'gauge_hard|note_mirror', 'skill_shama', 'skill_milk', 'skill_shikoku', 'skill_mika', 'skill_mithra', 'skill_toa', 'skill_nami_twilight', 'skill_ilith_ivy', 'skill_hikari_vanessa', 'skill_maya', 'skill_intruder', 'skill_luin', '', 'skill_aichan', 'skill_luna_ilot', 'skill_eto_hoppe'] 'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', '', '', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', '', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange', 'gauge_safe_10', 'frags_nami', 'skill_elizabeth', 'skill_lily', 'skill_kanae_midsummer', '', '', 'visual_ghost_skynotes', 'skill_vita', 'skill_fatalis', 'frags_ongeki_slash', 'frags_ongeki_hard', 'skill_amane', 'skill_kou_winter', '', 'gauge_hard|note_mirror', 'skill_shama', 'skill_milk', 'skill_shikoku', 'skill_mika', 'skill_mithra', 'skill_toa', 'skill_nami_twilight', 'skill_ilith_ivy', 'skill_hikari_vanessa', 'skill_maya', 'skill_intruder', 'skill_luin', '', 'skill_aichan', 'skill_luna_ilot', 'skill_eto_hoppe', 'skill_nell', 'skill_chinatsu', 'skill_tsumugi']
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', 'ilith_awakened_skill', 'eto_uncap', 'luna_uncap', 'shirabe_entry_fee', skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', 'ilith_awakened_skill', 'eto_uncap', 'luna_uncap', 'shirabe_entry_fee',
'', '', '', '', '', 'ayu_uncap', '', 'frags_yume', '', 'skill_saya_uncap', '', '', '', '', '', '', 'skill_kanae_uncap', '', '', '', 'skill_doroc_uncap', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'skill_luin_uncap', '', '', '', ''] '', '', '', '', '', 'ayu_uncap', '', 'frags_yume', '', 'skill_saya_uncap', '', '', '', '', '', '', 'skill_kanae_uncap', '', '', '', 'skill_doroc_uncap', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'skill_luin_uncap', '', '', '', '', '', '', '']
skill_unlock_level = [0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, skill_unlock_level = [0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0,
0, 0, 0, 8, 0, 14, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 0, 0, 0, 8, 0, 14, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
frag1 = [55, 55, 60, 50, 47, 79, 47, 57, 41, 22, 50, 54, 60, 56, 78, 42, 41, 61, 52, 50, 52, 32, frag1 = [55, 55, 60, 50, 47, 79, 47, 57, 41, 22, 50, 54, 60, 56, 78, 42, 41, 61, 52, 50, 52, 32,
42, 55, 45, 58, 43, 0.5, 68, 50, 62, 45, 45, 52, 44, 27, 59, 0, 45, 50, 50, 47, 47, 61, 43, 42, 38, 25, 58, 50, 61, 45, 45, 38, 34, 27, 18, 56, 47, 30, 45, 57, 56, 47, 33, 26, 29, 66, 40, 33, 51, 27, 50, 60, 45, 50, 38, 22] 42, 55, 45, 58, 43, 0.5, 68, 50, 62, 45, 45, 52, 44, 27, 59, 0, 45, 50, 50, 47, 47, 61, 43, 42, 38, 25, 58, 50, 61, 45, 45, 38, 34, 27, 18, 56, 47, 30, 45, 57, 56, 47, 33, 26, 29, 66, 40, 33, 51, 27, 50, 60, 45, 50, 38, 22, 63, 37, 23]
prog1 = [35, 55, 47, 50, 60, 70, 60, 70, 58, 45, 70, 45, 42, 46, 61, 67, 49, 44, 28, 45, 24, 46, 52, prog1 = [35, 55, 47, 50, 60, 70, 60, 70, 58, 45, 70, 45, 42, 46, 61, 67, 49, 44, 28, 45, 24, 46, 52,
59, 62, 33, 58, 25, 63, 69, 50, 45, 45, 51, 34, 70, 62, 70, 45, 32, 32, 61, 47, 47, 37, 42, 50, 50, 45, 41, 61, 45, 45, 58, 50, 130, 18, 57, 55, 50, 45, 70, 37.5, 29, 44, 26, 26, 35, 40, 33, 58, 31, 50, 50, 45, 41, 12, 31] 59, 62, 33, 58, 25, 63, 69, 50, 45, 45, 51, 34, 70, 62, 70, 45, 32, 32, 61, 47, 47, 37, 42, 50, 50, 45, 41, 61, 45, 45, 58, 50, 130, 18, 57, 55, 50, 45, 70, 37.5, 29, 44, 26, 26, 35, 40, 33, 58, 31, 40, 50, 45, 41, 12, 31, 72, 40, 16]
overdrive1 = [35, 55, 25, 50, 47, 70, 72, 57, 41, 7, 10, 32, 65, 31, 61, 53, 31, 47, 38, 12, 39, 18, overdrive1 = [35, 55, 25, 50, 47, 70, 72, 57, 41, 7, 10, 32, 65, 31, 61, 53, 31, 47, 38, 12, 39, 18,
48, 65, 45, 55, 44, 25, 46, 44, 33, 45, 45, 37, 25, 27, 50, 20, 45, 63, 21, 47, 61, 47, 65, 80, 38, 30, 49, 15, 34, 45, 45, 38, 67, 120, 44, 33, 55, 50, 45, 57, 31, 29, 65, 26, 29, 42.5, 40, 33, 58, 31, 50, 34, 45, 41, 12, 19] 48, 65, 45, 55, 44, 25, 46, 44, 33, 45, 45, 37, 25, 27, 50, 20, 45, 63, 21, 47, 61, 47, 65, 80, 38, 30, 49, 15, 34, 45, 45, 38, 67, 120, 44, 33, 55, 50, 45, 57, 31, 29, 65, 26, 29, 42.5, 40, 33, 58, 31, 35, 34, 45, 41, 12, 19, 38, 40, 26]
frag20 = [78, 80, 90, 75, 70, 79, 70, 79, 65, 40, 50, 80, 90, 82, 0, 61, 67, 92, 85, 50, 86, 52, frag20 = [78, 80, 90, 75, 70, 79, 70, 79, 65, 40, 50, 80, 90, 82, 0, 61, 67, 92, 85, 50, 86, 52,
65, 85, 67, 88, 64, 0.5, 95, 70, 95, 50, 80, 87, 71, 50, 85, 0, 80, 75, 50, 70, 70, 90, 65, 80, 61, 50, 68, 60, 90, 67, 50, 60, 51, 50, 35, 85, 47, 50, 75, 80, 90, 80, 50, 51, 54, 100, 50, 58, 51, 40, 50, 70, 50, 61.6, 48, 37] 65, 85, 67, 88, 64, 0.5, 95, 70, 95, 50, 80, 87, 71, 50, 85, 0, 80, 75, 50, 70, 70, 90, 65, 80, 61, 50, 68, 60, 90, 67, 50, 60, 51, 50, 35, 85, 47, 50, 75, 80, 90, 80, 50, 51, 54, 100, 50, 58, 51, 40, 115, 70, 50, 61.6, 48, 37, 90, 60, 50]
prog20 = [61, 80, 70, 75, 90, 70, 90, 102, 84, 78, 105, 67, 63, 68, 0, 99, 80, 66, 46, 83, 40, 73, prog20 = [61, 80, 70, 75, 90, 70, 90, 102, 84, 78, 105, 67, 63, 68, 0, 99, 80, 66, 46, 83, 40, 73,
80, 90, 93, 50, 86, 78, 89, 98, 75, 80, 50, 64, 55, 100, 90, 110, 80, 50, 74, 90, 70, 70, 56, 80, 79, 55, 65, 59, 90, 50, 90, 90, 75, 210, 35, 86, 92, 80, 75, 100, 60, 50, 68, 51, 50, 53, 85, 58, 96, 47, 50, 80, 67, 41, 55, 50] 80, 90, 93, 50, 86, 78, 89, 98, 75, 80, 50, 64, 55, 100, 90, 110, 80, 50, 74, 90, 70, 70, 56, 80, 79, 55, 65, 59, 90, 50, 90, 90, 75, 210, 35, 86, 92, 80, 75, 100, 60, 50, 68, 51, 50, 53, 85, 58, 96, 47, 80, 80, 67, 41, 55, 50, 103, 66, 35]
overdrive20 = [61, 80, 47, 75, 70, 70, 95, 79, 65, 31, 50, 59, 90, 58, 0, 78, 50, 70, 62, 49, 64, overdrive20 = [61, 80, 47, 75, 70, 70, 95, 79, 65, 31, 50, 59, 90, 58, 0, 78, 50, 70, 62, 49, 64,
46, 73, 95, 67, 84, 70, 78, 69, 70, 50, 80, 80, 63, 25, 50, 72, 55, 50, 95, 55, 70, 90, 70, 99, 80, 61, 40, 69, 62, 51, 90, 67, 60, 100, 200, 85, 50, 92, 50, 75, 80, 49.5, 50, 100, 51, 54, 65.5, 59.5, 58, 96, 47, 50, 54, 90, 41, 34, 30] 46, 73, 95, 67, 84, 70, 78, 69, 70, 50, 80, 80, 63, 25, 50, 72, 55, 50, 95, 55, 70, 90, 70, 99, 80, 61, 40, 69, 62, 51, 90, 67, 60, 100, 200, 85, 50, 92, 50, 75, 80, 49.5, 50, 100, 51, 54, 65.5, 59.5, 58, 96, 47, 75, 54, 90, 41, 34, 30, 55, 66, 55]
frag30 = [88, 90, 100, 75, 80, 89, 70, 79, 65, 40, 50, 90, 100, 92, 0, 61, 67, 92, 85, 50, 86, 62, frag30 = [88, 90, 100, 75, 80, 89, 70, 79, 65, 40, 50, 90, 100, 92, 0, 61, 67, 92, 85, 50, 86, 62,
65, 95, 67, 88, 74, 0.5, 105, 80, 105, 50, 80, 87, 81, 50, 95, 0, 80, 75, 50, 70, 80, 100, 65, 80, 61, 50, 68, 60, 90, 67, 50, 60, 51, 50, 35, 85, 47, 50, 75, 80, 90, 80, 50, 51, 64, 100, 50, 58, 51, 40, 50, 80, 50, 61.6, 48, 37] 65, 95, 67, 88, 74, 0.5, 105, 80, 105, 50, 80, 87, 81, 50, 95, 0, 80, 75, 50, 70, 80, 100, 65, 80, 61, 50, 68, 60, 90, 67, 50, 60, 51, 50, 35, 85, 47, 50, 75, 80, 90, 80, 50, 51, 64, 100, 50, 58, 51, 40, 115, 80, 50, 61.6, 48, 37, 90, 60, 50]
prog30 = [71, 90, 80, 75, 100, 80, 90, 102, 84, 78, 110, 77, 73, 78, 0, 99, 80, 66, 46, 93, 40, 83, prog30 = [71, 90, 80, 75, 100, 80, 90, 102, 84, 78, 110, 77, 73, 78, 0, 99, 80, 66, 46, 93, 40, 83,
80, 100, 93, 50, 96, 88, 99, 108, 85, 80, 50, 64, 65, 100, 100, 110, 80, 50, 74, 90, 80, 80, 56, 80, 79, 55, 65, 59, 90, 50, 90, 90, 75, 210, 35, 86, 92, 80, 75, 100, 60, 50, 68, 51, 60, 53, 85, 58, 96, 47, 50, 90, 67, 41, 55, 50] 80, 100, 93, 50, 96, 88, 99, 108, 85, 80, 50, 64, 65, 100, 100, 110, 80, 50, 74, 90, 80, 80, 56, 80, 79, 55, 65, 59, 90, 50, 90, 90, 75, 210, 35, 86, 92, 80, 75, 100, 60, 50, 68, 51, 60, 53, 85, 58, 96, 47, 80, 90, 67, 41, 55, 50, 103, 66, 35]
overdrive30 = [71, 90, 57, 75, 80, 80, 95, 79, 65, 31, 50, 69, 100, 68, 0, 78, 50, 70, 62, 59, 64, overdrive30 = [71, 90, 57, 75, 80, 80, 95, 79, 65, 31, 50, 69, 100, 68, 0, 78, 50, 70, 62, 59, 64,
56, 73, 105, 67, 84, 80, 88, 79, 80, 60, 80, 80, 63, 35, 50, 82, 55, 50, 95, 55, 70, 100, 80, 99, 80, 61, 40, 69, 62, 51, 90, 67, 60, 100, 200, 85, 50, 92, 50, 75, 80, 49.5, 50, 100, 51, 64, 65.5, 59.5, 58, 96, 47, 50, 64, 90, 41, 34, 30] 56, 73, 105, 67, 84, 80, 88, 79, 80, 60, 80, 80, 63, 35, 50, 82, 55, 50, 95, 55, 70, 100, 80, 99, 80, 61, 40, 69, 62, 51, 90, 67, 60, 100, 200, 85, 50, 92, 50, 75, 80, 49.5, 50, 100, 51, 64, 65.5, 59.5, 58, 96, 47, 75, 64, 90, 41, 34, 30, 55, 66, 55]
char_type = [1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0, 2, 3, 1, 0, 0, 0, 1, char_type = [1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 2, 0, 0, 0, 2, 3, 1, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 2, 2, 0, 0, 2, 0, 0, 2, 0, 2, 2, 1, 0, 2, 0, 0, 2, 0, 0, 0, 0] 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 2, 2, 0, 0, 2, 0, 0, 2, 0, 2, 2, 1, 0, 2, 0, 4, 2, 0, 0, 0, 0, 4, 0, 0]
char_core = { char_core = {
0: [{'core_id': 'core_hollow', 'amount': 25}, {'core_id': 'core_desolate', 'amount': 5}], 0: [{'core_id': 'core_hollow', 'amount': 25}, {'core_id': 'core_desolate', 'amount': 5}],
@@ -71,7 +71,7 @@ class InitData:
'core_ambivalent', 'core_scarlet', 'core_groove', 'core_generic', 'core_binary', 'core_colorful', 'core_course_skip_purchase', 'core_umbral', 'core_wacca', 'core_sunset', 'core_tanoc', 'core_serene'] 'core_ambivalent', 'core_scarlet', 'core_groove', 'core_generic', 'core_binary', 'core_colorful', 'core_course_skip_purchase', 'core_umbral', 'core_wacca', 'core_sunset', 'core_tanoc', 'core_serene']
world_songs = ["babaroque", "shadesoflight", "kanagawa", "lucifer", "anokumene", "ignotus", "rabbitintheblackroom", "qualia", "redandblue", "bookmaker", "darakunosono", "espebranch", "blacklotus", "givemeanightmare", "vividtheory", "onefr", "gekka", "vexaria3", "infinityheaven3", "fairytale3", "goodtek3", "suomi", "rugie", "faintlight", "harutopia", "goodtek", "dreaminattraction", "syro", "diode", "freefall", "grimheart", "blaster", world_songs = ["babaroque", "shadesoflight", "kanagawa", "lucifer", "anokumene", "ignotus", "rabbitintheblackroom", "qualia", "redandblue", "bookmaker", "darakunosono", "espebranch", "blacklotus", "givemeanightmare", "vividtheory", "onefr", "gekka", "vexaria3", "infinityheaven3", "fairytale3", "goodtek3", "suomi", "rugie", "faintlight", "harutopia", "goodtek", "dreaminattraction", "syro", "diode", "freefall", "grimheart", "blaster",
"cyberneciacatharsis", "monochromeprincess", "revixy", "vector", "supernova", "nhelv", "purgatorium3", "dement3", "crossover", "guardina", "axiumcrisis", "worldvanquisher", "sheriruth", "pragmatism", "gloryroad", "etherstrike", "corpssansorganes", "lostdesire", "blrink", "essenceoftwilight", "lapis", "solitarydream", "lumia3", "purpleverse", "moonheart3", "glow", "enchantedlove", "take", "lifeispiano", "vandalism", "nexttoyou3", "lostcivilization3", "turbocharger", "bookmaker3", "laqryma3", "kyogenkigo", "hivemind", "seclusion", "quonwacca3", "bluecomet", "energysynergymatrix", "gengaozo", "lastendconductor3", "antithese3", "qualia3", "kanagawa3", "heavensdoor3", "pragmatism3", "nulctrl", "avril", "ddd", "merlin3", "omakeno3", "nekonote", "sanskia", 'altair', 'mukishitsu', 'trapcrow', 'redandblue3', 'ignotus3', 'singularity3', 'dropdead3', 'arcahv', 'freefall3', 'partyvinyl3', 'tsukinimurakumo', 'mantis', 'worldfragments', 'astrawalkthrough', 'chronicle', 'trappola3', 'letsrock', 'shadesoflight3', 'teriqma3', 'impact3', 'lostemotion', 'gimmick', 'lawlesspoint', 'hybris', 'ultimatetaste', 'rgb', 'matenrou', 'dynitikos', 'amekagura', 'fantasy', 'aloneandlorn', 'felys', 'onandon', 'hotarubinoyuki', 'oblivia3', 'libertas3', 'einherjar3', 'purpleverse3', 'viciousheroism3', 'inkarusi3', 'cyberneciacatharsis3', 'alephzero', 'hellohell', 'ichirin', 'awakeninruins', 'morningloom', 'lethalvoltage', 'leaveallbehind', 'desive', 'oldschoolsalvage', 'distortionhuman', 'epitaxy', 'hailstone', 'furetemitai', 'prayer'] "cyberneciacatharsis", "monochromeprincess", "revixy", "vector", "supernova", "nhelv", "purgatorium3", "dement3", "crossover", "guardina", "axiumcrisis", "worldvanquisher", "sheriruth", "pragmatism", "gloryroad", "etherstrike", "corpssansorganes", "lostdesire", "blrink", "essenceoftwilight", "lapis", "solitarydream", "lumia3", "purpleverse", "moonheart3", "glow", "enchantedlove", "take", "lifeispiano", "vandalism", "nexttoyou3", "lostcivilization3", "turbocharger", "bookmaker3", "laqryma3", "kyogenkigo", "hivemind", "seclusion", "quonwacca3", "bluecomet", "energysynergymatrix", "gengaozo", "lastendconductor3", "antithese3", "qualia3", "kanagawa3", "heavensdoor3", "pragmatism3", "nulctrl", "avril", "ddd", "merlin3", "omakeno3", "nekonote", "sanskia", 'altair', 'mukishitsu', 'trapcrow', 'redandblue3', 'ignotus3', 'singularity3', 'dropdead3', 'arcahv', 'freefall3', 'partyvinyl3', 'tsukinimurakumo', 'mantis', 'worldfragments', 'astrawalkthrough', 'chronicle', 'trappola3', 'letsrock', 'shadesoflight3', 'teriqma3', 'impact3', 'lostemotion', 'gimmick', 'lawlesspoint', 'hybris', 'ultimatetaste', 'rgb', 'matenrou', 'dynitikos', 'amekagura', 'fantasy', 'aloneandlorn', 'felys', 'onandon', 'hotarubinoyuki', 'oblivia3', 'libertas3', 'einherjar3', 'purpleverse3', 'viciousheroism3', 'inkarusi3', 'cyberneciacatharsis3', 'alephzero', 'hellohell', 'ichirin', 'awakeninruins', 'morningloom', 'lethalvoltage', 'leaveallbehind', 'desive', 'oldschoolsalvage', 'distortionhuman', 'epitaxy', 'hailstone', 'furetemitai', 'prayer', 'astralexe']
world_unlocks = ["scenery_chap1", "scenery_chap2", world_unlocks = ["scenery_chap1", "scenery_chap2",
"scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6", "scenery_chap7", "scenery_beyond"] "scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6", "scenery_chap7", "scenery_beyond"]

View File

@@ -445,5 +445,50 @@
"core_generic_20", "core_generic_20",
"course_banner_11" "course_banner_11"
] ]
},
{
"course_id": "6.0-dan-12",
"style": 12,
"songs": [
{
"flag_as_hidden": true,
"difficulty": 2,
"id": "abstrusedilemma"
},
{
"flag_as_hidden": true,
"difficulty": 3,
"id": "worldender"
},
{
"flag_as_hidden": true,
"difficulty": 4,
"id": "alterego"
},
{
"flag_as_hidden": true,
"difficulty": 3,
"id": "designant"
}
],
"gauge_requirement": "default",
"requirements": [
{
"value": "4.0-dan-11",
"type": "course"
}
],
"flag_as_hidden_when_requirements_not_met": true,
"dan_name": "Phase 12",
"course_name": "侵蚀万物的色彩",
"can_start": true,
"is_completed": false,
"high_score": 0,
"best_clear_type": -1,
"rewards": [
"fragment2000",
"core_generic_20",
"course_banner_12"
]
} }
] ]

View File

@@ -862,5 +862,41 @@
], ],
"orig_price": 500, "orig_price": 500,
"price": 500 "price": 500
},
{
"name": "ongeki_append_2",
"items": [
{
"type": "pack",
"id": "ongeki_append_2",
"is_available": true
},
{
"type": "core",
"amount": 4,
"id": "core_generic",
"is_available": true
}
],
"orig_price": 400,
"price": 400
},
{
"name": "lephon",
"items": [
{
"type": "pack",
"id": "lephon",
"is_available": true
},
{
"type": "core",
"amount": 5,
"id": "core_generic",
"is_available": true
}
],
"orig_price": 500,
"price": 500
} }
] ]

View File

@@ -36,7 +36,8 @@ stamina int,
world_mode_locked_end_ts int, world_mode_locked_end_ts int,
beyond_boost_gauge real default 0, beyond_boost_gauge real default 0,
kanae_stored_prog real default 0, kanae_stored_prog real default 0,
mp_notification_enabled int default 1 mp_notification_enabled int default 1,
insight_state default 4 -- 这里写 4 是为了避免不能切换状态和无故被侵入
); );
create table if not exists login(access_token text, create table if not exists login(access_token text,
user_id int, user_id int,
@@ -145,7 +146,9 @@ stamina_multiply int,
fragment_multiply int, fragment_multiply int,
prog_boost_multiply int, prog_boost_multiply int,
beyond_boost_gauge_usage int, beyond_boost_gauge_usage int,
skill_cytusii_flag text skill_cytusii_flag text,
skill_chinatsu_flag text,
invasion_flag int
); );
create table if not exists item(item_id text, create table if not exists item(item_id text,
type text, type text,

View File

@@ -29,11 +29,12 @@ def score_token_world(user_id):
d = request.args.get d = request.args.get
stamina_multiply = int(d('stamina_multiply', 1)) stamina_multiply = d('stamina_multiply', 1, type=int)
fragment_multiply = int(d('fragment_multiply', 100)) fragment_multiply = d('fragment_multiply', 100, type=int)
prog_boost_multiply = int(d('prog_boost_multiply', 0)) prog_boost_multiply = d('prog_boost_multiply', 0, type=int)
beyond_boost_gauge_use = int(d('beyond_boost_gauge_use', 0)) beyond_boost_gauge_use = d('beyond_boost_gauge_use', 0, type=int)
skill_cytusii_flag = None skill_cytusii_flag = None
skill_chinatsu_flag = None
skill_id = d('skill_id') skill_id = d('skill_id')
if (skill_id == 'skill_ilith_ivy' or skill_id == 'skill_hikari_vanessa') and d('is_skill_sealed') == 'false': if (skill_id == 'skill_ilith_ivy' or skill_id == 'skill_hikari_vanessa') and d('is_skill_sealed') == 'false':
@@ -41,23 +42,34 @@ def score_token_world(user_id):
# TODO: 需要重构整个 user_play世界模式 / 课题模式,所以现在临时 work 一下 # TODO: 需要重构整个 user_play世界模式 / 课题模式,所以现在临时 work 一下
skill_cytusii_flag = ''.join([str(randint(0, 2)) for _ in range(5)]) skill_cytusii_flag = ''.join([str(randint(0, 2)) for _ in range(5)])
if skill_id == 'skill_chinatsu' and d('is_skill_sealed') == 'false':
skill_chinatsu_flag = ''.join([str(randint(0, 2)) for _ in range(7)])
skill_flag = skill_cytusii_flag or skill_chinatsu_flag
with Connect() as c: with Connect() as c:
x = UserPlay(c, UserOnline(c, user_id)) x = UserPlay(c, UserOnline(c, user_id))
x.song.set_chart(request.args['song_id'], int( x.song.set_chart(d('song_id'), d('difficulty', type=int))
request.args['difficulty']))
x.set_play_state_for_world( x.set_play_state_for_world(
stamina_multiply, fragment_multiply, prog_boost_multiply, beyond_boost_gauge_use, skill_cytusii_flag) stamina_multiply, fragment_multiply, prog_boost_multiply, beyond_boost_gauge_use, skill_cytusii_flag, skill_chinatsu_flag)
r = { r = {
"stamina": x.user.stamina.stamina, "stamina": x.user.stamina.stamina,
"max_stamina_ts": x.user.stamina.max_stamina_ts, "max_stamina_ts": x.user.stamina.max_stamina_ts,
"token": x.song_token, "token": x.song_token,
'play_parameters': {},
} }
if skill_cytusii_flag and skill_id: if skill_flag and skill_id:
r['play_parameters'] = { r['play_parameters'] = {
skill_id: list( skill_id: list(
map(lambda x: Constant.WORLD_VALUE_NAME_ENUM[int(x)], skill_cytusii_flag)) map(lambda x: Constant.WORLD_VALUE_NAME_ENUM[int(x)], skill_flag)),
} }
if x.invasion_flag == 1:
r['play_parameters']['invasion_start'] = True
elif x.invasion_flag == 2:
r['play_parameters']['invasion_hard'] = True
return success_return(r) return success_return(r)
@@ -115,11 +127,14 @@ def song_score_post(user_id):
x.submission_hash = request.form['submission_hash'] x.submission_hash = request.form['submission_hash']
if 'combo_interval_bonus' in request.form: if 'combo_interval_bonus' in request.form:
x.combo_interval_bonus = int(request.form['combo_interval_bonus']) x.combo_interval_bonus = int(request.form['combo_interval_bonus'])
if 'hp_interval_bonus' in request.form:
x.hp_interval_bonus = int(request.form['hp_interval_bonus'])
x.highest_health = request.form.get("highest_health", type=int) x.highest_health = request.form.get("highest_health", type=int)
x.lowest_health = request.form.get("lowest_health", type=int) x.lowest_health = request.form.get("lowest_health", type=int)
if not x.is_valid: if not x.is_valid:
raise InputError('Invalid score.', 107) raise InputError('Invalid score.', 107)
x.upload_score() x.upload_score()
# room_code???
return success_return(x.to_dict()) return success_return(x.to_dict())

View File

@@ -50,6 +50,16 @@ def user_me(user_id):
return success_return(UserOnline(c, user_id).to_dict()) return success_return(UserOnline(c, user_id).to_dict())
@bp.route('/me/toggle_invasion', methods=['POST']) # insight skill
@auth_required(request)
@arc_try
def toggle_invasion(user_id):
with Connect() as c:
user = UserOnline(c, user_id)
user.toggle_invasion()
return success_return({'user_id': user.user_id, 'insight_state': user.insight_state})
@bp.route('/me/character', methods=['POST']) # 角色切换 @bp.route('/me/character', methods=['POST']) # 角色切换
@auth_required(request) @auth_required(request)
@arc_try @arc_try

View File

@@ -443,7 +443,7 @@ def all_character():
def change_character(): def change_character():
# 修改角色数据 # 修改角色数据
skill_ids = ['No_skill', 'gauge_easy', 'note_mirror', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere', skill_ids = ['No_skill', 'gauge_easy', 'note_mirror', 'gauge_hard', 'frag_plus_10_pack_stellights', 'gauge_easy|frag_plus_15_pst&prs', 'gauge_hard|fail_frag_minus_100', 'frag_plus_5_side_light', 'visual_hide_hp', 'frag_plus_5_side_conflict', 'challenge_fullcombo_0gauge', 'gauge_overflow', 'gauge_easy|note_mirror', 'note_mirror', 'visual_tomato_pack_tonesphere',
'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', 'frags_kou', 'visual_ink', 'shirabe_entry_fee', 'frags_yume', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange', 'gauge_safe_10', 'frags_nami', 'skill_elizabeth', 'skill_lily', 'skill_kanae_midsummer', 'eto_uncap', 'luna_uncap', 'frags_preferred_song', 'visual_ghost_skynotes', 'ayu_uncap', 'skill_vita', 'skill_fatalis', 'skill_reunion', 'frags_ongeki_slash', 'frags_ongeki_hard', 'skill_amane', 'skill_kou_winter', 'gauge_hard|note_mirror', 'skill_shama', 'skill_milk', 'skill_shikoku', 'skill_mika', 'ilith_awakened_skill', 'skill_mithra', 'skill_toa', 'skill_nami_twilight', 'skill_ilith_ivy', 'skill_hikari_vanessa', 'skill_maya', 'skill_luin', 'skill_luin_uncap', 'skill_kanae_uncap', 'skill_doroc_uncap', 'skill_saya_uncap', 'skill_luna_ilot', 'skill_eto_hoppe', 'skill_aichan'] 'frag_rng_ayu', 'gaugestart_30|gaugegain_70', 'combo_100-frag_1', 'audio_gcemptyhit_pack_groovecoaster', 'gauge_saya', 'gauge_chuni', 'kantandeshou', 'gauge_haruna', 'frags_nono', 'gauge_pandora', 'gauge_regulus', 'omatsuri_daynight', 'sometimes(note_mirror|frag_plus_5)', 'scoreclear_aa|visual_scoregauge', 'gauge_tempest', 'gauge_hard', 'gauge_ilith_summer', 'frags_kou', 'visual_ink', 'shirabe_entry_fee', 'frags_yume', 'note_mirror|visual_hide_far', 'frags_ongeki', 'gauge_areus', 'gauge_seele', 'gauge_isabelle', 'gauge_exhaustion', 'skill_lagrange', 'gauge_safe_10', 'frags_nami', 'skill_elizabeth', 'skill_lily', 'skill_kanae_midsummer', 'eto_uncap', 'luna_uncap', 'frags_preferred_song', 'visual_ghost_skynotes', 'ayu_uncap', 'skill_vita', 'skill_fatalis', 'skill_reunion', 'frags_ongeki_slash', 'frags_ongeki_hard', 'skill_amane', 'skill_kou_winter', 'gauge_hard|note_mirror', 'skill_shama', 'skill_milk', 'skill_shikoku', 'skill_mika', 'ilith_awakened_skill', 'skill_mithra', 'skill_toa', 'skill_nami_twilight', 'skill_ilith_ivy', 'skill_hikari_vanessa', 'skill_maya', 'skill_luin', 'skill_luin_uncap', 'skill_kanae_uncap', 'skill_doroc_uncap', 'skill_saya_uncap', 'skill_luna_ilot', 'skill_eto_hoppe', 'skill_aichan', 'skill_nell', 'skill_chinatsu', 'skill_tsumugi']
return render_template('web/changechar.html', skill_ids=skill_ids) return render_template('web/changechar.html', skill_ids=skill_ids)