mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2025-12-14 08:06:23 +08:00
[Enhance] Missions & ETR
- Add support for missions - PTT mechanism: Change first play protection to new best protection - Adapt to the new difficulty ETR - Uncap DORO*C - Incomplete support for "pick_ticket" - Fix requirements: cryptography >= 35.0.0 Note: This is an intermediate test version, only for Arcaea 5.4.0c. Next version will adapt to 5.4.0.
This commit is contained in:
10
README.md
10
README.md
@@ -1,10 +1,10 @@
|
|||||||
# Arcaea-server
|
# Arcaea-server
|
||||||
|
|
||||||
一个微型的Arcaea本地服务器 A small local server for Arcaea
|
一个微型的 Arcaea 本地服务器 A small local server for Arcaea
|
||||||
|
|
||||||
## 简介 Introduction
|
## 简介 Introduction
|
||||||
|
|
||||||
这是基于Python以及Flask的微型本地Arcaea服务器,可以模拟游戏的主要功能。这可能是我第一次写这种大程序,若有不妥之处,敬请谅解。
|
这是基于 Python 以及 Flask 的微型本地 Arcaea 服务器,可以模拟游戏的主要功能。这可能是我第一次写这种大程序,若有不妥之处,敬请谅解。
|
||||||
|
|
||||||
本程序主要用于学习研究,不得用于任何商业行为,否则后果自负,这不是强制要求,只是一个提醒与警告。
|
本程序主要用于学习研究,不得用于任何商业行为,否则后果自负,这不是强制要求,只是一个提醒与警告。
|
||||||
|
|
||||||
@@ -50,12 +50,14 @@ This procedure is mainly used for study and research, and shall not be used for
|
|||||||
- 下载频次限制 Download rate limit
|
- 下载频次限制 Download rate limit
|
||||||
- 购买系统 Purchase system
|
- 购买系统 Purchase system
|
||||||
- 单曲和曲包 Single & Pack
|
- 单曲和曲包 Single & Pack
|
||||||
- :x: 捆绑包 Bundle
|
- :x: 捆绑包 Pack bundle
|
||||||
- 折扣 Discount
|
- 折扣 Discount
|
||||||
- 五周年兑换券 5-th anniversary ticket
|
- 五周年兑换券 5-th anniversary ticket
|
||||||
|
- 单曲兑换券 Pick ticket
|
||||||
- :x: Extend 包自动降价 Extend pack automatic price reduction
|
- :x: Extend 包自动降价 Extend pack automatic price reduction
|
||||||
- 奖励系统 Present system
|
- 奖励系统 Present system
|
||||||
- 兑换码系统 Redeem code system
|
- 兑换码系统 Redeem code system
|
||||||
|
- 新手任务 Missions
|
||||||
- 角色系统 Character system
|
- 角色系统 Character system
|
||||||
- 数据记录 Data recording
|
- 数据记录 Data recording
|
||||||
- 用户成绩 Users' scores
|
- 用户成绩 Users' scores
|
||||||
@@ -117,7 +119,7 @@ It is just so interesting. What it can do is under exploration.
|
|||||||
- Windows / Linux / Mac OS / Android...
|
- Windows / Linux / Mac OS / Android...
|
||||||
- Python >= 3.6
|
- Python >= 3.6
|
||||||
- Flask >= 2.0
|
- Flask >= 2.0
|
||||||
- Cryptography >= 3.0.0
|
- Cryptography >= 35.0.0
|
||||||
- limits >= 2.7.0
|
- limits >= 2.7.0
|
||||||
- Charles, IDA, proxy app... (optional)
|
- Charles, IDA, proxy app... (optional)
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ def songs_get(data, user):
|
|||||||
'''查询全歌曲信息'''
|
'''查询全歌曲信息'''
|
||||||
A = ['song_id', 'name']
|
A = ['song_id', 'name']
|
||||||
B = ['song_id', 'name', 'rating_pst',
|
B = ['song_id', 'name', 'rating_pst',
|
||||||
'rating_prs', 'rating_ftr', 'rating_byn']
|
'rating_prs', 'rating_ftr', 'rating_byn', 'rating_etr']
|
||||||
with Connect() as c:
|
with Connect() as c:
|
||||||
query = Query(A, A, B).from_dict(data)
|
query = Query(A, A, B).from_dict(data)
|
||||||
x = Sql(c).select('chart', query=query)
|
x = Sql(c).select('chart', query=query)
|
||||||
@@ -97,8 +97,8 @@ def songs_post(data, user):
|
|||||||
@api_try
|
@api_try
|
||||||
def songs_song_difficulty_rank_get(data, user, song_id, difficulty):
|
def songs_song_difficulty_rank_get(data, user, song_id, difficulty):
|
||||||
'''查询歌曲某个难度的成绩排行榜,和游戏内接口相似,只允许limit'''
|
'''查询歌曲某个难度的成绩排行榜,和游戏内接口相似,只允许limit'''
|
||||||
if difficulty not in [0, 1, 2, 3]:
|
if difficulty not in [0, 1, 2, 3, 4]:
|
||||||
raise InputError('Difficulty must be 0, 1, 2 or 3')
|
raise InputError('Difficulty must be 0, 1, 2, 3 or 4')
|
||||||
limit = data.get('limit', 20)
|
limit = data.get('limit', 20)
|
||||||
if not isinstance(limit, int):
|
if not isinstance(limit, int):
|
||||||
raise InputError('Limit must be int')
|
raise InputError('Limit must be int')
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Config:
|
|||||||
|
|
||||||
SONG_FILE_HASH_PRE_CALCULATE = True
|
SONG_FILE_HASH_PRE_CALCULATE = True
|
||||||
|
|
||||||
GAME_API_PREFIX = '/samusugiru/26' # str | list[str]
|
GAME_API_PREFIX = '/saikyoukaze/27' # 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]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from .config_manager import Config
|
from .config_manager import Config
|
||||||
|
|
||||||
ARCAEA_SERVER_VERSION = 'v2.11.3.4'
|
ARCAEA_SERVER_VERSION = 'v2.11.3.5'
|
||||||
ARCAEA_LOG_DATBASE_VERSION = 'v1.1'
|
ARCAEA_LOG_DATBASE_VERSION = 'v1.1'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ class DatabaseInit:
|
|||||||
('memory', 'memory', 1))
|
('memory', 'memory', 1))
|
||||||
self.c.execute('''insert into item values(?,?,?)''',
|
self.c.execute('''insert into item values(?,?,?)''',
|
||||||
('anni5tix', 'anni5tix', 1))
|
('anni5tix', 'anni5tix', 1))
|
||||||
|
self.c.execute('''insert into item values(?,?,?)''',
|
||||||
|
('pick_ticket', 'pick_ticket', 1))
|
||||||
|
|
||||||
with open(self.pack_path, 'rb') as f:
|
with open(self.pack_path, 'rb') as f:
|
||||||
self.insert_purchase_item(load(f))
|
self.insert_purchase_item(load(f))
|
||||||
@@ -99,6 +101,9 @@ class DatabaseInit:
|
|||||||
with open(self.single_path, 'rb') as f:
|
with open(self.single_path, 'rb') as f:
|
||||||
self.insert_purchase_item(load(f))
|
self.insert_purchase_item(load(f))
|
||||||
|
|
||||||
|
self.c.execute('''insert into item values(?,?,?)''', # 新手任务奖励曲
|
||||||
|
('innocence', 'world_song', 1))
|
||||||
|
|
||||||
def course_init(self) -> None:
|
def course_init(self) -> None:
|
||||||
'''初始化课题信息'''
|
'''初始化课题信息'''
|
||||||
courses = []
|
courses = []
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class UserItem(Item):
|
|||||||
|
|
||||||
|
|
||||||
class NormalItem(UserItem):
|
class NormalItem(UserItem):
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c=None) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.c = c
|
self.c = c
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ class NormalItem(UserItem):
|
|||||||
|
|
||||||
|
|
||||||
class PositiveItem(UserItem):
|
class PositiveItem(UserItem):
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c=None) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.c = c
|
self.c = c
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ class PositiveItem(UserItem):
|
|||||||
class ItemCore(PositiveItem):
|
class ItemCore(PositiveItem):
|
||||||
item_type = 'core'
|
item_type = 'core'
|
||||||
|
|
||||||
def __init__(self, c, core_type: str = '', amount: int = 0) -> None:
|
def __init__(self, c=None, core_type: str = '', amount: int = 0) -> None:
|
||||||
super().__init__(c)
|
super().__init__(c)
|
||||||
self.is_available = True
|
self.is_available = True
|
||||||
self.item_id = core_type
|
self.item_id = core_type
|
||||||
@@ -220,10 +220,12 @@ class Memory(UserItem):
|
|||||||
class Fragment(UserItem):
|
class Fragment(UserItem):
|
||||||
item_type = 'fragment'
|
item_type = 'fragment'
|
||||||
|
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c=None, amount=0) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.c = c
|
self.c = c
|
||||||
self.is_available = True
|
self.is_available = True
|
||||||
|
self.item_id = self.item_type
|
||||||
|
self.amount = amount
|
||||||
|
|
||||||
def user_claim_item(self, user):
|
def user_claim_item(self, user):
|
||||||
pass
|
pass
|
||||||
@@ -238,12 +240,24 @@ class Anni5tix(PositiveItem):
|
|||||||
def __init__(self, c) -> None:
|
def __init__(self, c) -> None:
|
||||||
super().__init__(c)
|
super().__init__(c)
|
||||||
self.is_available = True
|
self.is_available = True
|
||||||
|
self.item_id = self.item_type
|
||||||
|
self.amount = 1
|
||||||
|
|
||||||
|
|
||||||
|
class PickTicket(PositiveItem):
|
||||||
|
item_type = 'pick_ticket'
|
||||||
|
|
||||||
|
def __init__(self, c=None) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
self.is_available = True
|
||||||
|
self.item_id = self.item_type
|
||||||
|
self.amount = 1
|
||||||
|
|
||||||
|
|
||||||
class WorldSong(NormalItem):
|
class WorldSong(NormalItem):
|
||||||
item_type = 'world_song'
|
item_type = 'world_song'
|
||||||
|
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c=None) -> None:
|
||||||
super().__init__(c)
|
super().__init__(c)
|
||||||
self.is_available = True
|
self.is_available = True
|
||||||
|
|
||||||
@@ -293,8 +307,10 @@ class ProgBoost(UserItem):
|
|||||||
class Stamina6(UserItem):
|
class Stamina6(UserItem):
|
||||||
item_type = 'stamina6'
|
item_type = 'stamina6'
|
||||||
|
|
||||||
def __init__(self, c) -> None:
|
def __init__(self, c=None) -> None:
|
||||||
super().__init__(c)
|
super().__init__(c)
|
||||||
|
self.item_id = 'stamina6'
|
||||||
|
self.amount = 1
|
||||||
|
|
||||||
def user_claim_item(self, user):
|
def user_claim_item(self, user):
|
||||||
'''
|
'''
|
||||||
@@ -307,6 +323,23 @@ class Stamina6(UserItem):
|
|||||||
user.update_user_one_column('world_mode_locked_end_ts', -1)
|
user.update_user_one_column('world_mode_locked_end_ts', -1)
|
||||||
|
|
||||||
|
|
||||||
|
class ItemStamina(UserItem):
|
||||||
|
item_type = 'stamina'
|
||||||
|
|
||||||
|
def __init__(self, c=None, amount=1) -> None:
|
||||||
|
super().__init__(c)
|
||||||
|
self.item_id = 'stamina'
|
||||||
|
self.amount = amount
|
||||||
|
|
||||||
|
def user_claim_item(self, user):
|
||||||
|
'''
|
||||||
|
新手任务奖励体力
|
||||||
|
'''
|
||||||
|
user.select_user_about_stamina()
|
||||||
|
user.stamina.stamina += self.amount
|
||||||
|
user.stamina.update()
|
||||||
|
|
||||||
|
|
||||||
class ItemFactory:
|
class ItemFactory:
|
||||||
def __init__(self, c=None) -> None:
|
def __init__(self, c=None) -> None:
|
||||||
self.c = c
|
self.c = c
|
||||||
@@ -324,6 +357,8 @@ class ItemFactory:
|
|||||||
return Memory(self.c)
|
return Memory(self.c)
|
||||||
elif item_type == 'anni5tix':
|
elif item_type == 'anni5tix':
|
||||||
return Anni5tix(self.c)
|
return Anni5tix(self.c)
|
||||||
|
elif item_type == 'pick_ticket':
|
||||||
|
return PickTicket(self.c)
|
||||||
elif item_type == 'world_song':
|
elif item_type == 'world_song':
|
||||||
return WorldSong(self.c)
|
return WorldSong(self.c)
|
||||||
elif item_type == 'world_unlock':
|
elif item_type == 'world_unlock':
|
||||||
|
|||||||
240
latest version/core/mission.py
Normal file
240
latest version/core/mission.py
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
from .item import Fragment, ItemCore, ItemStamina, PickTicket, WorldSong
|
||||||
|
|
||||||
|
|
||||||
|
class Mission:
|
||||||
|
mission_id: str = None
|
||||||
|
items: list = []
|
||||||
|
|
||||||
|
def __init__(self, c=None):
|
||||||
|
self.c = c
|
||||||
|
self.user = None
|
||||||
|
self._status: int = None
|
||||||
|
|
||||||
|
if self.c is not None:
|
||||||
|
for i in self.items:
|
||||||
|
i.c = self.c
|
||||||
|
|
||||||
|
def to_dict(self, has_items=False) -> dict:
|
||||||
|
r = {
|
||||||
|
'mission_id': self.mission_id,
|
||||||
|
'status': self.status,
|
||||||
|
}
|
||||||
|
if has_items:
|
||||||
|
r['items'] = [x.to_dict() for x in self.items]
|
||||||
|
return r
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self) -> str:
|
||||||
|
if self._status == 1:
|
||||||
|
return 'inprogress'
|
||||||
|
elif self._status == 2:
|
||||||
|
return 'cleared'
|
||||||
|
elif self._status == 3:
|
||||||
|
return 'prevclaimedfragmission'
|
||||||
|
elif self._status == 4:
|
||||||
|
return 'claimed'
|
||||||
|
|
||||||
|
return 'locked'
|
||||||
|
|
||||||
|
def user_claim_mission(self, user):
|
||||||
|
# param: user - User 类或子类的实例
|
||||||
|
if user is not None:
|
||||||
|
self.user = user
|
||||||
|
|
||||||
|
self.c.execute('''insert or replace into user_mission (user_id, mission_id, status) values (?, ?, 4)''',
|
||||||
|
(self.user.user_id, self.mission_id))
|
||||||
|
for i in self.items:
|
||||||
|
i.user_claim_item(self.user)
|
||||||
|
self._status = 4
|
||||||
|
|
||||||
|
def user_clear_mission(self, user):
|
||||||
|
# param: user - User 类或子类的实例
|
||||||
|
if user is not None:
|
||||||
|
self.user = user
|
||||||
|
|
||||||
|
self.c.execute('''insert or replace into user_mission (user_id, mission_id, status) values (?, ?, 2)''',
|
||||||
|
(self.user.user_id, self.mission_id))
|
||||||
|
self._status = 2
|
||||||
|
|
||||||
|
def select_user_mission(self, user):
|
||||||
|
# param: user - User 类或子类的实例
|
||||||
|
if user is not None:
|
||||||
|
self.user = user
|
||||||
|
|
||||||
|
self._status = 0
|
||||||
|
self.c.execute('''select status from user_mission where user_id=? and mission_id=?''',
|
||||||
|
(self.user.user_id, self.mission_id))
|
||||||
|
x = self.c.fetchone()
|
||||||
|
|
||||||
|
if x and x[0]:
|
||||||
|
self._status = x[0]
|
||||||
|
|
||||||
|
|
||||||
|
class M11(Mission):
|
||||||
|
mission_id = 'mission_1_1_tutorial'
|
||||||
|
items = [Fragment(amount=10)]
|
||||||
|
|
||||||
|
|
||||||
|
class M12(Mission):
|
||||||
|
mission_id = 'mission_1_2_clearsong'
|
||||||
|
items = [Fragment(amount=10)]
|
||||||
|
|
||||||
|
|
||||||
|
class M13(Mission):
|
||||||
|
mission_id = 'mission_1_3_settings'
|
||||||
|
items = [Fragment(amount=10)]
|
||||||
|
|
||||||
|
|
||||||
|
class M14(Mission):
|
||||||
|
mission_id = 'mission_1_4_allsongsview'
|
||||||
|
items = [Fragment(amount=10)]
|
||||||
|
|
||||||
|
|
||||||
|
class M15(Mission):
|
||||||
|
mission_id = 'mission_1_5_fragunlock'
|
||||||
|
items = [ItemCore(core_type='core_generic', amount=1)]
|
||||||
|
|
||||||
|
|
||||||
|
class M1E(Mission):
|
||||||
|
mission_id = 'mission_1_end'
|
||||||
|
items = [Fragment(amount=100)]
|
||||||
|
|
||||||
|
|
||||||
|
class M21(Mission):
|
||||||
|
mission_id = 'mission_2_1_account'
|
||||||
|
items = [Fragment(amount=20)]
|
||||||
|
|
||||||
|
|
||||||
|
class M22(Mission):
|
||||||
|
mission_id = 'mission_2_2_profile'
|
||||||
|
items = [Fragment(amount=20)]
|
||||||
|
|
||||||
|
|
||||||
|
class M23(Mission):
|
||||||
|
mission_id = 'mission_2_3_partner'
|
||||||
|
items = [Fragment(amount=20)]
|
||||||
|
|
||||||
|
|
||||||
|
class M24(Mission):
|
||||||
|
mission_id = 'mission_2_4_usestamina'
|
||||||
|
items = [ItemCore(core_type='core_generic', amount=1)]
|
||||||
|
|
||||||
|
|
||||||
|
class M25(Mission):
|
||||||
|
mission_id = 'mission_2_5_prologuestart'
|
||||||
|
items = [ItemCore(core_type='core_generic', amount=1)]
|
||||||
|
|
||||||
|
|
||||||
|
class M2E(Mission):
|
||||||
|
mission_id = 'mission_2_end'
|
||||||
|
items = [ItemCore(core_type='core_generic', amount=3)]
|
||||||
|
|
||||||
|
|
||||||
|
class M31(Mission):
|
||||||
|
mission_id = 'mission_3_1_prsclear'
|
||||||
|
items = [Fragment(amount=50)]
|
||||||
|
|
||||||
|
|
||||||
|
class M32(Mission):
|
||||||
|
mission_id = 'mission_3_2_etherdrop'
|
||||||
|
items = [ItemStamina(amount=2)]
|
||||||
|
|
||||||
|
|
||||||
|
class M33(Mission):
|
||||||
|
mission_id = 'mission_3_3_step50'
|
||||||
|
items = [Fragment(amount=50)]
|
||||||
|
|
||||||
|
|
||||||
|
class M34(Mission):
|
||||||
|
mission_id = 'mission_3_4_frag60'
|
||||||
|
items = [ItemStamina(amount=2)]
|
||||||
|
|
||||||
|
|
||||||
|
class M3E(Mission):
|
||||||
|
mission_id = 'mission_3_end'
|
||||||
|
items = [ItemStamina(amount=6)]
|
||||||
|
|
||||||
|
|
||||||
|
class M41(Mission):
|
||||||
|
mission_id = 'mission_4_1_exgrade'
|
||||||
|
items = [Fragment(amount=100)]
|
||||||
|
|
||||||
|
|
||||||
|
class M42(Mission):
|
||||||
|
mission_id = 'mission_4_2_potential350'
|
||||||
|
items = [ItemStamina(amount=2)]
|
||||||
|
|
||||||
|
|
||||||
|
class M43(Mission):
|
||||||
|
mission_id = 'mission_4_3_twomaps'
|
||||||
|
items = [Fragment(amount=100)]
|
||||||
|
|
||||||
|
|
||||||
|
class M44(Mission):
|
||||||
|
mission_id = 'mission_4_4_worldsongunlock'
|
||||||
|
items = [ItemCore(core_type='core_generic', amount=3)]
|
||||||
|
|
||||||
|
|
||||||
|
class M45(Mission):
|
||||||
|
mission_id = 'mission_4_5_prologuefinish'
|
||||||
|
items = [ItemStamina(amount=2)]
|
||||||
|
|
||||||
|
|
||||||
|
_innocence = WorldSong()
|
||||||
|
_innocence.amount = 1
|
||||||
|
_innocence.item_id = 'innocence'
|
||||||
|
|
||||||
|
|
||||||
|
class M4E(Mission):
|
||||||
|
mission_id = 'mission_4_end'
|
||||||
|
items = [_innocence]
|
||||||
|
|
||||||
|
|
||||||
|
class M51(Mission):
|
||||||
|
mission_id = 'mission_5_1_songgrouping'
|
||||||
|
items = [Fragment(amount=50)]
|
||||||
|
|
||||||
|
|
||||||
|
class M52(Mission):
|
||||||
|
mission_id = 'mission_5_2_partnerlv12'
|
||||||
|
items = [Fragment(amount=250)]
|
||||||
|
|
||||||
|
|
||||||
|
class M53(Mission):
|
||||||
|
mission_id = 'mission_5_3_cores'
|
||||||
|
items = [ItemCore(core_type='core_generic', amount=3)]
|
||||||
|
|
||||||
|
|
||||||
|
class M54(Mission):
|
||||||
|
mission_id = 'mission_5_4_courseclear'
|
||||||
|
items = [ItemCore(core_type='core_generic', amount=3)]
|
||||||
|
|
||||||
|
|
||||||
|
class M5E(Mission):
|
||||||
|
mission_id = 'mission_5_end'
|
||||||
|
items = [PickTicket()]
|
||||||
|
|
||||||
|
|
||||||
|
MISSION_DICT = {i.mission_id: i for i in Mission.__subclasses__()}
|
||||||
|
|
||||||
|
|
||||||
|
class UserMissionList:
|
||||||
|
def __init__(self, c=None, user=None):
|
||||||
|
self.c = c
|
||||||
|
self.user = user
|
||||||
|
|
||||||
|
self.missions: list = []
|
||||||
|
|
||||||
|
def select_all(self):
|
||||||
|
self.missions = []
|
||||||
|
self.c.execute('''select mission_id, status from user_mission where user_id=?''',
|
||||||
|
(self.user.user_id,))
|
||||||
|
for i in self.c.fetchall():
|
||||||
|
x = MISSION_DICT[i[0]]()
|
||||||
|
x._status = i[1]
|
||||||
|
self.missions.append(x)
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def to_dict_list(self) -> list:
|
||||||
|
return [i.to_dict() for i in self.missions]
|
||||||
@@ -29,7 +29,7 @@ class Purchase(CollectionItemMixin):
|
|||||||
|
|
||||||
self.items: list = []
|
self.items: list = []
|
||||||
|
|
||||||
# TODO: "discount_reason": "extend"
|
# TODO: "discount_reason": extend, sale
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def price_displayed(self) -> int:
|
def price_displayed(self) -> int:
|
||||||
@@ -44,6 +44,12 @@ class Purchase(CollectionItemMixin):
|
|||||||
x.select_user_item(self.user)
|
x.select_user_item(self.user)
|
||||||
if x.amount >= 1:
|
if x.amount >= 1:
|
||||||
return 0
|
return 0
|
||||||
|
elif self.discount_reason == 'pick_ticket':
|
||||||
|
x = ItemFactory(self.c).get_item('pick_ticket')
|
||||||
|
x.item_id = 'pick_ticket'
|
||||||
|
x.select_user_item(self.user)
|
||||||
|
if x.amount >= 1:
|
||||||
|
return 0
|
||||||
return self.price
|
return self.price
|
||||||
return self.orig_price
|
return self.orig_price
|
||||||
|
|
||||||
@@ -60,7 +66,7 @@ class Purchase(CollectionItemMixin):
|
|||||||
if self.discount_from > 0 and self.discount_to > 0:
|
if self.discount_from > 0 and self.discount_to > 0:
|
||||||
r['discount_from'] = self.discount_from
|
r['discount_from'] = self.discount_from
|
||||||
r['discount_to'] = self.discount_to
|
r['discount_to'] = self.discount_to
|
||||||
if not show_real_price or (self.discount_reason == 'anni5tix' and price == 0):
|
if not show_real_price or (self.discount_reason in ('anni5tix', 'pick_ticket') and price == 0):
|
||||||
r['discount_reason'] = self.discount_reason
|
r['discount_reason'] = self.discount_reason
|
||||||
return r
|
return r
|
||||||
|
|
||||||
@@ -186,10 +192,10 @@ class Purchase(CollectionItemMixin):
|
|||||||
raise TicketNotEnough(
|
raise TicketNotEnough(
|
||||||
'The user does not have enough memories.', -6)
|
'The user does not have enough memories.', -6)
|
||||||
|
|
||||||
if not(self.orig_price == 0 or self.price == 0 and self.discount_from <= int(time() * 1000) <= self.discount_to):
|
if not (self.orig_price == 0 or self.price == 0 and self.discount_from <= int(time() * 1000) <= self.discount_to):
|
||||||
if price_used == 0:
|
if price_used == 0:
|
||||||
x = ItemFactory(self.c).get_item('anni5tix')
|
x = ItemFactory(self.c).get_item(self.discount_reason)
|
||||||
x.item_id = 'anni5tix'
|
x.item_id = self.discount_reason
|
||||||
x.amount = -1
|
x.amount = -1
|
||||||
x.user_claim_item(self.user)
|
x.user_claim_item(self.user)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ class UserPlay(UserScore):
|
|||||||
self.submission_hash: str = None
|
self.submission_hash: str = None
|
||||||
self.beyond_gauge: int = None
|
self.beyond_gauge: int = None
|
||||||
self.unrank_flag: bool = None
|
self.unrank_flag: bool = None
|
||||||
self.first_protect_flag: bool = None
|
self.new_best_protect_flag: bool = None
|
||||||
self.ptt: 'Potential' = None
|
self.ptt: 'Potential' = None
|
||||||
|
|
||||||
self.is_world_mode: bool = None
|
self.is_world_mode: bool = None
|
||||||
@@ -245,7 +245,7 @@ class UserPlay(UserScore):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def is_protected(self) -> bool:
|
def is_protected(self) -> bool:
|
||||||
return self.health == -1 or int(self.score) >= 9800000 or self.first_protect_flag
|
return self.health == -1 or int(self.score) >= 9800000 or self.new_best_protect_flag
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_valid(self) -> bool:
|
def is_valid(self) -> bool:
|
||||||
@@ -473,16 +473,17 @@ class UserPlay(UserScore):
|
|||||||
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty})
|
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty})
|
||||||
x = self.c.fetchone()
|
x = self.c.fetchone()
|
||||||
if not x:
|
if not x:
|
||||||
self.first_protect_flag = True # 初见保护
|
self.new_best_protect_flag = True # 初见保护
|
||||||
self.c.execute('''insert into best_score values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n)''', {
|
self.c.execute('''insert into best_score values(:a,:b,:c,:d,:e,:f,:g,:h,:i,:j,:k,:l,:m,:n)''', {
|
||||||
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty, 'd': self.score, 'e': self.shiny_perfect_count, 'f': self.perfect_count, 'g': self.near_count, 'h': self.miss_count, 'i': self.health, 'j': self.modifier, 'k': self.time_played, 'l': self.clear_type, 'm': self.clear_type, 'n': self.rating})
|
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty, 'd': self.score, 'e': self.shiny_perfect_count, 'f': self.perfect_count, 'g': self.near_count, 'h': self.miss_count, 'i': self.health, 'j': self.modifier, 'k': self.time_played, 'l': self.clear_type, 'm': self.clear_type, 'n': self.rating})
|
||||||
self.user.update_global_rank()
|
self.user.update_global_rank()
|
||||||
else:
|
else:
|
||||||
self.first_protect_flag = False
|
self.new_best_protect_flag = False
|
||||||
if self.song_state > self.get_song_state(int(x[1])): # best状态更新
|
if self.song_state > self.get_song_state(int(x[1])): # best状态更新
|
||||||
self.c.execute('''update best_score set best_clear_type = :a where user_id = :b and song_id = :c and difficulty = :d''', {
|
self.c.execute('''update best_score set best_clear_type = :a where user_id = :b and song_id = :c and difficulty = :d''', {
|
||||||
'a': self.clear_type, 'b': self.user.user_id, 'c': self.song.song_id, 'd': self.song.difficulty})
|
'a': self.clear_type, 'b': self.user.user_id, 'c': self.song.song_id, 'd': self.song.difficulty})
|
||||||
if self.score >= int(x[0]): # best成绩更新
|
if self.score >= int(x[0]): # best成绩更新
|
||||||
|
self.new_best_protect_flag = True
|
||||||
self.c.execute('''update best_score set score = :d, shiny_perfect_count = :e, perfect_count = :f, near_count = :g, miss_count = :h, health = :i, modifier = :j, clear_type = :k, rating = :l, time_played = :m where user_id = :a and song_id = :b and difficulty = :c ''', {
|
self.c.execute('''update best_score set score = :d, shiny_perfect_count = :e, perfect_count = :f, near_count = :g, miss_count = :h, health = :i, modifier = :j, clear_type = :k, rating = :l, time_played = :m 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, 'd': self.score, 'e': self.shiny_perfect_count, 'f': self.perfect_count, 'g': self.near_count, 'h': self.miss_count, 'i': self.health, 'j': self.modifier, 'k': self.clear_type, 'l': self.rating, 'm': self.time_played})
|
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty, 'd': self.score, 'e': self.shiny_perfect_count, 'f': self.perfect_count, 'g': self.near_count, 'h': self.miss_count, 'i': self.health, 'j': self.modifier, 'k': self.clear_type, 'l': self.rating, 'm': self.time_played})
|
||||||
self.user.update_global_rank()
|
self.user.update_global_rank()
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class Chart:
|
|||||||
|
|
||||||
def select(self) -> None:
|
def select(self) -> None:
|
||||||
self.c.execute(
|
self.c.execute(
|
||||||
'''select rating_pst, rating_prs, rating_ftr, rating_byn from chart where song_id=:a''', {'a': self.song_id})
|
'''select rating_pst, rating_prs, rating_ftr, rating_byn, rating_etr from chart where song_id=:a''', {'a': self.song_id})
|
||||||
x = self.c.fetchone()
|
x = self.c.fetchone()
|
||||||
if x is None:
|
if x is None:
|
||||||
if Config.ALLOW_SCORE_WITH_NO_SONG:
|
if Config.ALLOW_SCORE_WITH_NO_SONG:
|
||||||
@@ -63,11 +63,12 @@ class Song:
|
|||||||
self.song_id = x[0]
|
self.song_id = x[0]
|
||||||
self.name = x[1]
|
self.name = x[1]
|
||||||
self.charts = [Chart(self.c, self.song_id, 0), Chart(self.c, self.song_id, 1), Chart(
|
self.charts = [Chart(self.c, self.song_id, 0), Chart(self.c, self.song_id, 1), Chart(
|
||||||
self.c, self.song_id, 2), Chart(self.c, self.song_id, 3)]
|
self.c, self.song_id, 2), Chart(self.c, self.song_id, 3), Chart(self.c, self.song_id, 4)]
|
||||||
self.charts[0].defnum = x[2]
|
self.charts[0].defnum = x[2]
|
||||||
self.charts[1].defnum = x[3]
|
self.charts[1].defnum = x[3]
|
||||||
self.charts[2].defnum = x[4]
|
self.charts[2].defnum = x[4]
|
||||||
self.charts[3].defnum = x[5]
|
self.charts[3].defnum = x[5]
|
||||||
|
self.charts[4].defnum = x[6]
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def from_dict(self, d: dict) -> 'Song':
|
def from_dict(self, d: dict) -> 'Song':
|
||||||
@@ -89,11 +90,11 @@ class Song:
|
|||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
'''全部更新'''
|
'''全部更新'''
|
||||||
self.c.execute(
|
self.c.execute(
|
||||||
'''update chart set name=?, rating_pst=?, rating_prs=?, rating_ftr=?, rating_byn=? where song_id=?''', (self.name, self.charts[0].defnum, self.charts[1].defnum, self.charts[2].defnum, self.charts[3].defnum, self.song_id))
|
'''update chart set name=?, rating_pst=?, rating_prs=?, rating_ftr=?, rating_byn=?, rating_etr=? where song_id=?''', (self.name, self.charts[0].defnum, self.charts[1].defnum, self.charts[2].defnum, self.charts[3].defnum, self.charts[4].defnum, self.song_id))
|
||||||
|
|
||||||
def insert(self) -> None:
|
def insert(self) -> None:
|
||||||
self.c.execute(
|
self.c.execute(
|
||||||
'''insert into chart values (?,?,?,?,?,?)''', (self.song_id, self.name, self.charts[0].defnum, self.charts[1].defnum, self.charts[2].defnum, self.charts[3].defnum))
|
'''insert into chart values (?,?,?,?,?,?,?)''', (self.song_id, self.name, self.charts[0].defnum, self.charts[1].defnum, self.charts[2].defnum, self.charts[3].defnum, self.charts[4].defnum))
|
||||||
|
|
||||||
def select_exists(self, song_id: str = None) -> bool:
|
def select_exists(self, song_id: str = None) -> bool:
|
||||||
if song_id is not None:
|
if song_id is not None:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from .error import (ArcError, DataExist, FriendError, InputError, NoAccess,
|
|||||||
NoData, RateLimit, UserBan)
|
NoData, RateLimit, UserBan)
|
||||||
from .item import UserItemList
|
from .item import UserItemList
|
||||||
from .limiter import ArcLimiter
|
from .limiter import ArcLimiter
|
||||||
|
from .mission import UserMissionList
|
||||||
from .score import Score
|
from .score import Score
|
||||||
from .sql import Query, Sql
|
from .sql import Query, Sql
|
||||||
from .world import Map, UserMap, UserStamina
|
from .world import Map, UserMap, UserStamina
|
||||||
@@ -349,6 +350,13 @@ class UserInfo(User):
|
|||||||
|
|
||||||
return self.__packs
|
return self.__packs
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pick_ticket(self) -> int:
|
||||||
|
x = UserItemList(self.c, self).select_from_type('pick_ticket')
|
||||||
|
if not x.items:
|
||||||
|
return 0
|
||||||
|
return x.items[0].amount
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def world_unlocks(self) -> list:
|
def world_unlocks(self) -> list:
|
||||||
if self.__world_unlocks is None:
|
if self.__world_unlocks is None:
|
||||||
@@ -520,7 +528,9 @@ class UserInfo(User):
|
|||||||
'country': '',
|
'country': '',
|
||||||
'course_banners': self.course_banners,
|
'course_banners': self.course_banners,
|
||||||
'world_mode_locked_end_ts': self.world_mode_locked_end_ts,
|
'world_mode_locked_end_ts': self.world_mode_locked_end_ts,
|
||||||
'locked_char_ids': [] # [1]
|
'locked_char_ids': [], # [1]
|
||||||
|
'user_missions': UserMissionList(self.c, self).select_all().to_dict_list(),
|
||||||
|
'pick_ticket': self.pick_ticket
|
||||||
}
|
}
|
||||||
|
|
||||||
def from_list(self, x: list) -> 'UserInfo':
|
def from_list(self, x: list) -> 'UserInfo':
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class InitData:
|
|||||||
'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']
|
'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_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_kanae_uncap', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'skill_luin_uncap']
|
'', '', '', '', '', 'ayu_uncap', '', 'frags_yume', '', '', '', '', '', '', '', '', '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, 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]
|
||||||
@@ -30,13 +30,13 @@ class InitData:
|
|||||||
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]
|
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]
|
||||||
|
|
||||||
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, 85, 67, 88, 74, 0.5, 105, 80, 105, 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, 35, 85, 47, 50, 75, 80, 90, 80, 50, 51, 64, 100, 50, 58, 51, 40, 50, 80]
|
65, 85, 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]
|
||||||
|
|
||||||
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, 90, 93, 50, 96, 88, 99, 108, 85, 80, 50, 64, 55, 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]
|
80, 90, 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]
|
||||||
|
|
||||||
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, 95, 67, 84, 80, 88, 79, 80, 60, 80, 80, 63, 25, 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]
|
56, 73, 95, 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]
|
||||||
|
|
||||||
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, 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]
|
||||||
@@ -62,14 +62,15 @@ class InitData:
|
|||||||
66: [{'core_id': 'core_chunithm', 'amount': 15}],
|
66: [{'core_id': 'core_chunithm', 'amount': 15}],
|
||||||
5: [{'core_id': 'core_hollow', 'amount': 0}],
|
5: [{'core_id': 'core_hollow', 'amount': 0}],
|
||||||
73: [{'core_id': 'core_wacca', 'amount': 15}],
|
73: [{'core_id': 'core_wacca', 'amount': 15}],
|
||||||
30: [{'core_id': 'core_hollow', 'amount': 5}, {'core_id': 'core_sunset', 'amount': 25}]
|
30: [{'core_id': 'core_hollow', 'amount': 5}, {'core_id': 'core_sunset', 'amount': 25}],
|
||||||
|
34: [{'core_id': 'core_tanoc', 'amount': 15}],
|
||||||
}
|
}
|
||||||
|
|
||||||
cores = ['core_hollow', 'core_desolate', 'core_chunithm', 'core_crimson',
|
cores = ['core_hollow', 'core_desolate', 'core_chunithm', 'core_crimson',
|
||||||
'core_ambivalent', 'core_scarlet', 'core_groove', 'core_generic', 'core_binary', 'core_colorful', 'core_course_skip_purchase', 'core_umbral', 'core_wacca', 'core_sunset']
|
'core_ambivalent', 'core_scarlet', 'core_groove', 'core_generic', 'core_binary', 'core_colorful', 'core_course_skip_purchase', 'core_umbral', 'core_wacca', 'core_sunset', 'core_tanoc']
|
||||||
|
|
||||||
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']
|
"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']
|
||||||
|
|
||||||
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"]
|
||||||
|
|||||||
@@ -1612,5 +1612,77 @@
|
|||||||
],
|
],
|
||||||
"orig_price": 100,
|
"orig_price": 100,
|
||||||
"price": 100
|
"price": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ionostream",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "single",
|
||||||
|
"id": "ionostream",
|
||||||
|
"is_available": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "core",
|
||||||
|
"amount": 1,
|
||||||
|
"id": "core_generic",
|
||||||
|
"is_available": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "masqueradelegion",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "single",
|
||||||
|
"id": "masqueradelegion",
|
||||||
|
"is_available": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "core",
|
||||||
|
"amount": 1,
|
||||||
|
"id": "core_generic",
|
||||||
|
"is_available": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "kyorenromance",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "single",
|
||||||
|
"id": "kyorenromance",
|
||||||
|
"is_available": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "core",
|
||||||
|
"amount": 1,
|
||||||
|
"id": "core_generic",
|
||||||
|
"is_available": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "qovat",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "single",
|
||||||
|
"id": "qovat",
|
||||||
|
"is_available": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "core",
|
||||||
|
"amount": 1,
|
||||||
|
"id": "core_generic",
|
||||||
|
"is_available": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"orig_price": 100,
|
||||||
|
"price": 100
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -241,10 +241,11 @@ primary key(present_id, item_id, type)
|
|||||||
);
|
);
|
||||||
create table if not exists chart(song_id text primary key,
|
create table if not exists chart(song_id text primary key,
|
||||||
name text,
|
name text,
|
||||||
rating_pst int,
|
rating_pst int default -1,
|
||||||
rating_prs int,
|
rating_prs int default -1,
|
||||||
rating_ftr int,
|
rating_ftr int default -1,
|
||||||
rating_byn int
|
rating_byn int default -1,
|
||||||
|
rating_etr int default -1
|
||||||
);
|
);
|
||||||
create table if not exists redeem(code text primary key,
|
create table if not exists redeem(code text primary key,
|
||||||
type int
|
type int
|
||||||
@@ -311,6 +312,12 @@ type text,
|
|||||||
amount int,
|
amount int,
|
||||||
primary key(course_id, item_id, type)
|
primary key(course_id, item_id, type)
|
||||||
);
|
);
|
||||||
|
create table if not exists user_mission(
|
||||||
|
user_id int,
|
||||||
|
mission_id text,
|
||||||
|
status int,
|
||||||
|
primary key(user_id, mission_id)
|
||||||
|
);
|
||||||
|
|
||||||
create index if not exists best_score_1 on best_score (song_id, difficulty);
|
create index if not exists best_score_1 on best_score (song_id, difficulty);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
flask>=2.0.2
|
flask>=2.0.2
|
||||||
cryptography>=3.0.0
|
cryptography>=35.0.0
|
||||||
limits>=2.7.0
|
limits>=2.7.0
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from flask import Blueprint, jsonify
|
|||||||
from core.config_manager import Config
|
from core.config_manager import Config
|
||||||
|
|
||||||
from . import (auth, course, friend, multiplayer, others, present, purchase,
|
from . import (auth, course, friend, multiplayer, others, present, purchase,
|
||||||
score, user, world)
|
score, user, world, mission)
|
||||||
|
|
||||||
|
|
||||||
__bp_old = Blueprint('old_server', __name__)
|
__bp_old = Blueprint('old_server', __name__)
|
||||||
@@ -24,7 +24,7 @@ def get_bps():
|
|||||||
|
|
||||||
bp = Blueprint('server', __name__)
|
bp = Blueprint('server', __name__)
|
||||||
list(map(bp.register_blueprint, [user.bp, auth.bp, friend.bp, score.bp,
|
list(map(bp.register_blueprint, [user.bp, auth.bp, friend.bp, score.bp,
|
||||||
world.bp, purchase.bp, present.bp, others.bp, multiplayer.bp, course.bp]))
|
world.bp, purchase.bp, present.bp, others.bp, multiplayer.bp, course.bp, mission.bp]))
|
||||||
|
|
||||||
bps = [Blueprint(x, __name__, url_prefix=x)
|
bps = [Blueprint(x, __name__, url_prefix=x)
|
||||||
for x in string_to_list(Config.GAME_API_PREFIX)]
|
for x in string_to_list(Config.GAME_API_PREFIX)]
|
||||||
|
|||||||
68
latest version/server/mission.py
Normal file
68
latest version/server/mission.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
from flask import Blueprint, request
|
||||||
|
|
||||||
|
from core.error import NoData
|
||||||
|
from core.mission import MISSION_DICT
|
||||||
|
from core.sql import Connect
|
||||||
|
from core.user import UserOnline
|
||||||
|
|
||||||
|
from .auth import auth_required
|
||||||
|
from .func import arc_try, success_return
|
||||||
|
|
||||||
|
bp = Blueprint('mission', __name__, url_prefix='/mission')
|
||||||
|
|
||||||
|
|
||||||
|
def parse_mission_form(multidict) -> list:
|
||||||
|
r = []
|
||||||
|
|
||||||
|
x = multidict.get('mission_1')
|
||||||
|
i = 1
|
||||||
|
while x:
|
||||||
|
r.append(x)
|
||||||
|
x = multidict.get(f'mission_{i + 1}')
|
||||||
|
i += 1
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/me/clear', methods=['POST']) # 新手任务确认完成
|
||||||
|
@auth_required(request)
|
||||||
|
@arc_try
|
||||||
|
def mission_clear(user_id):
|
||||||
|
m = parse_mission_form(request.form)
|
||||||
|
r = []
|
||||||
|
for i, mission_id in enumerate(m):
|
||||||
|
if mission_id not in MISSION_DICT:
|
||||||
|
return NoData(f'Mission `{mission_id}` not found')
|
||||||
|
with Connect() as c:
|
||||||
|
x = MISSION_DICT[mission_id](c)
|
||||||
|
x.user_clear_mission(UserOnline(c, user_id))
|
||||||
|
d = x.to_dict()
|
||||||
|
d['request_id'] = i + 1
|
||||||
|
r.append(d)
|
||||||
|
|
||||||
|
return success_return({'missions': r})
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/me/claim', methods=['POST']) # 领取新手任务奖励
|
||||||
|
@auth_required(request)
|
||||||
|
@arc_try
|
||||||
|
def mission_claim(user_id):
|
||||||
|
m = parse_mission_form(request.form)
|
||||||
|
r = []
|
||||||
|
|
||||||
|
with Connect() as c:
|
||||||
|
user = UserOnline(c, user_id)
|
||||||
|
|
||||||
|
for i, mission_id in enumerate(m):
|
||||||
|
if mission_id not in MISSION_DICT:
|
||||||
|
return NoData(f'Mission `{mission_id}` not found')
|
||||||
|
|
||||||
|
x = MISSION_DICT[mission_id](c)
|
||||||
|
x.user_claim_mission(user)
|
||||||
|
d = x.to_dict(has_items=True)
|
||||||
|
d['request_id'] = i + 1
|
||||||
|
r.append(d)
|
||||||
|
|
||||||
|
return success_return({
|
||||||
|
'missions': r,
|
||||||
|
'user': user.to_dict()
|
||||||
|
})
|
||||||
@@ -13,7 +13,7 @@ from core.user import UserOnline
|
|||||||
from .auth import auth_required
|
from .auth import auth_required
|
||||||
from .func import arc_try, error_return, success_return
|
from .func import arc_try, error_return, success_return
|
||||||
from .present import present_info
|
from .present import present_info
|
||||||
from .purchase import bundle_bundle, bundle_pack
|
from .purchase import bundle_bundle, get_single, bundle_pack
|
||||||
from .score import song_score_friend
|
from .score import song_score_friend
|
||||||
from .user import user_me
|
from .user import user_me
|
||||||
from .world import world_all
|
from .world import world_all
|
||||||
@@ -26,6 +26,28 @@ def game_info():
|
|||||||
return success_return(GameInfo().to_dict())
|
return success_return(GameInfo().to_dict())
|
||||||
|
|
||||||
|
|
||||||
|
# @bp.route('/game/content_bundle', methods=['GET']) # 热更新
|
||||||
|
# def game_content_bundle():
|
||||||
|
# app_version = request.headers.get('AppVersion')
|
||||||
|
# bundle_version = request.headers.get('ContentBundle')
|
||||||
|
# import os
|
||||||
|
# if bundle_version != '5.4.0':
|
||||||
|
# r = {'orderedResults': [
|
||||||
|
# {
|
||||||
|
# 'appVersion': '5.4.0',
|
||||||
|
# 'contentBundleVersion': '5.4.0',
|
||||||
|
# 'jsonUrl': 'http://192.168.0.110/bundle_download/bundle.json',
|
||||||
|
# 'jsonSize': os.path.getsize('./database/bundle/bundle.json'),
|
||||||
|
# 'bundleUrl': 'http://192.168.0.110/bundle_download/bundle',
|
||||||
|
# 'bundleSize': os.path.getsize('./database/bundle/bundle')
|
||||||
|
# },
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# else:
|
||||||
|
# r = {}
|
||||||
|
# return success_return(r)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/serve/download/me/song', methods=['GET']) # 歌曲下载
|
@bp.route('/serve/download/me/song', methods=['GET']) # 歌曲下载
|
||||||
@auth_required(request)
|
@auth_required(request)
|
||||||
@arc_try
|
@arc_try
|
||||||
@@ -66,15 +88,18 @@ def applog_me():
|
|||||||
return success_return({})
|
return success_return({})
|
||||||
|
|
||||||
|
|
||||||
map_dict = {'/user/me': user_me,
|
map_dict = {
|
||||||
'/purchase/bundle/pack': bundle_pack,
|
'/user/me': user_me,
|
||||||
'/serve/download/me/song': download_song,
|
'/purchase/bundle/pack': bundle_pack,
|
||||||
'/game/info': game_info,
|
'/serve/download/me/song': download_song,
|
||||||
'/present/me': present_info,
|
'/game/info': game_info,
|
||||||
'/world/map/me': world_all,
|
'/present/me': present_info,
|
||||||
'/score/song/friend': song_score_friend,
|
'/world/map/me': world_all,
|
||||||
'/purchase/bundle/bundle': bundle_bundle,
|
'/score/song/friend': song_score_friend,
|
||||||
'/finale/progress': finale_progress}
|
'/purchase/bundle/bundle': bundle_bundle,
|
||||||
|
'/finale/progress': finale_progress,
|
||||||
|
'/purchase/bundle/single': get_single
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/compose/aggregate', methods=['GET']) # 集成式请求
|
@bp.route('/compose/aggregate', methods=['GET']) # 集成式请求
|
||||||
|
|||||||
@@ -173,6 +173,12 @@ input[type=submit] {
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.difficulty_etr {
|
||||||
|
font-size: 0.9em;
|
||||||
|
background-color: rgb(161, 132, 181);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.rank {
|
.rank {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
|
|||||||
@@ -34,6 +34,11 @@
|
|||||||
<span class="difficulty_byd">BYD</span>
|
<span class="difficulty_byd">BYD</span>
|
||||||
<span class="song-rating">{{song['rating_byn']}}</span>
|
<span class="song-rating">{{song['rating_byn']}}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<br />
|
||||||
|
{% if song['rating_etr'] %}
|
||||||
|
<span class="difficulty_etr">ETR</span>
|
||||||
|
<span class="song-rating">{{song['rating_etr']}}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
<option value='fragment'>Fragment</option>
|
<option value='fragment'>Fragment</option>
|
||||||
<option value='memory'>Memory</option>
|
<option value='memory'>Memory</option>
|
||||||
<option value='anni5tix'>Anniversary 5 ticket</option>
|
<option value='anni5tix'>Anniversary 5 ticket</option>
|
||||||
|
<option value='pick_ticket'>Pick ticket</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<label for="amount">Amount</label>
|
<label for="amount">Amount</label>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
<option value='fragment'>Fragment</option>
|
<option value='fragment'>Fragment</option>
|
||||||
<option value='memory'>Memory</option>
|
<option value='memory'>Memory</option>
|
||||||
<option value='anni5tix'>Anniversary 5 ticket</option>
|
<option value='anni5tix'>Anniversary 5 ticket</option>
|
||||||
|
<option value='pick_ticket'>Pick ticket</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<label for="amount">Amount</label>
|
<label for="amount">Amount</label>
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
<input name="rating_ftr" id="rating_ftr" required>
|
<input name="rating_ftr" id="rating_ftr" required>
|
||||||
<label for="rating_byd">Beyond chart const</label>
|
<label for="rating_byd">Beyond chart const</label>
|
||||||
<input name="rating_byd" id="rating_byd" required>
|
<input name="rating_byd" id="rating_byd" required>
|
||||||
|
<label for="rating_etr">Eternal chart const</label>
|
||||||
|
<input name="rating_etr" id="rating_etr" required>
|
||||||
<div class="content">如果没有某个谱面,应该填入-1。</div>
|
<div class="content">如果没有某个谱面,应该填入-1。</div>
|
||||||
<div class="content">If there is no some chart, fill in -1 please.</div>
|
<div class="content">If there is no some chart, fill in -1 please.</div>
|
||||||
<input type="submit" value="Add">
|
<input type="submit" value="Add">
|
||||||
|
|||||||
@@ -191,13 +191,15 @@ def all_song():
|
|||||||
if x:
|
if x:
|
||||||
posts = []
|
posts = []
|
||||||
for i in x:
|
for i in x:
|
||||||
posts.append({'song_id': i[0],
|
posts.append({
|
||||||
'name_en': i[1],
|
'song_id': i[0],
|
||||||
'rating_pst': defnum(i[2]),
|
'name_en': i[1],
|
||||||
'rating_prs': defnum(i[3]),
|
'rating_pst': defnum(i[2]),
|
||||||
'rating_ftr': defnum(i[4]),
|
'rating_prs': defnum(i[3]),
|
||||||
'rating_byn': defnum(i[5])
|
'rating_ftr': defnum(i[4]),
|
||||||
})
|
'rating_byn': defnum(i[5]),
|
||||||
|
'rating_etr': defnum(i[6])
|
||||||
|
})
|
||||||
else:
|
else:
|
||||||
error = '没有谱面数据 No song data.'
|
error = '没有谱面数据 No song data.'
|
||||||
|
|
||||||
@@ -335,6 +337,7 @@ def add_song():
|
|||||||
rating_prs = get_rating(request.form['rating_prs'])
|
rating_prs = get_rating(request.form['rating_prs'])
|
||||||
rating_ftr = get_rating(request.form['rating_ftr'])
|
rating_ftr = get_rating(request.form['rating_ftr'])
|
||||||
rating_byd = get_rating(request.form['rating_byd'])
|
rating_byd = get_rating(request.form['rating_byd'])
|
||||||
|
rating_etr = get_rating(request.form['rating_etr'])
|
||||||
if len(song_id) >= 256:
|
if len(song_id) >= 256:
|
||||||
song_id = song_id[:200]
|
song_id = song_id[:200]
|
||||||
if len(name_en) >= 256:
|
if len(name_en) >= 256:
|
||||||
@@ -344,8 +347,8 @@ def add_song():
|
|||||||
c.execute(
|
c.execute(
|
||||||
'''select exists(select * from chart where song_id=:a)''', {'a': song_id})
|
'''select exists(select * from chart where song_id=:a)''', {'a': song_id})
|
||||||
if c.fetchone() == (0,):
|
if c.fetchone() == (0,):
|
||||||
c.execute('''insert into chart values(:a,:b,:c,:d,:e,:f)''', {
|
c.execute('''insert into chart values(:a,:b,:c,:d,:e,:f,:g)''', {
|
||||||
'a': song_id, 'b': name_en, 'c': rating_pst, 'd': rating_prs, 'e': rating_ftr, 'f': rating_byd})
|
'a': song_id, 'b': name_en, 'c': rating_pst, 'd': rating_prs, 'e': rating_ftr, 'f': rating_byd, 'g': rating_etr})
|
||||||
flash('歌曲添加成功 Successfully add the song.')
|
flash('歌曲添加成功 Successfully add the song.')
|
||||||
else:
|
else:
|
||||||
error = '歌曲已存在 The song exists.'
|
error = '歌曲已存在 The song exists.'
|
||||||
@@ -422,7 +425,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']
|
'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']
|
||||||
return render_template('web/changechar.html', skill_ids=skill_ids)
|
return render_template('web/changechar.html', skill_ids=skill_ids)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user