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:
@@ -50,12 +50,14 @@ This procedure is mainly used for study and research, and shall not be used for
|
||||
- 下载频次限制 Download rate limit
|
||||
- 购买系统 Purchase system
|
||||
- 单曲和曲包 Single & Pack
|
||||
- :x: 捆绑包 Bundle
|
||||
- :x: 捆绑包 Pack bundle
|
||||
- 折扣 Discount
|
||||
- 五周年兑换券 5-th anniversary ticket
|
||||
- 单曲兑换券 Pick ticket
|
||||
- :x: Extend 包自动降价 Extend pack automatic price reduction
|
||||
- 奖励系统 Present system
|
||||
- 兑换码系统 Redeem code system
|
||||
- 新手任务 Missions
|
||||
- 角色系统 Character system
|
||||
- 数据记录 Data recording
|
||||
- 用户成绩 Users' scores
|
||||
@@ -117,7 +119,7 @@ It is just so interesting. What it can do is under exploration.
|
||||
- Windows / Linux / Mac OS / Android...
|
||||
- Python >= 3.6
|
||||
- Flask >= 2.0
|
||||
- Cryptography >= 3.0.0
|
||||
- Cryptography >= 35.0.0
|
||||
- limits >= 2.7.0
|
||||
- Charles, IDA, proxy app... (optional)
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ def songs_get(data, user):
|
||||
'''查询全歌曲信息'''
|
||||
A = ['song_id', 'name']
|
||||
B = ['song_id', 'name', 'rating_pst',
|
||||
'rating_prs', 'rating_ftr', 'rating_byn']
|
||||
'rating_prs', 'rating_ftr', 'rating_byn', 'rating_etr']
|
||||
with Connect() as c:
|
||||
query = Query(A, A, B).from_dict(data)
|
||||
x = Sql(c).select('chart', query=query)
|
||||
@@ -97,8 +97,8 @@ def songs_post(data, user):
|
||||
@api_try
|
||||
def songs_song_difficulty_rank_get(data, user, song_id, difficulty):
|
||||
'''查询歌曲某个难度的成绩排行榜,和游戏内接口相似,只允许limit'''
|
||||
if difficulty not in [0, 1, 2, 3]:
|
||||
raise InputError('Difficulty must be 0, 1, 2 or 3')
|
||||
if difficulty not in [0, 1, 2, 3, 4]:
|
||||
raise InputError('Difficulty must be 0, 1, 2, 3 or 4')
|
||||
limit = data.get('limit', 20)
|
||||
if not isinstance(limit, int):
|
||||
raise InputError('Limit must be int')
|
||||
|
||||
@@ -12,7 +12,7 @@ class Config:
|
||||
|
||||
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]
|
||||
|
||||
ALLOW_APPVERSION = [] # list[str]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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'
|
||||
|
||||
|
||||
|
||||
@@ -92,6 +92,8 @@ class DatabaseInit:
|
||||
('memory', 'memory', 1))
|
||||
self.c.execute('''insert into item values(?,?,?)''',
|
||||
('anni5tix', 'anni5tix', 1))
|
||||
self.c.execute('''insert into item values(?,?,?)''',
|
||||
('pick_ticket', 'pick_ticket', 1))
|
||||
|
||||
with open(self.pack_path, 'rb') as f:
|
||||
self.insert_purchase_item(load(f))
|
||||
@@ -99,6 +101,9 @@ class DatabaseInit:
|
||||
with open(self.single_path, 'rb') as f:
|
||||
self.insert_purchase_item(load(f))
|
||||
|
||||
self.c.execute('''insert into item values(?,?,?)''', # 新手任务奖励曲
|
||||
('innocence', 'world_song', 1))
|
||||
|
||||
def course_init(self) -> None:
|
||||
'''初始化课题信息'''
|
||||
courses = []
|
||||
|
||||
@@ -89,7 +89,7 @@ class UserItem(Item):
|
||||
|
||||
|
||||
class NormalItem(UserItem):
|
||||
def __init__(self, c) -> None:
|
||||
def __init__(self, c=None) -> None:
|
||||
super().__init__()
|
||||
self.c = c
|
||||
|
||||
@@ -115,7 +115,7 @@ class NormalItem(UserItem):
|
||||
|
||||
|
||||
class PositiveItem(UserItem):
|
||||
def __init__(self, c) -> None:
|
||||
def __init__(self, c=None) -> None:
|
||||
super().__init__()
|
||||
self.c = c
|
||||
|
||||
@@ -142,7 +142,7 @@ class PositiveItem(UserItem):
|
||||
class ItemCore(PositiveItem):
|
||||
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)
|
||||
self.is_available = True
|
||||
self.item_id = core_type
|
||||
@@ -220,10 +220,12 @@ class Memory(UserItem):
|
||||
class Fragment(UserItem):
|
||||
item_type = 'fragment'
|
||||
|
||||
def __init__(self, c) -> None:
|
||||
def __init__(self, c=None, amount=0) -> None:
|
||||
super().__init__()
|
||||
self.c = c
|
||||
self.is_available = True
|
||||
self.item_id = self.item_type
|
||||
self.amount = amount
|
||||
|
||||
def user_claim_item(self, user):
|
||||
pass
|
||||
@@ -238,12 +240,24 @@ class Anni5tix(PositiveItem):
|
||||
def __init__(self, c) -> None:
|
||||
super().__init__(c)
|
||||
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):
|
||||
item_type = 'world_song'
|
||||
|
||||
def __init__(self, c) -> None:
|
||||
def __init__(self, c=None) -> None:
|
||||
super().__init__(c)
|
||||
self.is_available = True
|
||||
|
||||
@@ -293,8 +307,10 @@ class ProgBoost(UserItem):
|
||||
class Stamina6(UserItem):
|
||||
item_type = 'stamina6'
|
||||
|
||||
def __init__(self, c) -> None:
|
||||
def __init__(self, c=None) -> None:
|
||||
super().__init__(c)
|
||||
self.item_id = 'stamina6'
|
||||
self.amount = 1
|
||||
|
||||
def user_claim_item(self, user):
|
||||
'''
|
||||
@@ -307,6 +323,23 @@ class Stamina6(UserItem):
|
||||
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:
|
||||
def __init__(self, c=None) -> None:
|
||||
self.c = c
|
||||
@@ -324,6 +357,8 @@ class ItemFactory:
|
||||
return Memory(self.c)
|
||||
elif item_type == 'anni5tix':
|
||||
return Anni5tix(self.c)
|
||||
elif item_type == 'pick_ticket':
|
||||
return PickTicket(self.c)
|
||||
elif item_type == 'world_song':
|
||||
return WorldSong(self.c)
|
||||
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 = []
|
||||
|
||||
# TODO: "discount_reason": "extend"
|
||||
# TODO: "discount_reason": extend, sale
|
||||
|
||||
@property
|
||||
def price_displayed(self) -> int:
|
||||
@@ -44,6 +44,12 @@ class Purchase(CollectionItemMixin):
|
||||
x.select_user_item(self.user)
|
||||
if x.amount >= 1:
|
||||
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.orig_price
|
||||
|
||||
@@ -60,7 +66,7 @@ class Purchase(CollectionItemMixin):
|
||||
if self.discount_from > 0 and self.discount_to > 0:
|
||||
r['discount_from'] = self.discount_from
|
||||
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
|
||||
return r
|
||||
|
||||
@@ -188,8 +194,8 @@ class Purchase(CollectionItemMixin):
|
||||
|
||||
if not (self.orig_price == 0 or self.price == 0 and self.discount_from <= int(time() * 1000) <= self.discount_to):
|
||||
if price_used == 0:
|
||||
x = ItemFactory(self.c).get_item('anni5tix')
|
||||
x.item_id = 'anni5tix'
|
||||
x = ItemFactory(self.c).get_item(self.discount_reason)
|
||||
x.item_id = self.discount_reason
|
||||
x.amount = -1
|
||||
x.user_claim_item(self.user)
|
||||
else:
|
||||
|
||||
@@ -207,7 +207,7 @@ class UserPlay(UserScore):
|
||||
self.submission_hash: str = None
|
||||
self.beyond_gauge: int = None
|
||||
self.unrank_flag: bool = None
|
||||
self.first_protect_flag: bool = None
|
||||
self.new_best_protect_flag: bool = None
|
||||
self.ptt: 'Potential' = None
|
||||
|
||||
self.is_world_mode: bool = None
|
||||
@@ -245,7 +245,7 @@ class UserPlay(UserScore):
|
||||
|
||||
@property
|
||||
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
|
||||
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})
|
||||
x = self.c.fetchone()
|
||||
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)''', {
|
||||
'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()
|
||||
else:
|
||||
self.first_protect_flag = False
|
||||
self.new_best_protect_flag = False
|
||||
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''', {
|
||||
'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成绩更新
|
||||
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 ''', {
|
||||
'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()
|
||||
|
||||
@@ -33,7 +33,7 @@ class Chart:
|
||||
|
||||
def select(self) -> None:
|
||||
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()
|
||||
if x is None:
|
||||
if Config.ALLOW_SCORE_WITH_NO_SONG:
|
||||
@@ -63,11 +63,12 @@ class Song:
|
||||
self.song_id = x[0]
|
||||
self.name = x[1]
|
||||
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[1].defnum = x[3]
|
||||
self.charts[2].defnum = x[4]
|
||||
self.charts[3].defnum = x[5]
|
||||
self.charts[4].defnum = x[6]
|
||||
return self
|
||||
|
||||
def from_dict(self, d: dict) -> 'Song':
|
||||
@@ -89,11 +90,11 @@ class Song:
|
||||
def update(self) -> None:
|
||||
'''全部更新'''
|
||||
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:
|
||||
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:
|
||||
if song_id is not None:
|
||||
|
||||
@@ -11,6 +11,7 @@ from .error import (ArcError, DataExist, FriendError, InputError, NoAccess,
|
||||
NoData, RateLimit, UserBan)
|
||||
from .item import UserItemList
|
||||
from .limiter import ArcLimiter
|
||||
from .mission import UserMissionList
|
||||
from .score import Score
|
||||
from .sql import Query, Sql
|
||||
from .world import Map, UserMap, UserStamina
|
||||
@@ -349,6 +350,13 @@ class UserInfo(User):
|
||||
|
||||
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
|
||||
def world_unlocks(self) -> list:
|
||||
if self.__world_unlocks is None:
|
||||
@@ -520,7 +528,9 @@ class UserInfo(User):
|
||||
'country': '',
|
||||
'course_banners': self.course_banners,
|
||||
'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':
|
||||
|
||||
@@ -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']
|
||||
|
||||
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,
|
||||
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]
|
||||
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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}],
|
||||
5: [{'core_id': 'core_hollow', 'amount': 0}],
|
||||
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',
|
||||
'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",
|
||||
"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",
|
||||
"scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6", "scenery_chap7", "scenery_beyond"]
|
||||
|
||||
@@ -1612,5 +1612,77 @@
|
||||
],
|
||||
"orig_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,
|
||||
name text,
|
||||
rating_pst int,
|
||||
rating_prs int,
|
||||
rating_ftr int,
|
||||
rating_byn int
|
||||
rating_pst int default -1,
|
||||
rating_prs int default -1,
|
||||
rating_ftr int default -1,
|
||||
rating_byn int default -1,
|
||||
rating_etr int default -1
|
||||
);
|
||||
create table if not exists redeem(code text primary key,
|
||||
type int
|
||||
@@ -311,6 +312,12 @@ type text,
|
||||
amount int,
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
flask>=2.0.2
|
||||
cryptography>=3.0.0
|
||||
cryptography>=35.0.0
|
||||
limits>=2.7.0
|
||||
|
||||
@@ -3,7 +3,7 @@ from flask import Blueprint, jsonify
|
||||
from core.config_manager import Config
|
||||
|
||||
from . import (auth, course, friend, multiplayer, others, present, purchase,
|
||||
score, user, world)
|
||||
score, user, world, mission)
|
||||
|
||||
|
||||
__bp_old = Blueprint('old_server', __name__)
|
||||
@@ -24,7 +24,7 @@ def get_bps():
|
||||
|
||||
bp = Blueprint('server', __name__)
|
||||
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)
|
||||
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 .func import arc_try, error_return, success_return
|
||||
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 .user import user_me
|
||||
from .world import world_all
|
||||
@@ -26,6 +26,28 @@ def game_info():
|
||||
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']) # 歌曲下载
|
||||
@auth_required(request)
|
||||
@arc_try
|
||||
@@ -66,7 +88,8 @@ def applog_me():
|
||||
return success_return({})
|
||||
|
||||
|
||||
map_dict = {'/user/me': user_me,
|
||||
map_dict = {
|
||||
'/user/me': user_me,
|
||||
'/purchase/bundle/pack': bundle_pack,
|
||||
'/serve/download/me/song': download_song,
|
||||
'/game/info': game_info,
|
||||
@@ -74,7 +97,9 @@ map_dict = {'/user/me': user_me,
|
||||
'/world/map/me': world_all,
|
||||
'/score/song/friend': song_score_friend,
|
||||
'/purchase/bundle/bundle': bundle_bundle,
|
||||
'/finale/progress': finale_progress}
|
||||
'/finale/progress': finale_progress,
|
||||
'/purchase/bundle/single': get_single
|
||||
}
|
||||
|
||||
|
||||
@bp.route('/compose/aggregate', methods=['GET']) # 集成式请求
|
||||
|
||||
@@ -173,6 +173,12 @@ input[type=submit] {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.difficulty_etr {
|
||||
font-size: 0.9em;
|
||||
background-color: rgb(161, 132, 181);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.rank {
|
||||
font-size: 0.8em;
|
||||
margin-left: 4px;
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
<span class="difficulty_byd">BYD</span>
|
||||
<span class="song-rating">{{song['rating_byn']}}</span>
|
||||
{% endif %}
|
||||
<br />
|
||||
{% if song['rating_etr'] %}
|
||||
<span class="difficulty_etr">ETR</span>
|
||||
<span class="song-rating">{{song['rating_etr']}}</span>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<option value='fragment'>Fragment</option>
|
||||
<option value='memory'>Memory</option>
|
||||
<option value='anni5tix'>Anniversary 5 ticket</option>
|
||||
<option value='pick_ticket'>Pick ticket</option>
|
||||
</select>
|
||||
</div>
|
||||
<label for="amount">Amount</label>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<option value='fragment'>Fragment</option>
|
||||
<option value='memory'>Memory</option>
|
||||
<option value='anni5tix'>Anniversary 5 ticket</option>
|
||||
<option value='pick_ticket'>Pick ticket</option>
|
||||
</select>
|
||||
</div>
|
||||
<label for="amount">Amount</label>
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
<input name="rating_ftr" id="rating_ftr" required>
|
||||
<label for="rating_byd">Beyond chart const</label>
|
||||
<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">If there is no some chart, fill in -1 please.</div>
|
||||
<input type="submit" value="Add">
|
||||
|
||||
@@ -191,12 +191,14 @@ def all_song():
|
||||
if x:
|
||||
posts = []
|
||||
for i in x:
|
||||
posts.append({'song_id': i[0],
|
||||
posts.append({
|
||||
'song_id': i[0],
|
||||
'name_en': i[1],
|
||||
'rating_pst': defnum(i[2]),
|
||||
'rating_prs': defnum(i[3]),
|
||||
'rating_ftr': defnum(i[4]),
|
||||
'rating_byn': defnum(i[5])
|
||||
'rating_byn': defnum(i[5]),
|
||||
'rating_etr': defnum(i[6])
|
||||
})
|
||||
else:
|
||||
error = '没有谱面数据 No song data.'
|
||||
@@ -335,6 +337,7 @@ def add_song():
|
||||
rating_prs = get_rating(request.form['rating_prs'])
|
||||
rating_ftr = get_rating(request.form['rating_ftr'])
|
||||
rating_byd = get_rating(request.form['rating_byd'])
|
||||
rating_etr = get_rating(request.form['rating_etr'])
|
||||
if len(song_id) >= 256:
|
||||
song_id = song_id[:200]
|
||||
if len(name_en) >= 256:
|
||||
@@ -344,8 +347,8 @@ def add_song():
|
||||
c.execute(
|
||||
'''select exists(select * from chart where song_id=:a)''', {'a': song_id})
|
||||
if c.fetchone() == (0,):
|
||||
c.execute('''insert into chart values(:a,:b,:c,:d,:e,:f)''', {
|
||||
'a': song_id, 'b': name_en, 'c': rating_pst, 'd': rating_prs, 'e': rating_ftr, 'f': rating_byd})
|
||||
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, 'g': rating_etr})
|
||||
flash('歌曲添加成功 Successfully add the song.')
|
||||
else:
|
||||
error = '歌曲已存在 The song exists.'
|
||||
@@ -422,7 +425,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', '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)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user