mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2025-12-14 08:06:23 +08:00
'Small' update
- Add Course Mode - Add support for downloading additional files - Add support for `skill_fatalis` (Hikari booms your world.) - Delete my hair X< > WHERE IS MY TAIRITSU ?! > Some other things are not supported now, such as... the feature which is one line above.
This commit is contained in:
@@ -128,6 +128,11 @@ class Character:
|
||||
'''对外显示的uncap状态'''
|
||||
return False if self.is_uncapped_override else self.is_uncapped
|
||||
|
||||
@property
|
||||
def is_base_character(self) -> bool:
|
||||
# 应该是只有对立这样
|
||||
return self.character_id == 1
|
||||
|
||||
|
||||
class UserCharacter(Character):
|
||||
'''
|
||||
@@ -212,7 +217,8 @@ class UserCharacter(Character):
|
||||
def to_dict(self) -> dict:
|
||||
if self.char_type is None:
|
||||
self.select_character_info(self.user)
|
||||
r = {"is_uncapped_override": self.is_uncapped_override,
|
||||
r = {'base_character': self.is_base_character,
|
||||
"is_uncapped_override": self.is_uncapped_override,
|
||||
"is_uncapped": self.is_uncapped,
|
||||
"uncap_cores": self.uncap_cores_to_dict(),
|
||||
"char_type": self.char_type,
|
||||
@@ -231,6 +237,10 @@ class UserCharacter(Character):
|
||||
}
|
||||
if self.voice:
|
||||
r['voice'] = self.voice
|
||||
if self.character_id == 55:
|
||||
r['fatalis_is_limited'] = True # emmmmmmm
|
||||
if self.character_id in [1, 6, 7, 17, 18, 24, 32, 35, 52]:
|
||||
r['base_character_id'] = 1
|
||||
return r
|
||||
|
||||
def change_uncap_override(self, user=None):
|
||||
|
||||
@@ -17,9 +17,11 @@ class Constant:
|
||||
ETO_UNCAP_BONUS_PROGRESS = 7
|
||||
LUNA_UNCAP_BONUS_PROGRESS = 7
|
||||
AYU_UNCAP_BONUS_PROGRESS = 5
|
||||
SKILL_FATALIS_WORLD_LOCKED_TIME = 3600000
|
||||
|
||||
MAX_FRIEND_COUNT = 50
|
||||
|
||||
# You can change this to make another PTT mechanism.
|
||||
BEST30_WEIGHT = 1 / 40
|
||||
RECENT10_WEIGHT = 1 / 40
|
||||
|
||||
@@ -31,5 +33,7 @@ class Constant:
|
||||
DOWNLOAD_TIME_GAP_LIMIT = Config.DOWNLOAD_TIME_GAP_LIMIT
|
||||
DOWNLOAD_LINK_PREFIX = Config.DOWNLOAD_LINK_PREFIX
|
||||
|
||||
LINK_PLAY_UNLOCK_LENGTH = 512
|
||||
LINK_PLAY_TIMEOUT = 10
|
||||
LINK_PLAY_UNLOCK_LENGTH = 512 # Units: bytes
|
||||
LINK_PLAY_TIMEOUT = 10 # Units: seconds
|
||||
|
||||
COURSE_STAMINA_COST = 4
|
||||
|
||||
289
latest version/core/course.py
Normal file
289
latest version/core/course.py
Normal file
@@ -0,0 +1,289 @@
|
||||
|
||||
|
||||
from .error import NoData
|
||||
from .song import Chart
|
||||
from .item import ItemFactory
|
||||
|
||||
|
||||
class CourseChart(Chart):
|
||||
def __init__(self, c=None, song_id: str = None, difficulty: int = None) -> None:
|
||||
super().__init__(c, song_id, difficulty)
|
||||
self.flag_as_hidden: bool = None
|
||||
|
||||
def from_dict(self, d: dict) -> 'CourseChart':
|
||||
self.song_id = d['id']
|
||||
self.difficulty = d['difficulty']
|
||||
self.flag_as_hidden = d.get('flag_as_hidden', False)
|
||||
return self
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
'id': self.song_id,
|
||||
'difficulty': self.difficulty,
|
||||
'flag_as_hidden': self.flag_as_hidden
|
||||
}
|
||||
|
||||
def insert_course_chart(self, course_id: str, song_index: int) -> None:
|
||||
self.c.execute('insert into course_chart values (?,?,?,?,?)',
|
||||
(course_id, self.song_id, self.difficulty, self.flag_as_hidden, song_index))
|
||||
|
||||
|
||||
class Course:
|
||||
def __init__(self, c=None) -> None:
|
||||
self.c = c
|
||||
self.course_id: str = None
|
||||
self.course_name: str = None
|
||||
self.dan_name: str = None
|
||||
self.style: int = None
|
||||
self.gauge_requirement: str = None
|
||||
self.flag_as_hidden_when_requirements_not_met: bool = None
|
||||
self.can_start: bool = None # 这有什么鬼用?
|
||||
|
||||
self.requirements: list = []
|
||||
self.charts: list = [None, None, None, None]
|
||||
self.items: list = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
if self.course_name is None:
|
||||
self.select_course()
|
||||
if not self.items:
|
||||
self.select_course_item()
|
||||
if not self.charts:
|
||||
self.select_course_chart()
|
||||
return {
|
||||
'course_id': self.course_id,
|
||||
'course_name': self.course_name,
|
||||
'dan_name': self.dan_name,
|
||||
'style': self.style,
|
||||
'gauge_requirement': self.gauge_requirement,
|
||||
'flag_as_hidden_when_requirements_not_met': self.flag_as_hidden_when_requirements_not_met,
|
||||
'can_start': self.can_start,
|
||||
'requirements': [{'value': x, 'type': 'course'} for x in self.requirements],
|
||||
'songs': [x.to_dict() for x in self.charts],
|
||||
'rewards': [str(x) for x in self.items]
|
||||
}
|
||||
|
||||
def from_dict(self, d: dict) -> 'Course':
|
||||
self.course_id = d['course_id']
|
||||
self.course_name = d.get('course_name', '')
|
||||
self.dan_name = d.get('dan_name', '')
|
||||
self.style = d.get('style', 1)
|
||||
self.gauge_requirement = d.get('gauge_requirement', 'default')
|
||||
self.flag_as_hidden_when_requirements_not_met = d.get(
|
||||
'flag_as_hidden_when_requirements_not_met', False)
|
||||
self.can_start = d.get('can_start', True)
|
||||
self.requirements = [x['value'] for x in d.get('requirements', [])]
|
||||
self.charts = [CourseChart(self.c).from_dict(x)
|
||||
for x in d.get('songs', [])]
|
||||
self.items = [ItemFactory.from_str(x, self.c)
|
||||
for x in d.get('rewards', [])]
|
||||
|
||||
return self
|
||||
|
||||
def from_list(self, l: list) -> 'Course':
|
||||
self.course_id = l[0]
|
||||
self.course_name = l[1]
|
||||
self.dan_name = l[2]
|
||||
self.style = l[3] if l[3] else 1
|
||||
self.gauge_requirement = l[4] if l[4] else 'default'
|
||||
self.flag_as_hidden_when_requirements_not_met = l[5] == 1
|
||||
self.can_start = l[6] == 1
|
||||
|
||||
return self
|
||||
|
||||
def select_course(self, course_id: str = None) -> 'Course':
|
||||
if course_id is not None:
|
||||
self.course_id = course_id
|
||||
self.c.execute(
|
||||
'''select * from course where course_id = ?''', (self.course_id,))
|
||||
x = self.c.fetchone()
|
||||
if x is None:
|
||||
raise NoData('The course `%s` is not found.' % self.course_id)
|
||||
return self.from_list(x)
|
||||
|
||||
def select_course_chart(self) -> None:
|
||||
self.c.execute(
|
||||
'''select * from course_chart where course_id = ?''', (self.course_id,))
|
||||
|
||||
for i in self.c.fetchall():
|
||||
self.charts[i[4]] = CourseChart(self.c).from_dict({
|
||||
'id': i[1],
|
||||
'difficulty': i[2],
|
||||
'flag_as_hidden': i[3] == 1
|
||||
})
|
||||
|
||||
def select_course_requirement(self) -> None:
|
||||
self.c.execute(
|
||||
'''select required_id from course_requirement where course_id = ?''', (self.course_id,))
|
||||
self.requirements = [x[0] for x in self.c.fetchall()]
|
||||
|
||||
def select_course_item(self) -> None:
|
||||
self.c.execute(
|
||||
'''select * from course_item where course_id = ?''', (self.course_id,))
|
||||
self.items = [ItemFactory.from_dict({
|
||||
'item_id': x[1],
|
||||
'type': x[2],
|
||||
'amount': x[3] if x[3] else 1,
|
||||
}, self.c) for x in self.c.fetchall()]
|
||||
|
||||
def insert_course(self) -> None:
|
||||
self.c.execute(
|
||||
'''insert into course values (?,?,?,?,?,?,?)''', (self.course_id, self.course_name, self.dan_name, self.style, self.gauge_requirement, self.flag_as_hidden_when_requirements_not_met, self.can_start))
|
||||
|
||||
def insert_course_item(self) -> None:
|
||||
for i in self.items:
|
||||
self.c.execute('''insert into course_item values (?,?,?,?)''',
|
||||
(self.course_id, i.item_id, i.item_type, i.amount))
|
||||
|
||||
def insert_course_chart(self) -> None:
|
||||
for i, x in enumerate(self.charts):
|
||||
x.insert_course_chart(self.course_id, i)
|
||||
|
||||
def insert_course_requirement(self) -> None:
|
||||
for i in self.requirements:
|
||||
self.c.execute('''insert into course_requirement values (?,?)''',
|
||||
(self.course_id, i))
|
||||
|
||||
def insert_all(self) -> None:
|
||||
self.insert_course()
|
||||
self.insert_course_item()
|
||||
self.insert_course_chart()
|
||||
self.insert_course_requirement()
|
||||
|
||||
|
||||
class UserCourse(Course):
|
||||
'''
|
||||
用户课题类\
|
||||
parameter: `user` - `User`类或子类的实例
|
||||
'''
|
||||
|
||||
def __init__(self, c=None, user=None) -> None:
|
||||
super().__init__(c)
|
||||
self.user = user
|
||||
|
||||
self.is_completed: bool = False
|
||||
self.high_score: int = None
|
||||
self.best_clear_type: int = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
r = super().to_dict()
|
||||
if self.is_completed is None:
|
||||
self.select_user_course()
|
||||
r.update({
|
||||
'is_completed': self.is_completed,
|
||||
'high_score': self.high_score,
|
||||
'best_clear_type': self.best_clear_type
|
||||
})
|
||||
return r
|
||||
|
||||
def select_user_course(self, course_id: str = None) -> None:
|
||||
if course_id is not None:
|
||||
self.course_id = course_id
|
||||
self.c.execute('''select * from user_course where user_id = ? and course_id = ?''',
|
||||
(self.user.user_id, self.course_id))
|
||||
x = self.c.fetchone()
|
||||
if x is None:
|
||||
self.is_completed = False
|
||||
self.high_score = 0
|
||||
self.best_clear_type = 0
|
||||
else:
|
||||
self.is_completed = True
|
||||
self.high_score = x[2]
|
||||
self.best_clear_type = x[3]
|
||||
|
||||
def insert_user_course(self) -> None:
|
||||
self.c.execute('''insert into user_course values (?,?,?,?)''',
|
||||
(self.user.user_id, self.course_id, self.high_score, self.best_clear_type))
|
||||
|
||||
def update_user_course(self) -> None:
|
||||
self.c.execute('''update user_course set high_score = ?, best_clear_type = ? where user_id = ? and course_id = ?''',
|
||||
(self.high_score, self.best_clear_type, self.user.user_id, self.course_id))
|
||||
|
||||
|
||||
class UserCourseList:
|
||||
'''
|
||||
用户课题列表类\
|
||||
parameter: `user` - `User`类或子类的实例
|
||||
'''
|
||||
|
||||
def __init__(self, c=None, user=None) -> None:
|
||||
self.c = c
|
||||
self.user = user
|
||||
|
||||
self.courses: list = []
|
||||
|
||||
def to_dict_list(self) -> list:
|
||||
return [x.to_dict() for x in self.courses]
|
||||
|
||||
def select_all(self) -> None:
|
||||
self.c.execute('''select * from course''')
|
||||
self.courses = [UserCourse(self.c, self.user).from_list(x)
|
||||
for x in self.c.fetchall()]
|
||||
for i in self.courses:
|
||||
i.select_user_course()
|
||||
i.select_course_chart()
|
||||
i.select_course_item()
|
||||
i.select_course_requirement()
|
||||
|
||||
|
||||
class CoursePlay(UserCourse):
|
||||
'''
|
||||
课题模式打歌类,联动UserPlay\
|
||||
parameter: `user` - `UserOnline`类或子类的实例\
|
||||
'user_play` - `UserPlay`类的实例
|
||||
'''
|
||||
|
||||
def __init__(self, c=None, user=None, user_play=None) -> None:
|
||||
super().__init__(c, user)
|
||||
self.user_play = user_play
|
||||
|
||||
self.score: int = None
|
||||
self.clear_type: int = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
'rewards': [x.to_dict() for x in self.items],
|
||||
"current_stamina": self.user.stamina.stamina,
|
||||
"max_stamina_ts": self.user.stamina.max_stamina_ts,
|
||||
'user_course_banners': self.user.course_banners
|
||||
}
|
||||
|
||||
def update(self) -> None:
|
||||
'''课题模式更新'''
|
||||
if self.user_play.health < 0:
|
||||
# 你挂了
|
||||
self.user_play.course_play_state = 5
|
||||
self.score = 0
|
||||
self.clear_type = 0
|
||||
self.user_play.update_play_state_for_course()
|
||||
return None
|
||||
self.user_play.course_play_state += 1
|
||||
self.score += self.user_play.score
|
||||
from .score import Score
|
||||
if Score.get_song_state(self.clear_type) > Score.get_song_state(self.user_play.clear_type):
|
||||
self.clear_type = self.user_play.clear_type
|
||||
self.user_play.update_play_state_for_course()
|
||||
|
||||
if self.user_play.course_play_state == 4:
|
||||
self.user.select_user_about_stamina()
|
||||
self.select_course_item()
|
||||
for i in self.items:
|
||||
i.user_claim_item(self.user)
|
||||
|
||||
self.select_user_course()
|
||||
if not self.is_completed:
|
||||
self.high_score = self.score
|
||||
self.best_clear_type = self.clear_type
|
||||
self.is_completed = True
|
||||
self.insert_user_course()
|
||||
return None
|
||||
|
||||
flag = False
|
||||
if self.score > self.high_score:
|
||||
self.high_score = self.score
|
||||
flag = True
|
||||
if Score.get_song_state(self.clear_type) > Score.get_song_state(self.best_clear_type):
|
||||
self.best_clear_type = self.clear_type
|
||||
flag = True
|
||||
if flag:
|
||||
self.update_user_course()
|
||||
@@ -136,7 +136,7 @@ class DownloadList(UserDownload):
|
||||
|
||||
re = {}
|
||||
for i in dir_list:
|
||||
if os.path.isfile(os.path.join(Constant.SONG_FILE_FOLDER_PATH, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg', '3.ogg']:
|
||||
if os.path.isfile(os.path.join(Constant.SONG_FILE_FOLDER_PATH, song_id, i)) and i in ['0.aff', '1.aff', '2.aff', '3.aff', 'base.ogg', '3.ogg', 'video.mp4', 'video_audio.ogg']:
|
||||
x = UserDownload(self.c, self.user)
|
||||
# self.downloads.append(x) # 这实际上没有用
|
||||
x.song_id = song_id
|
||||
@@ -156,6 +156,16 @@ class DownloadList(UserDownload):
|
||||
re['audio']['3'] = {"checksum": x.hash, "url": x.url}
|
||||
else:
|
||||
re['audio']['3'] = {"checksum": x.hash}
|
||||
elif i == 'video.mp4' or i == 'video_audio.ogg':
|
||||
if 'additional_files' not in re:
|
||||
re['additional_files'] = []
|
||||
|
||||
if self.url_flag:
|
||||
re['additional_files'].append(
|
||||
{"checksum": x.hash, "url": x.url, 'file_name': i})
|
||||
else:
|
||||
re['additional_files'].append(
|
||||
{"checksum": x.hash, 'file_name': i})
|
||||
else:
|
||||
if 'chart' not in re:
|
||||
re['chart'] = {}
|
||||
|
||||
@@ -45,7 +45,8 @@ class UserItem(Item):
|
||||
查询用户item\
|
||||
parameter: `user` - `User`类或子类的实例
|
||||
'''
|
||||
self.user = user
|
||||
if user is not None:
|
||||
self.user = user
|
||||
self.c.execute('''select amount from user_item where user_id=? and item_id=? and type=?''',
|
||||
(self.user.user_id, self.item_id, self.item_type))
|
||||
x = self.c.fetchone()
|
||||
@@ -88,6 +89,7 @@ class PositiveItem(UserItem):
|
||||
self.c = c
|
||||
|
||||
def user_claim_item(self, user):
|
||||
'''添加或使用用户item,注意是+amount'''
|
||||
self.user = user
|
||||
self.c.execute('''select amount from user_item where user_id=? and item_id=? and type=?''',
|
||||
(self.user.user_id, self.item_id, self.item_type))
|
||||
@@ -116,6 +118,9 @@ class ItemCore(PositiveItem):
|
||||
self.item_id = core.item_id
|
||||
self.amount = - core.amount if reverse else core.amount
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.item_id + '_' + str(self.amount)
|
||||
|
||||
|
||||
class ItemCharacter(UserItem):
|
||||
item_type = 'character'
|
||||
@@ -179,6 +184,9 @@ class Fragment(UserItem):
|
||||
def user_claim_item(self, user):
|
||||
pass
|
||||
|
||||
def __str__(self) -> str:
|
||||
return 'fragment' + str(self.amount)
|
||||
|
||||
|
||||
class Anni5tix(PositiveItem):
|
||||
item_type = 'anni5tix'
|
||||
@@ -204,6 +212,17 @@ class WorldUnlock(NormalItem):
|
||||
self.is_available = True
|
||||
|
||||
|
||||
class CourseBanner(NormalItem):
|
||||
item_type = 'course_banner'
|
||||
|
||||
def __init__(self, c) -> None:
|
||||
super().__init__(c)
|
||||
self.is_available = True
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.item_id)
|
||||
|
||||
|
||||
class Single(NormalItem):
|
||||
item_type = 'single'
|
||||
|
||||
@@ -229,7 +248,7 @@ class ProgBoost(UserItem):
|
||||
世界模式prog_boost\
|
||||
parameters: `user` - `UserOnline`类或子类的实例
|
||||
'''
|
||||
user.update_prog_boost(1)
|
||||
user.update_user_one_column('prog_boost', 1)
|
||||
|
||||
|
||||
class Stamina6(UserItem):
|
||||
@@ -240,11 +259,13 @@ class Stamina6(UserItem):
|
||||
|
||||
def user_claim_item(self, user):
|
||||
'''
|
||||
世界模式记忆源点买体力
|
||||
世界模式记忆源点或残片买体力+6\
|
||||
顺手清一下世界模式过载状态
|
||||
'''
|
||||
user.select_user_about_stamina()
|
||||
user.stamina.stamina += 6
|
||||
user.stamina.update()
|
||||
user.update_user_one_column('world_mode_locked_end_ts', -1)
|
||||
|
||||
|
||||
class ItemFactory:
|
||||
@@ -278,6 +299,8 @@ class ItemFactory:
|
||||
return ProgBoost(self.c)
|
||||
elif item_type == 'stamina6':
|
||||
return Stamina6(self.c)
|
||||
elif item_type == 'course_banner':
|
||||
return CourseBanner(self.c)
|
||||
else:
|
||||
raise InputError('The item type `%s` is wrong.' % item_type)
|
||||
|
||||
@@ -303,6 +326,31 @@ class ItemFactory:
|
||||
i.is_available = d.get('is_available', True)
|
||||
return i
|
||||
|
||||
@classmethod
|
||||
def from_str(cls, s: str, c=None):
|
||||
if s.startswith('fragment'):
|
||||
item_type = 'fragment'
|
||||
item_id = 'fragment'
|
||||
amount = int(s[8:])
|
||||
elif s.startswith('core'):
|
||||
item_type = 'core'
|
||||
x = s.split('_')
|
||||
item_id = x[0] + '_' + x[1]
|
||||
amount = int(x[-1])
|
||||
elif s.startswith('course_banner'):
|
||||
item_type = 'course_banner'
|
||||
item_id = s
|
||||
amount = 1
|
||||
else:
|
||||
raise InputError('The string of item is wrong.')
|
||||
i = cls().get_item(item_type)
|
||||
if c is not None:
|
||||
i.c = c
|
||||
i.item_id = item_id
|
||||
i.amount = amount
|
||||
i.is_available = True
|
||||
return i
|
||||
|
||||
|
||||
class UserItemList:
|
||||
'''
|
||||
|
||||
@@ -107,7 +107,7 @@ class LocalMultiPlayer:
|
||||
'''创建房间'''
|
||||
if user is not None:
|
||||
self.user = user
|
||||
user.select_user_about_name()
|
||||
user.select_user_one_column('name')
|
||||
self.data_swap((1, self.user.name, self.user.song_unlock))
|
||||
self.room = Room()
|
||||
self.room.room_code = self.data_recv[1]
|
||||
@@ -124,7 +124,7 @@ class LocalMultiPlayer:
|
||||
if room is not None:
|
||||
self.room = room
|
||||
|
||||
self.user.select_user_about_name()
|
||||
self.user.select_user_one_column('name')
|
||||
self.data_swap(
|
||||
(2, self.user.name, self.user.song_unlock, room.room_code))
|
||||
self.room.room_code = self.data_recv[1]
|
||||
|
||||
@@ -110,7 +110,7 @@ class Purchase:
|
||||
self.select()
|
||||
if not self.items:
|
||||
self.select_items()
|
||||
self.user.select_user_about_ticket()
|
||||
self.user.select_user_one_column('ticket', 0)
|
||||
price_used = self.price_displayed
|
||||
|
||||
if self.user.ticket < price_used:
|
||||
@@ -125,7 +125,7 @@ class Purchase:
|
||||
x.user_claim_item(self.user)
|
||||
else:
|
||||
self.user.ticket -= price_used
|
||||
self.user.update_user_about_ticket()
|
||||
self.user.update_user_one_column('ticket')
|
||||
|
||||
for i in self.items:
|
||||
i.user_claim_item(self.user)
|
||||
|
||||
@@ -13,10 +13,11 @@ class SaveData:
|
||||
self.clearlamps_data = []
|
||||
self.clearedsongs_data = []
|
||||
self.unlocklist_data = []
|
||||
self.installid_data = ''
|
||||
self.devicemodelname_data = ''
|
||||
self.installid_data: str = ''
|
||||
self.devicemodelname_data: str = ''
|
||||
self.story_data = []
|
||||
self.createdAt = 0
|
||||
self.createdAt: int = 0
|
||||
self.finalestate_data: str = "0|100|5616|85146|402821|148126|629916|492991|982851|510091|1912|942819|100606|919245|26270|781178|265839|354540|1611284|6478221|7178089|9580111|139100|2757121|1411969|2249637|3927929|26270|781178|265839|7692918|1245269|5628557|6199755|8340388|6897967|9435206|8853182|6483214|4923592|718524|8922556|7939972|1762215|877327|7939972|3229801|3217716|1642203|2487749|1624592|5357186|5362614|4202613|27003|7178029|4047038|9202383|8677179|4916716|2126424|2140654|5258529|1844588|7228940|3956629|65189|8123987|74181243|9173764|6123461|37167213|671214|171272315|1337"
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
@@ -45,7 +46,10 @@ class SaveData:
|
||||
"version": {
|
||||
"val": 1
|
||||
},
|
||||
"createdAt": self.createdAt
|
||||
"createdAt": self.createdAt,
|
||||
# 'finalestate': {
|
||||
# 'val': self.finalestate_data
|
||||
# }
|
||||
}
|
||||
|
||||
def select_all(self, user) -> None:
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
from base64 import b64encode
|
||||
from os import urandom
|
||||
from time import time
|
||||
|
||||
from .constant import Constant
|
||||
from .course import CoursePlay
|
||||
from .error import NoData, StaminaNotEnough
|
||||
from .item import ItemCore
|
||||
from .song import Chart
|
||||
from .sql import Query, Sql
|
||||
from .util import md5
|
||||
@@ -205,16 +209,22 @@ class UserPlay(UserScore):
|
||||
self.ptt: Potential = None # 临时用来计算用户ptt的
|
||||
self.world_play: 'WorldPlay' = None
|
||||
|
||||
self.course_play_state: int = None
|
||||
self.course_play: 'CoursePlay' = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
if self.is_world_mode is None:
|
||||
if self.is_world_mode is None or self.course_play_state is None:
|
||||
return {}
|
||||
elif not self.is_world_mode:
|
||||
return {'global_rank': self.user.global_rank, 'user_rating': self.user.rating_ptt}
|
||||
else:
|
||||
if self.course_play_state == 4:
|
||||
r = self.course_play.to_dict()
|
||||
elif self.is_world_mode:
|
||||
r = self.world_play.to_dict()
|
||||
r['user_rating'] = self.user.rating_ptt
|
||||
r['global_rank'] = self.user.global_rank
|
||||
return r
|
||||
else:
|
||||
r = {}
|
||||
r['user_rating'] = self.user.rating_ptt
|
||||
r['global_rank'] = self.user.global_rank
|
||||
r['finale_play_value'] = 0 # emmmm
|
||||
return r
|
||||
|
||||
@property
|
||||
def is_protected(self) -> bool:
|
||||
@@ -243,19 +253,31 @@ class UserPlay(UserScore):
|
||||
return True
|
||||
|
||||
def get_play_state(self) -> None:
|
||||
'''本应该是检查是否有token,当然这里不管有没有,是用来判断世界模式的'''
|
||||
self.c.execute('''select stamina_multiply,fragment_multiply,prog_boost_multiply from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
|
||||
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty})
|
||||
'''检查token,当然这里不管有没有,是用来判断世界模式和课题模式的'''
|
||||
self.c.execute(
|
||||
'''select * from songplay_token where token=:a ''', {'a': self.song_token})
|
||||
x = self.c.fetchone()
|
||||
if not x:
|
||||
self.is_world_mode = False
|
||||
self.course_play_state = -1
|
||||
return None
|
||||
self.stamina_multiply = int(x[0])
|
||||
self.fragment_multiply = int(x[1])
|
||||
self.prog_boost_multiply = int(x[2])
|
||||
self.is_world_mode = True
|
||||
self.song.set_chart(x[2], x[3])
|
||||
if x[4]:
|
||||
self.course_play = CoursePlay(self.c, self.user, self)
|
||||
self.course_play.course_id = x[4]
|
||||
self.course_play.score = x[6]
|
||||
self.course_play.clear_type = x[7]
|
||||
self.is_world_mode = False
|
||||
self.course_play_state = x[5]
|
||||
else:
|
||||
self.stamina_multiply = int(x[8])
|
||||
self.fragment_multiply = int(x[9])
|
||||
self.prog_boost_multiply = int(x[10])
|
||||
self.is_world_mode = True
|
||||
self.course_play_state = -1
|
||||
|
||||
def set_play_state(self, stamina_multiply: int = 1, fragment_multiply: int = 100, prog_boost_multiply: int = 0) -> None:
|
||||
def set_play_state_for_world(self, stamina_multiply: int = 1, fragment_multiply: int = 100, prog_boost_multiply: int = 0) -> None:
|
||||
self.song_token = b64encode(urandom(64)).decode()
|
||||
self.stamina_multiply = int(stamina_multiply)
|
||||
self.fragment_multiply = int(fragment_multiply)
|
||||
self.prog_boost_multiply = int(prog_boost_multiply)
|
||||
@@ -266,10 +288,9 @@ class UserPlay(UserScore):
|
||||
if x and x[0] == 1:
|
||||
self.prog_boost_multiply = 300
|
||||
|
||||
self.c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
|
||||
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty})
|
||||
self.c.execute('''insert into world_songplay values(:a,:b,:c,:d,:e,:f)''', {
|
||||
'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})
|
||||
self.clear_play_state()
|
||||
self.c.execute('''insert into songplay_token values(:t,:a,:b,:c,'',-1,0,0,:d,:e,:f)''', {
|
||||
'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, 't': self.song_token})
|
||||
|
||||
self.user.select_user_about_current_map()
|
||||
self.user.current_map.select_map_info()
|
||||
@@ -277,12 +298,59 @@ class UserPlay(UserScore):
|
||||
self.user.select_user_about_stamina()
|
||||
if self.user.stamina.stamina < self.user.current_map.stamina_cost * self.stamina_multiply:
|
||||
raise StaminaNotEnough('Stamina is not enough.')
|
||||
|
||||
self.user.select_user_about_character()
|
||||
if not self.user.is_skill_sealed:
|
||||
self.user.character.select_character_info()
|
||||
if self.user.character.skill_id_displayed == 'skill_fatalis':
|
||||
# 特殊判断hikari fatalis的双倍体力消耗
|
||||
self.user.stamina.stamina -= self.user.current_map.stamina_cost * \
|
||||
self.stamina_multiply * 2
|
||||
self.user.stamina.update()
|
||||
return None
|
||||
|
||||
self.user.stamina.stamina -= self.user.current_map.stamina_cost * self.stamina_multiply
|
||||
self.user.stamina.update()
|
||||
|
||||
def set_play_state_for_course(self, use_course_skip_purchase: bool, course_id: str = None) -> None:
|
||||
'''课题模式打歌初始化'''
|
||||
self.song_token = 'c_' + b64encode(urandom(64)).decode()
|
||||
if course_id is not None:
|
||||
self.course_play.course_id = course_id
|
||||
|
||||
self.course_play_state = 0
|
||||
self.course_play.score = 0
|
||||
self.course_play.clear_type = 3 # 设置为PM,即最大值
|
||||
|
||||
self.c.execute('''insert into songplay_token values(?,?,?,?,?,?,?,?,1,100,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.user.select_user_about_stamina()
|
||||
if use_course_skip_purchase:
|
||||
x = ItemCore(self.c)
|
||||
x.item_id = 'core_course_skip_purchase'
|
||||
x.amount = -1
|
||||
x.user_claim_item(self.user)
|
||||
else:
|
||||
if self.user.stamina.stamina < Constant.COURSE_STAMINA_COST:
|
||||
raise StaminaNotEnough('Stamina is not enough.')
|
||||
self.user.stamina.stamina -= Constant.COURSE_STAMINA_COST
|
||||
self.user.stamina.update()
|
||||
|
||||
def update_token_for_course(self) -> None:
|
||||
'''课题模式更新token,并查用户体力'''
|
||||
previous_token = self.song_token
|
||||
self.song_token = 'c_' + b64encode(urandom(64)).decode()
|
||||
self.c.execute('''update songplay_token set token=? where token=?''',
|
||||
(self.song_token, previous_token))
|
||||
self.user.select_user_about_stamina()
|
||||
|
||||
def update_play_state_for_course(self) -> None:
|
||||
self.c.execute('''update songplay_token set course_state=?, course_score=?, course_clear_type=? where token=?''',
|
||||
(self.course_play_state, self.course_play.score, self.course_play.clear_type, self.song_token))
|
||||
|
||||
def clear_play_state(self) -> None:
|
||||
self.c.execute('''delete from world_songplay where user_id=:a and song_id=:b and difficulty=:c''', {
|
||||
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty})
|
||||
self.c.execute('''delete from songplay_token where user_id=:a ''', {
|
||||
'a': self.user.user_id})
|
||||
|
||||
def update_recent30(self) -> None:
|
||||
'''更新此分数对应用户的recent30'''
|
||||
@@ -377,6 +445,10 @@ class UserPlay(UserScore):
|
||||
self.world_play = WorldPlay(self.c, self.user, self)
|
||||
self.world_play.update()
|
||||
|
||||
# 课题模式判断
|
||||
if self.course_play_state >= 0:
|
||||
self.course_play.update()
|
||||
|
||||
|
||||
class Potential:
|
||||
'''
|
||||
|
||||
@@ -32,8 +32,10 @@ class Chart:
|
||||
'''select rating_pst, rating_prs, rating_ftr, rating_byn from chart where song_id=:a''', {'a': self.song_id})
|
||||
x = self.c.fetchone()
|
||||
if x is None:
|
||||
raise NoData('The song `%s` does not exist.' % self.song_id)
|
||||
self.defnum = x[self.difficulty]
|
||||
self.defnum = -10
|
||||
# raise NoData('The song `%s` does not exist.' % self.song_id)
|
||||
else:
|
||||
self.defnum = x[self.difficulty]
|
||||
|
||||
|
||||
class Song:
|
||||
|
||||
@@ -286,6 +286,8 @@ class UserInfo(User):
|
||||
self.favorite_character = None
|
||||
self.max_stamina_notification_enabled = False
|
||||
self.prog_boost = 0
|
||||
self.next_fragstam_ts: int = None
|
||||
self.world_mode_locked_end_ts: int = None
|
||||
|
||||
self.__cores: list = None
|
||||
self.__packs: list = None
|
||||
@@ -295,6 +297,7 @@ class UserInfo(User):
|
||||
self.__world_unlocks: list = None
|
||||
self.__world_songs: list = None
|
||||
self.curr_available_maps: list = None
|
||||
self.__course_banners: list = None
|
||||
|
||||
@property
|
||||
def cores(self) -> list:
|
||||
@@ -339,6 +342,15 @@ class UserInfo(User):
|
||||
|
||||
return self.__world_songs
|
||||
|
||||
@property
|
||||
def course_banners(self) -> list:
|
||||
if self.__course_banners is None:
|
||||
x = UserItemList(
|
||||
self.c, self.user_id).select_from_type('course_banner')
|
||||
self.__course_banners = [i.item_id for i in x.items]
|
||||
|
||||
return self.__course_banners
|
||||
|
||||
def select_characters(self) -> None:
|
||||
self.characters = UserCharacterList(self.c, self)
|
||||
self.characters.select_user_characters()
|
||||
@@ -471,7 +483,11 @@ class UserInfo(User):
|
||||
"max_friend": Constant.MAX_FRIEND_COUNT,
|
||||
"rating": self.rating_ptt,
|
||||
"join_date": self.join_date,
|
||||
"global_rank": self.global_rank
|
||||
"global_rank": self.global_rank,
|
||||
'country': '',
|
||||
'course_banners': self.course_banners,
|
||||
'world_mode_locked_end_ts': self.world_mode_locked_end_ts,
|
||||
'locked_char_ids': [] # [1]
|
||||
}
|
||||
|
||||
def from_list(self, x: list) -> 'UserInfo':
|
||||
@@ -510,6 +526,7 @@ class UserInfo(User):
|
||||
|
||||
self.stamina = UserStamina(self.c, self)
|
||||
self.stamina.set_value(x[32], x[33])
|
||||
self.world_mode_locked_end_ts = x[34] if x[34] else -1
|
||||
|
||||
return self
|
||||
|
||||
@@ -563,7 +580,7 @@ class UserInfo(User):
|
||||
查询user表有关世界模式打歌的信息
|
||||
'''
|
||||
self.c.execute(
|
||||
'''select character_id, max_stamina_ts, stamina, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, current_map from user where user_id=?''', (self.user_id,))
|
||||
'''select character_id, max_stamina_ts, stamina, is_skill_sealed, is_char_uncapped, is_char_uncapped_override, current_map, world_mode_locked_end_ts from user where user_id=?''', (self.user_id,))
|
||||
x = self.c.fetchone()
|
||||
if not x:
|
||||
raise NoData('No user.', 108, -3)
|
||||
@@ -575,24 +592,13 @@ class UserInfo(User):
|
||||
self.character.is_uncapped = x[4] == 1
|
||||
self.character.is_uncapped_override = x[5] == 1
|
||||
self.current_map = UserMap(self.c, x[6], self)
|
||||
|
||||
def select_user_about_world_rank_score(self) -> None:
|
||||
'''
|
||||
查询user表有关世界模式排名的信息
|
||||
'''
|
||||
self.c.execute(
|
||||
'''select world_rank_score from user where user_id=?''', (self.user_id,))
|
||||
x = self.c.fetchone()
|
||||
if not x:
|
||||
raise NoData('No user.', 108, -3)
|
||||
|
||||
self.world_rank_score = x[0]
|
||||
self.world_mode_locked_end_ts = x[7] if x[7] else -1
|
||||
|
||||
@property
|
||||
def global_rank(self) -> int:
|
||||
'''用户世界排名,如果超过设定最大值,返回0'''
|
||||
if self.world_rank_score is None:
|
||||
self.select_user_about_world_rank_score()
|
||||
self.select_user_one_column('world_rank_score', 0)
|
||||
if self.world_rank_score is None:
|
||||
return 0
|
||||
|
||||
@@ -643,55 +649,32 @@ class UserInfo(User):
|
||||
|
||||
self.world_rank_score = score_sum
|
||||
|
||||
def select_user_about_ticket(self) -> None:
|
||||
def select_user_one_column(self, column_name: str, default_value=None) -> None:
|
||||
'''
|
||||
查询user表有关记忆源点的信息
|
||||
查询user表的某个属性\
|
||||
请注意必须是一个普通属性,不能是一个类的实例
|
||||
'''
|
||||
self.c.execute('''select ticket from user where user_id = :a''', {
|
||||
'a': self.user_id})
|
||||
if column_name not in self.__dict__:
|
||||
raise InputError('No such column.')
|
||||
self.c.execute('''select %s from user where user_id = :a''' %
|
||||
column_name, {'a': self.user_id})
|
||||
x = self.c.fetchone()
|
||||
if not x:
|
||||
raise NoData('No user.', 108, -3)
|
||||
|
||||
self.ticket = x[0]
|
||||
self.__dict__[column_name] = x[0] if x[0] else default_value
|
||||
|
||||
def update_user_about_ticket(self, ticket: int = None) -> None:
|
||||
'''更新记忆源点'''
|
||||
if ticket is not None:
|
||||
self.ticket = ticket
|
||||
self.c.execute('''update user set ticket = :a where user_id = :b''', {
|
||||
'a': self.ticket, 'b': self.user_id})
|
||||
|
||||
def select_user_about_fragstam(self) -> None:
|
||||
def update_user_one_column(self, column_name: str, value=None) -> None:
|
||||
'''
|
||||
查询user表有关碎片购买体力时间的信息
|
||||
更新user表的某个属性\
|
||||
请注意必须是一个普通属性,不能是一个类的实例
|
||||
'''
|
||||
self.c.execute('''select next_fragstam_ts from user where user_id = :a''', {
|
||||
'a': self.user_id})
|
||||
x = self.c.fetchone()
|
||||
if not x:
|
||||
raise NoData('No user.', 108, -3)
|
||||
|
||||
self.next_fragstam_ts = x[0] if x[0] else 0
|
||||
|
||||
def update_user_about_fragstam(self, next_fragstam_ts: int = None) -> None:
|
||||
'''更新碎片购买体力时间'''
|
||||
if next_fragstam_ts is not None:
|
||||
self.next_fragstam_ts = next_fragstam_ts
|
||||
self.c.execute('''update user set next_fragstam_ts = :a where user_id = :b''', {
|
||||
'a': self.next_fragstam_ts, 'b': self.user_id})
|
||||
|
||||
def select_user_about_name(self) -> None:
|
||||
'''
|
||||
查询user表有关用户名的信息
|
||||
'''
|
||||
self.c.execute('''select name from user where user_id = :a''', {
|
||||
'a': self.user_id})
|
||||
x = self.c.fetchone()
|
||||
if not x:
|
||||
raise NoData('No user.', 108, -3)
|
||||
|
||||
self.name = x[0]
|
||||
if column_name not in self.__dict__:
|
||||
raise InputError('No such column.')
|
||||
if value is not None:
|
||||
self.__dict__[column_name] = value
|
||||
self.c.execute('''update user set %s = :a where user_id = :b''' %
|
||||
column_name, {'a': self.__dict__[column_name], 'b': self.user_id})
|
||||
|
||||
|
||||
class UserOnline(UserInfo):
|
||||
@@ -731,29 +714,8 @@ class UserOnline(UserInfo):
|
||||
else:
|
||||
raise FriendError('No user or the user is not your friend.', 401)
|
||||
|
||||
def update_prog_boost(self, prog_boost: int = None) -> None:
|
||||
'''更新`prog_boost`'''
|
||||
if prog_boost:
|
||||
self.prog_boost = prog_boost
|
||||
self.c.execute('''update user set prog_boost = :a where user_id = :b''',
|
||||
{'a': self.prog_boost, 'b': self.user_id})
|
||||
|
||||
def change_favorite_character(self, character_id: int) -> None:
|
||||
'''更改用户的favorite_character'''
|
||||
self.favorite_character = UserCharacter(self.c, character_id, self)
|
||||
self.c.execute('''update user set favorite_character = :a where user_id = :b''',
|
||||
{'a': self.favorite_character.character_id, 'b': self.user_id})
|
||||
|
||||
def change_is_hide_rating(self, is_hide_rating: bool = None) -> None:
|
||||
'''更改用户的is_hide_rating'''
|
||||
if is_hide_rating is not None:
|
||||
self.is_hide_rating = is_hide_rating
|
||||
self.c.execute('''update user set is_hide_rating = :a where user_id = :b''',
|
||||
{'a': self.is_hide_rating, 'b': self.user_id})
|
||||
|
||||
def change_max_stamina_notification_enabled(self, max_stamina_notification_enabled: bool = None) -> None:
|
||||
'''更改用户的max_stamina_notification_enabled'''
|
||||
if max_stamina_notification_enabled is not None:
|
||||
self.max_stamina_notification_enabled = max_stamina_notification_enabled
|
||||
self.c.execute('''update user set max_stamina_notification_enabled = :a where user_id = :b''',
|
||||
{'a': self.max_stamina_notification_enabled, 'b': self.user_id})
|
||||
|
||||
@@ -374,8 +374,8 @@ class Stamina:
|
||||
@property
|
||||
def stamina(self) -> int:
|
||||
'''通过计算得到当前的正确体力值'''
|
||||
stamina = int(Constant.MAX_STAMINA - (self.max_stamina_ts -
|
||||
int(time()*1000)) / Constant.STAMINA_RECOVER_TICK)
|
||||
stamina = round(Constant.MAX_STAMINA - (self.max_stamina_ts -
|
||||
int(time()*1000)) / Constant.STAMINA_RECOVER_TICK)
|
||||
|
||||
if stamina >= Constant.MAX_STAMINA:
|
||||
if self.__stamina >= Constant.MAX_STAMINA:
|
||||
@@ -383,12 +383,12 @@ class Stamina:
|
||||
else:
|
||||
stamina = Constant.MAX_STAMINA
|
||||
|
||||
return stamina if stamina > 0 else 0
|
||||
return stamina
|
||||
|
||||
@stamina.setter
|
||||
def stamina(self, value: int) -> None:
|
||||
'''设置体力值,此处会导致max_stamina_ts变化'''
|
||||
self.__stamina = int(value)
|
||||
self.__stamina = round(value)
|
||||
self.max_stamina_ts = int(
|
||||
time()*1000) - (self.__stamina-Constant.MAX_STAMINA) * Constant.STAMINA_RECOVER_TICK
|
||||
|
||||
@@ -464,7 +464,8 @@ class WorldPlay:
|
||||
"overdrive": self.character_used.overdrive.get_value(self.character_used.level)
|
||||
},
|
||||
"current_stamina": self.user.stamina.stamina,
|
||||
"max_stamina_ts": self.user.stamina.max_stamina_ts
|
||||
"max_stamina_ts": self.user.stamina.max_stamina_ts,
|
||||
'world_mode_locked_end_ts': self.user.world_mode_locked_end_ts
|
||||
}
|
||||
|
||||
if self.overdrive_extra is not None:
|
||||
@@ -536,7 +537,7 @@ class WorldPlay:
|
||||
def update(self) -> None:
|
||||
'''世界模式更新'''
|
||||
if self.user_play.prog_boost_multiply != 0:
|
||||
self.user.update_prog_boost(0)
|
||||
self.user.update_user_one_column('prog_boost', 0)
|
||||
|
||||
self.user_play.clear_play_state()
|
||||
self.user.select_user_about_world_play()
|
||||
@@ -591,8 +592,8 @@ class WorldPlay:
|
||||
self._skill_vita()
|
||||
|
||||
def after_climb(self) -> None:
|
||||
factory_dict = {'eto_uncap': self._eto_uncap,
|
||||
'ayu_uncap': self._ayu_uncap, 'luna_uncap': self._luna_uncap}
|
||||
factory_dict = {'eto_uncap': self._eto_uncap, 'ayu_uncap': self._ayu_uncap,
|
||||
'luna_uncap': self._luna_uncap, 'skill_fatalis': self._skill_fatalis}
|
||||
if self.character_used.skill_id_displayed in factory_dict:
|
||||
factory_dict[self.character_used.skill_id_displayed]()
|
||||
|
||||
@@ -658,3 +659,10 @@ class WorldPlay:
|
||||
self.step_value = 0
|
||||
|
||||
self.user.current_map.reclimb(self.step_value)
|
||||
|
||||
def _skill_fatalis(self) -> None:
|
||||
'''hikari fatalis技能,世界模式超载,打完休息60分钟'''
|
||||
|
||||
self.user.world_mode_locked_end_ts = int(
|
||||
time()*1000) + Constant.SKILL_FATALIS_WORLD_LOCKED_TIME
|
||||
self.user.update_user_one_column('world_mode_locked_end_ts')
|
||||
|
||||
449
latest version/database/courses.json
Normal file
449
latest version/database/courses.json
Normal file
@@ -0,0 +1,449 @@
|
||||
[
|
||||
{
|
||||
"course_id": "4.0-dan-1",
|
||||
"style": 1,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 1,
|
||||
"id": "inkarusi"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 1,
|
||||
"id": "snowwhite"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 1,
|
||||
"id": "sakurafubuki"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 1,
|
||||
"id": "purgatorium"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 1",
|
||||
"course_name": "新世界的第一步",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment300",
|
||||
"course_banner_1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-2",
|
||||
"style": 2,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "vexaria"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "clotho"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "brandnewworld"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "oblivia"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 2",
|
||||
"course_name": "一次心跳的加速",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment400",
|
||||
"course_banner_2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-3",
|
||||
"style": 3,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "suomi"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "grimheart"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "bookmaker"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "avril"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 3",
|
||||
"course_name": "永不屈服的精神",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment500",
|
||||
"course_banner_3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-4",
|
||||
"style": 4,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "gekka"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "solitarydream"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "kanagawa"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "iconoclast"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 4",
|
||||
"course_name": "光芒的永恒之地",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment600",
|
||||
"course_banner_4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-5",
|
||||
"style": 5,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "faintlight"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "eveninginscarlet"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "kyogenkigo"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "blrink"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 5",
|
||||
"course_name": "玻璃之中的残酷",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment700",
|
||||
"course_banner_5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-6",
|
||||
"style": 6,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "vindication"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "heartjackin"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "ascent"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "macromod"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 6",
|
||||
"course_name": "沉浸于悲喜交加",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment800",
|
||||
"course_banner_6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-7",
|
||||
"style": 7,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "galaxyfriends"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "neokosmo"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "conflict"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "redolentshape"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 7",
|
||||
"course_name": "在命运到来之际",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment900",
|
||||
"course_banner_7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-8",
|
||||
"style": 8,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "corruption"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "neowings"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "valhallazero"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "izana"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [],
|
||||
"flag_as_hidden_when_requirements_not_met": false,
|
||||
"dan_name": "Phase 8",
|
||||
"course_name": "趋于混沌的时空",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment1000",
|
||||
"course_banner_8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-9",
|
||||
"style": 9,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "felis"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "lightningscrew"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "seclusion"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": false,
|
||||
"difficulty": 2,
|
||||
"id": "livefastdieyoung"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [
|
||||
{
|
||||
"value": "4.0-dan-8",
|
||||
"type": "course"
|
||||
}
|
||||
],
|
||||
"flag_as_hidden_when_requirements_not_met": true,
|
||||
"dan_name": "Phase 9",
|
||||
"course_name": "分崩离析的自我",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment1000",
|
||||
"core_generic_10",
|
||||
"course_banner_9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-10",
|
||||
"style": 10,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 2,
|
||||
"id": "cyaegha"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 2,
|
||||
"id": "divinelight"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 2,
|
||||
"id": "dantalion"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 2,
|
||||
"id": "aegleseeker"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [
|
||||
{
|
||||
"value": "4.0-dan-9",
|
||||
"type": "course"
|
||||
}
|
||||
],
|
||||
"flag_as_hidden_when_requirements_not_met": true,
|
||||
"dan_name": "Phase 10",
|
||||
"course_name": "光与对立的洪流",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment1000",
|
||||
"core_generic_10",
|
||||
"course_banner_10"
|
||||
]
|
||||
},
|
||||
{
|
||||
"course_id": "4.0-dan-11",
|
||||
"style": 11,
|
||||
"songs": [
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 3,
|
||||
"id": "infinitestrife"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 2,
|
||||
"id": "grievouslady"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 2,
|
||||
"id": "fractureray"
|
||||
},
|
||||
{
|
||||
"flag_as_hidden": true,
|
||||
"difficulty": 3,
|
||||
"id": "tempestissimo"
|
||||
}
|
||||
],
|
||||
"gauge_requirement": "default",
|
||||
"requirements": [
|
||||
{
|
||||
"value": "4.0-dan-10",
|
||||
"type": "course"
|
||||
}
|
||||
],
|
||||
"flag_as_hidden_when_requirements_not_met": true,
|
||||
"dan_name": "Phase 11",
|
||||
"course_name": "创世之曙光",
|
||||
"can_start": true,
|
||||
"is_completed": false,
|
||||
"high_score": 0,
|
||||
"best_clear_type": -1,
|
||||
"rewards": [
|
||||
"fragment2000",
|
||||
"core_generic_20",
|
||||
"course_banner_11"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -4,7 +4,7 @@ import json
|
||||
|
||||
# 数据库初始化文件,删掉arcaea_database.db文件后运行即可,谨慎使用
|
||||
|
||||
ARCAEA_SERVER_VERSION = 'v2.8.7.dev'
|
||||
ARCAEA_SERVER_VERSION = 'v2.8.9.dev.616sb'
|
||||
|
||||
|
||||
def main(path='./'):
|
||||
@@ -48,7 +48,8 @@ def main(path='./'):
|
||||
ban_flag text,
|
||||
next_fragstam_ts int,
|
||||
max_stamina_ts int,
|
||||
stamina int
|
||||
stamina int,
|
||||
world_mode_locked_end_ts int
|
||||
);''')
|
||||
c.execute('''create table if not exists login(access_token text,
|
||||
user_id int,
|
||||
@@ -187,13 +188,17 @@ def main(path='./'):
|
||||
is_locked int,
|
||||
primary key(user_id, map_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists world_songplay(user_id int,
|
||||
c.execute('''create table if not exists songplay_token(token text primary key,
|
||||
user_id int,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
course_id text,
|
||||
course_state int,
|
||||
course_score int,
|
||||
course_clear_type int,
|
||||
stamina_multiply int,
|
||||
fragment_multiply int,
|
||||
prog_boost_multiply int,
|
||||
primary key(user_id, song_id, difficulty)
|
||||
prog_boost_multiply int
|
||||
);''')
|
||||
c.execute('''create table if not exists download_token(user_id int,
|
||||
song_id text,
|
||||
@@ -299,49 +304,80 @@ def main(path='./'):
|
||||
login_ip text,
|
||||
primary key(user_id, token)
|
||||
);''')
|
||||
c.execute('''create table if not exists course(course_id text primary key,
|
||||
course_name text,
|
||||
dan_name text,
|
||||
style int,
|
||||
gauge_requirement text,
|
||||
flag_as_hidden_when_requirements_not_met int,
|
||||
can_start int
|
||||
);''')
|
||||
c.execute('''create table if not exists user_course(user_id int,
|
||||
course_id text,
|
||||
high_score int,
|
||||
best_clear_type int,
|
||||
primary key(user_id, course_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists course_chart(course_id text,
|
||||
song_id text,
|
||||
difficulty int,
|
||||
flag_as_hidden int,
|
||||
song_index int,
|
||||
primary key(course_id, song_id, difficulty)
|
||||
);''')
|
||||
c.execute('''create table if not exists course_requirement(course_id text,
|
||||
required_id text,
|
||||
primary key(course_id, required_id)
|
||||
);''')
|
||||
c.execute('''create table if not exists course_item(course_id text,
|
||||
item_id text,
|
||||
type text,
|
||||
amount int,
|
||||
primary key(course_id, item_id, type)
|
||||
);''')
|
||||
|
||||
# 搭档初始化
|
||||
char = ['hikari', 'tairitsu', 'kou', 'sapphire', 'lethe', '', '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']
|
||||
'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)']
|
||||
|
||||
skill_id = ['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', '', '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']
|
||||
'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']
|
||||
|
||||
skill_id_uncap = ['', '', 'frags_kou', '', 'visual_ink', '', '', '', '', '', '', 'eto_uncap', 'luna_uncap', 'shirabe_entry_fee',
|
||||
'', '', '', '', '', 'ayu_uncap', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
|
||||
'', '', '', '', '', 'ayu_uncap', '', 'frags_yume', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
|
||||
|
||||
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, 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]
|
||||
|
||||
frag1 = [55, 55, 60, 50, 47, 0, 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]
|
||||
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]
|
||||
|
||||
prog1 = [35, 55, 47, 50, 60, 0, 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]
|
||||
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, 60]
|
||||
|
||||
overdrive1 = [35, 55, 25, 50, 47, 0, 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]
|
||||
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, 65]
|
||||
|
||||
frag20 = [78, 80, 90, 75, 70, 0, 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]
|
||||
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]
|
||||
|
||||
prog20 = [61, 80, 70, 75, 90, 0, 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]
|
||||
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, 100]
|
||||
|
||||
overdrive20 = [61, 80, 47, 75, 70, 0, 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]
|
||||
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, 105]
|
||||
|
||||
frag30 = [88, 90, 100, 75, 80, 0, 70, 79, 65, 40, 50, 90, 100, 92, 0, 61, 67, 92, 85, 50, 86, 62,
|
||||
65, 85, 67, 88, 74, 0.5, 105, 80, 95, 50, 80, 87, 71, 50, 95, 0, 80, 75, 50, 70, 80, 100, 65, 80, 61, 50, 68, 60, 90, 67, 50, 60, 51]
|
||||
65, 85, 67, 88, 74, 0.5, 105, 80, 95, 50, 80, 87, 71, 50, 95, 0, 80, 75, 50, 70, 80, 100, 65, 80, 61, 50, 68, 60, 90, 67, 50, 60, 51, 50]
|
||||
|
||||
prog30 = [71, 90, 80, 75, 100, 0, 90, 102, 84, 78, 105, 77, 73, 78, 0, 99, 80, 66, 46, 93, 40, 83,
|
||||
80, 90, 93, 50, 96, 88, 99, 108, 75, 80, 50, 64, 55, 100, 100, 110, 80, 50, 74, 90, 80, 80, 56, 80, 79, 55, 65, 59, 90, 50, 90, 90, 75]
|
||||
80, 90, 93, 50, 96, 88, 99, 108, 75, 80, 50, 64, 55, 100, 100, 110, 80, 50, 74, 90, 80, 80, 56, 80, 79, 55, 65, 59, 90, 50, 90, 90, 75, 100]
|
||||
|
||||
overdrive30 = [71, 90, 57, 75, 80, 0, 95, 79, 65, 31, 50, 69, 100, 68, 0, 78, 50, 70, 62, 59, 64,
|
||||
56, 73, 95, 67, 84, 80, 88, 79, 80, 50, 80, 80, 63, 25, 50, 82, 55, 50, 95, 55, 70, 100, 80, 99, 80, 61, 40, 69, 62, 51, 90, 67, 60, 100]
|
||||
56, 73, 95, 67, 84, 80, 88, 79, 80, 50, 80, 80, 63, 25, 50, 82, 55, 50, 95, 55, 70, 100, 80, 99, 80, 61, 40, 69, 62, 51, 90, 67, 60, 100, 105]
|
||||
|
||||
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]
|
||||
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]
|
||||
|
||||
char_core = {
|
||||
0: [{'core_id': 'core_hollow', 'amount': 25}, {'core_id': 'core_desolate', 'amount': 5}],
|
||||
@@ -362,7 +398,7 @@ def main(path='./'):
|
||||
19: [{'core_id': 'core_colorful', 'amount': 30}]
|
||||
}
|
||||
|
||||
for i in range(0, 55):
|
||||
for i in range(0, 56):
|
||||
skill_requires_uncap = 1 if i == 2 else 0
|
||||
|
||||
if i in [0, 1, 2, 4, 13, 26, 27, 28, 29, 36, 21, 42, 43, 11, 12, 19]:
|
||||
@@ -370,10 +406,11 @@ def main(path='./'):
|
||||
c.execute(sql, (i, char[i], frag1[i], prog1[i], overdrive1[i], frag20[i], prog20[i], overdrive20[i],
|
||||
frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i]))
|
||||
else:
|
||||
if i != 5:
|
||||
sql = '''insert into character values(?,?,20,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)'''
|
||||
c.execute(sql, (i, char[i], frag1[i], prog1[i], overdrive1[i], frag20[i], prog20[i], overdrive20[i],
|
||||
frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i]))
|
||||
if i == 5:
|
||||
continue
|
||||
sql = '''insert into character values(?,?,20,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)'''
|
||||
c.execute(sql, (i, char[i], frag1[i], prog1[i], overdrive1[i], frag20[i], prog20[i], overdrive20[i],
|
||||
frag30[i], prog30[i], overdrive30[i], skill_id[i], skill_unlock_level[i], skill_requires_uncap, skill_id_uncap[i], char_type[i]))
|
||||
|
||||
c.execute('''insert into character values(?,?,20,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)''', (99,
|
||||
'shirahime', 38, 33, 28, 66, 58, 50, 66, 58, 50, 'frags_preferred_song', 0, 0, '', 0))
|
||||
@@ -383,7 +420,7 @@ def main(path='./'):
|
||||
c.execute('''insert into char_item values(?,?,'core',?)''',
|
||||
(i, j['core_id'], j['amount']))
|
||||
cores = ['core_hollow', 'core_desolate', 'core_chunithm', 'core_crimson',
|
||||
'core_ambivalent', 'core_scarlet', 'core_groove', 'core_generic', 'core_binary', 'core_colorful']
|
||||
'core_ambivalent', 'core_scarlet', 'core_groove', 'core_generic', 'core_binary', 'core_colorful', 'core_course_skip_purchase']
|
||||
|
||||
for i in cores:
|
||||
c.execute('''insert into item values(?,"core",1,'')''', (i,))
|
||||
@@ -394,10 +431,14 @@ def main(path='./'):
|
||||
c.execute('''insert into item values(?,"world_song",1,'')''', (i,))
|
||||
|
||||
world_unlocks = ["scenery_chap1", "scenery_chap2",
|
||||
"scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6"]
|
||||
"scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6", "scenery_chap7"]
|
||||
for i in world_unlocks:
|
||||
c.execute('''insert into item values(?,"world_unlock",1,'')''', (i,))
|
||||
|
||||
course_banners = ['course_banner_' + str(i) for i in range(1, 12)]
|
||||
for i in course_banners:
|
||||
c.execute('''insert into item values(?,"course_banner",1,'')''', (i,))
|
||||
|
||||
c.execute('''insert into item values(?,?,?,?)''',
|
||||
('fragment', 'fragment', 1, ''))
|
||||
c.execute('''insert into item values(?,?,?,?)''',
|
||||
@@ -450,7 +491,25 @@ def main(path='./'):
|
||||
f.close()
|
||||
insert_items(c, packs)
|
||||
|
||||
# api权限与权限组初始化
|
||||
# course初始化
|
||||
try:
|
||||
f = open(path+'courses.json', 'r', encoding="utf-8")
|
||||
courses = json.load(f)
|
||||
f.close()
|
||||
except:
|
||||
courses = []
|
||||
|
||||
if courses:
|
||||
if path == './':
|
||||
# 有什么好办法吗
|
||||
import sys
|
||||
sys.path.append('..')
|
||||
from core.course import Course
|
||||
for i in courses:
|
||||
x = Course(c).from_dict(i)
|
||||
x.insert_all()
|
||||
|
||||
# api权限与权限组初始化
|
||||
role = ['admin', 'user', 'selecter']
|
||||
role_caption = ['管理员', '用户', '查询接口']
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "dynamix",
|
||||
@@ -66,8 +66,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "mirai",
|
||||
@@ -91,8 +91,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "yugamu",
|
||||
@@ -111,8 +111,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "lanota",
|
||||
@@ -131,8 +131,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "nijuusei",
|
||||
@@ -171,8 +171,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "tonesphere",
|
||||
@@ -191,8 +191,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "groovecoaster",
|
||||
@@ -211,8 +211,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "zettai",
|
||||
@@ -231,8 +231,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "chunithm",
|
||||
@@ -269,8 +269,8 @@
|
||||
],
|
||||
"price": 400,
|
||||
"orig_price": 400,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "omatsuri",
|
||||
@@ -289,8 +289,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "vs",
|
||||
@@ -309,8 +309,8 @@
|
||||
],
|
||||
"price": 500,
|
||||
"orig_price": 500,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "extend",
|
||||
@@ -329,8 +329,9 @@
|
||||
],
|
||||
"price": 0,
|
||||
"orig_price": 700,
|
||||
"discount_from": 1615248000000,
|
||||
"discount_to": 1615852799000
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000,
|
||||
"discount_reason": "extend"
|
||||
},
|
||||
{
|
||||
"name": "alice",
|
||||
@@ -348,7 +349,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 500,
|
||||
"price": 500
|
||||
"price": 500,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "alice_append_1",
|
||||
@@ -366,7 +369,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 300,
|
||||
"price": 300
|
||||
"price": 300,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "ongeki",
|
||||
@@ -384,7 +389,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 400,
|
||||
"price": 400
|
||||
"price": 400,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "maimai",
|
||||
@@ -402,7 +409,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 400,
|
||||
"price": 400
|
||||
"price": 400,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "chunithm_append_1",
|
||||
@@ -438,7 +447,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 300,
|
||||
"price": 300
|
||||
"price": 300,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "observer",
|
||||
@@ -456,7 +467,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 500,
|
||||
"price": 500
|
||||
"price": 500,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "observer_append_2",
|
||||
@@ -474,7 +487,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 300,
|
||||
"price": 300
|
||||
"price": 300,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "wacca",
|
||||
@@ -492,7 +507,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 500,
|
||||
"price": 500
|
||||
"price": 500,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "nijuusei_append_1",
|
||||
@@ -528,7 +545,9 @@
|
||||
}
|
||||
],
|
||||
"orig_price": 500,
|
||||
"price": 500
|
||||
"price": 500,
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "musedash",
|
||||
@@ -538,20 +557,17 @@
|
||||
"id": "musedash",
|
||||
"is_available": true
|
||||
},
|
||||
{
|
||||
"type": "character",
|
||||
"id": "marija",
|
||||
"is_available": true
|
||||
},
|
||||
{
|
||||
"type": "core",
|
||||
"amount": 5,
|
||||
"amount": 4,
|
||||
"id": "core_generic",
|
||||
"is_available": true
|
||||
}
|
||||
],
|
||||
"orig_price": 400,
|
||||
"price": 400,
|
||||
"orig_price": 400
|
||||
"discount_from": 1646784000000,
|
||||
"discount_to": 1647388799000
|
||||
},
|
||||
{
|
||||
"name": "lanota_append_1",
|
||||
@@ -570,5 +586,23 @@
|
||||
],
|
||||
"orig_price": 300,
|
||||
"price": 300
|
||||
},
|
||||
{
|
||||
"name": "finale",
|
||||
"items": [
|
||||
{
|
||||
"type": "pack",
|
||||
"id": "finale",
|
||||
"is_available": true
|
||||
},
|
||||
{
|
||||
"type": "core",
|
||||
"amount": 5,
|
||||
"id": "core_generic",
|
||||
"is_available": true
|
||||
}
|
||||
],
|
||||
"orig_price": 500,
|
||||
"price": 500
|
||||
}
|
||||
]
|
||||
@@ -9,6 +9,7 @@ from . import purchase
|
||||
from . import present
|
||||
from . import others
|
||||
from . import multiplayer
|
||||
from . import course
|
||||
|
||||
bp = Blueprint('server', __name__, url_prefix=Config.GAME_API_PREFIX)
|
||||
bp.register_blueprint(user.bp)
|
||||
@@ -20,3 +21,4 @@ bp.register_blueprint(purchase.bp)
|
||||
bp.register_blueprint(present.bp)
|
||||
bp.register_blueprint(others.bp)
|
||||
bp.register_blueprint(multiplayer.bp)
|
||||
bp.register_blueprint(course.bp)
|
||||
|
||||
33
latest version/server/course.py
Normal file
33
latest version/server/course.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from core.constant import Constant
|
||||
from core.course import UserCourseList
|
||||
from core.error import ArcError
|
||||
from core.item import ItemCore
|
||||
from core.sql import Connect
|
||||
from core.user import UserOnline
|
||||
from flask import Blueprint, request
|
||||
|
||||
from .auth import auth_required
|
||||
from .func import error_return, success_return
|
||||
|
||||
bp = Blueprint('course', __name__, url_prefix='/course')
|
||||
|
||||
|
||||
@bp.route('/me', methods=['GET'])
|
||||
@auth_required(request)
|
||||
def course_me(user_id):
|
||||
with Connect() as c:
|
||||
try:
|
||||
user = UserOnline(c, user_id)
|
||||
core = ItemCore(c)
|
||||
core.item_id = 'core_course_skip_purchase'
|
||||
core.select(user)
|
||||
x = UserCourseList(c, user)
|
||||
x.select_all()
|
||||
return success_return({
|
||||
'courses': x.to_dict_list(),
|
||||
"stamina_cost": Constant.COURSE_STAMINA_COST,
|
||||
"course_skip_purchase_ticket": core.amount
|
||||
})
|
||||
except ArcError as e:
|
||||
return error_return(e)
|
||||
return error_return()
|
||||
@@ -12,7 +12,7 @@ from werkzeug.datastructures import ImmutableMultiDict
|
||||
from .auth import auth_required
|
||||
from .func import error_return, success_return
|
||||
from .present import present_info
|
||||
from .purchase import bundle_pack
|
||||
from .purchase import bundle_pack, bundle_bundle
|
||||
from .score import song_score_friend
|
||||
from .user import user_me
|
||||
from .world import world_all
|
||||
@@ -44,13 +44,20 @@ def download_song(user_id):
|
||||
return error_return()
|
||||
|
||||
|
||||
@bp.route('/finale/progress', methods=['GET'])
|
||||
def finale_progress():
|
||||
return success_return({'percentage': 100000})
|
||||
|
||||
|
||||
map_dict = {'/user/me': user_me,
|
||||
'/purchase/bundle/pack': bundle_pack,
|
||||
'/serve/download/me/song': download_song,
|
||||
'/game/info': game_info,
|
||||
'/present/me': present_info,
|
||||
'/world/map/me': world_all,
|
||||
'/score/song/friend': song_score_friend}
|
||||
'/score/song/friend': song_score_friend,
|
||||
'/purchase/bundle/bundle': bundle_bundle,
|
||||
'/finale/progress': finale_progress}
|
||||
|
||||
|
||||
@bp.route('/compose/aggregate', methods=['GET']) # 集成式请求
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from time import time
|
||||
|
||||
from core.error import ArcError, ItemUnavailable
|
||||
from core.item import ItemFactory
|
||||
from core.item import ItemFactory, Stamina6
|
||||
from core.purchase import Purchase, PurchaseList
|
||||
from core.redeem import UserRedeem
|
||||
from core.sql import Connect
|
||||
@@ -40,6 +40,35 @@ def get_single(user_id):
|
||||
return error_return()
|
||||
|
||||
|
||||
@bp.route('/bundle/bundle', methods=['GET']) # 捆绑包
|
||||
def bundle_bundle():
|
||||
return success_return([])
|
||||
# return success_return([{
|
||||
# "name": "chronicles",
|
||||
# "items": [{
|
||||
# "type": "bundle",
|
||||
# "id": "core"
|
||||
# }, {
|
||||
# "type": "bundle",
|
||||
# "id": "prelude"
|
||||
# }, {
|
||||
# "type": "bundle",
|
||||
# "id": "rei"
|
||||
# }, {
|
||||
# "type": "bundle",
|
||||
# "id": "yugamu"
|
||||
# }, {
|
||||
# "type": "bundle",
|
||||
# "id": "vs"
|
||||
# }],
|
||||
# "orig_price": 2000,
|
||||
# "price": 2000,
|
||||
# "discount_from": 1657152000000,
|
||||
# "discount_to": 1758447999000,
|
||||
# "discount_reason": "chronicle"
|
||||
# }])
|
||||
|
||||
|
||||
@bp.route('/me/pack', methods=['POST']) # 曲包和单曲购买
|
||||
@auth_required(request)
|
||||
def buy_pack_or_single(user_id):
|
||||
@@ -89,7 +118,7 @@ def buy_special(user_id):
|
||||
if item_id == 'stamina6':
|
||||
r['stamina'] = x.user.stamina.stamina
|
||||
r['max_stamina_ts'] = x.user.stamina.max_stamina_ts
|
||||
|
||||
r['world_mode_locked_end_ts'] = -1
|
||||
return success_return(r)
|
||||
except ArcError as e:
|
||||
return error_return(e)
|
||||
@@ -105,21 +134,21 @@ def purchase_stamina(user_id, buy_stamina_type):
|
||||
return error_return()
|
||||
|
||||
user = UserOnline(c, user_id)
|
||||
user.select_user_about_fragstam()
|
||||
user.select_user_one_column('next_fragstam_ts', -1)
|
||||
now = int(time()*1000)
|
||||
if user.next_fragstam_ts > now:
|
||||
return ItemUnavailable('Buying stamina by fragment is not available yet.', 905)
|
||||
|
||||
user.update_user_about_fragstam(now + 24 * 3600 * 1000)
|
||||
user.select_user_about_stamina()
|
||||
user.stamina.stamina += 6
|
||||
user.stamina.update()
|
||||
|
||||
user.update_user_one_column(
|
||||
'next_fragstam_ts', now + 24 * 3600 * 1000)
|
||||
s = Stamina6(c)
|
||||
s.user_claim_item(user)
|
||||
return success_return({
|
||||
"user_id": user.user_id,
|
||||
"stamina": user.stamina.stamina,
|
||||
"max_stamina_ts": user.stamina.max_stamina_ts,
|
||||
"next_fragstam_ts": user.next_fragstam_ts
|
||||
"next_fragstam_ts": user.next_fragstam_ts,
|
||||
'world_mode_locked_end_ts': -1
|
||||
})
|
||||
except ArcError as e:
|
||||
return error_return(e)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from time import time
|
||||
from core.course import CoursePlay
|
||||
|
||||
from core.error import ArcError, InputError
|
||||
from core.rank import RankList
|
||||
@@ -18,7 +19,7 @@ def score_token():
|
||||
return success_return({'token': '1145141919810'})
|
||||
|
||||
|
||||
@bp.route('/token/world', methods=['GET']) # 世界模式成绩上传所需的token,无验证
|
||||
@bp.route('/token/world', methods=['GET']) # 世界模式成绩上传所需的token
|
||||
@auth_required(request)
|
||||
def score_token_world(user_id):
|
||||
|
||||
@@ -33,12 +34,12 @@ def score_token_world(user_id):
|
||||
x = UserPlay(c, UserOnline(c, user_id))
|
||||
x.song.set_chart(request.args['song_id'], int(
|
||||
request.args['difficulty']))
|
||||
x.set_play_state(stamina_multiply,
|
||||
fragment_multiply, prog_boost_multiply)
|
||||
x.set_play_state_for_world(stamina_multiply,
|
||||
fragment_multiply, prog_boost_multiply)
|
||||
return success_return({
|
||||
"stamina": x.user.stamina.stamina,
|
||||
"max_stamina_ts": x.user.stamina.max_stamina_ts,
|
||||
"token": "13145201919810"
|
||||
"token": x.song_token
|
||||
}
|
||||
)
|
||||
except ArcError as e:
|
||||
@@ -46,6 +47,47 @@ def score_token_world(user_id):
|
||||
return error_return()
|
||||
|
||||
|
||||
@bp.route('/token/course', methods=['GET']) # 课题模式成绩上传所需的token
|
||||
@auth_required(request)
|
||||
def score_token_course(user_id):
|
||||
with Connect() as c:
|
||||
try:
|
||||
use_course_skip_purchase = request.args.get(
|
||||
'use_course_skip_purchase', 'false') == 'true'
|
||||
|
||||
user = UserOnline(c, user_id)
|
||||
user_play = UserPlay(c, user)
|
||||
user_play.song_token = request.args.get('previous_token', None)
|
||||
user_play.get_play_state()
|
||||
|
||||
status = 'created'
|
||||
if user_play.course_play_state == -1:
|
||||
# 没有token,课题模式刚开始
|
||||
course_play = CoursePlay(c, user, user_play)
|
||||
course_play.course_id = request.args['course_id']
|
||||
user_play.course_play = course_play
|
||||
user_play.set_play_state_for_course(
|
||||
use_course_skip_purchase)
|
||||
elif 0 <= user_play.course_play_state <= 3:
|
||||
# 验证token
|
||||
user_play.update_token_for_course()
|
||||
else:
|
||||
# 课题模式已经结束
|
||||
user_play.clear_play_state()
|
||||
user.select_user_about_stamina()
|
||||
status = 'cleared' if user_play.course_play_state == 4 else 'failed'
|
||||
|
||||
return success_return({
|
||||
"stamina": user.stamina.stamina,
|
||||
"max_stamina_ts": user.stamina.max_stamina_ts,
|
||||
"token": user_play.song_token,
|
||||
'status': status
|
||||
})
|
||||
except ArcError as e:
|
||||
return error_return(e)
|
||||
return error_return()
|
||||
|
||||
|
||||
@bp.route('/song', methods=['POST']) # 成绩上传
|
||||
@auth_required(request)
|
||||
def song_score_post(user_id):
|
||||
|
||||
@@ -177,10 +177,8 @@ def sys_set(user_id, set_arg):
|
||||
user.change_favorite_character(int(value))
|
||||
else:
|
||||
value = 'true' == value
|
||||
if 'is_hide_rating' == set_arg:
|
||||
user.change_is_hide_rating(value)
|
||||
elif 'max_stamina_notification_enabled' == set_arg:
|
||||
user.change_max_stamina_notification_enabled(value)
|
||||
if 'is_hide_rating' == set_arg or 'max_stamina_notification_enabled' == set_arg:
|
||||
user.update_user_one_column(set_arg, value)
|
||||
return success_return(user.to_dict())
|
||||
except ArcError as e:
|
||||
return error_return(e)
|
||||
|
||||
@@ -19,7 +19,7 @@ class Config():
|
||||
游戏API地址前缀
|
||||
Game API's URL prefix
|
||||
'''
|
||||
GAME_API_PREFIX = '/years/19'
|
||||
GAME_API_PREFIX = '/divide/20'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
@@ -30,7 +30,7 @@ class Config():
|
||||
Allowed game versions
|
||||
If it is blank, all are allowed.
|
||||
'''
|
||||
ALLOW_APPVERSION = ['3.12.6', '3.12.6c', '3.12.10', '3.12.10c']
|
||||
ALLOW_APPVERSION = ['3.12.6', '3.12.6c', '4.0.0', '4.0.0c']
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
@@ -218,7 +218,7 @@ class Config():
|
||||
是否全解锁搭档
|
||||
If unlocking all partners is enabled
|
||||
'''
|
||||
CHARACTER_FULL_UNLOCK = False
|
||||
CHARACTER_FULL_UNLOCK = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
@@ -423,7 +423,7 @@ def all_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',
|
||||
'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']
|
||||
'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']
|
||||
return render_template('web/changechar.html', skill_ids=skill_ids)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user