[Enhance] API for presents & character values

- Add API endpoints for presents
- Change character value algorithm
- Update character values (I forgot in v2.10.3)
This commit is contained in:
Lost-MSth
2023-02-10 18:15:53 +08:00
parent 6f39274b99
commit 7ece2598d1
8 changed files with 267 additions and 47 deletions

View File

@@ -70,16 +70,24 @@ class CharacterValue:
self.set_parameter(start, mid, end)
@staticmethod
def _calc_char_value_20(level, stata, statb, lva=1, lvb=20):
# 计算1~20级搭档数值的核心函数返回浮点数来自https://redive.estertion.win/arcaea/calc/
n = [0, 0, 0.0005831753900000081, 0.004665403120000065, 0.015745735529959858, 0.03732322495992008, 0.07289692374980007, 0.12596588423968, 0.2000291587694801, 0.29858579967923987, 0.42513485930893946,
0.5748651406910605, 0.7014142003207574, 0.7999708412305152, 0.8740341157603029, 0.9271030762501818, 0.962676775040091, 0.9842542644700301, 0.9953345968799998, 0.9994168246100001, 1]
e = n[lva] - n[lvb]
a = stata - statb
r = a / e
d = stata - n[lva] * r
def _calc_char_value_20_math(level: int, value_1: float, value_20: float) -> float:
# by Lost-MSth
# 4/6859 = 0.00058317539
if level <= 10:
return 0.00058317539 * (level - 1) ** 3 * (value_20 - value_1) + value_1
else:
return - 0.00058317539 * (20 - level) ** 3 * (value_20 - value_1) + value_20
return d + r * n[level]
# @staticmethod
# def _calc_char_value_20(level: int, stata, statb, lva=1, lvb=20) -> float:
# # 计算1~20级搭档数值的核心函数返回浮点数来自https://redive.estertion.win/arcaea/calc/
# n = [0, 0, 0.0005831753900000081, 0.004665403120000065, 0.015745735529959858, 0.03732322495992008, 0.07289692374980007, 0.12596588423968, 0.2000291587694801, 0.29858579967923987, 0.42513485930893946,
# 0.5748651406910605, 0.7014142003207574, 0.7999708412305152, 0.8740341157603029, 0.9271030762501818, 0.962676775040091, 0.9842542644700301, 0.9953345968799998, 0.9994168246100001, 1]
# e = n[lva] - n[lvb]
# a = stata - statb
# r = a / e
# d = stata - n[lva] * r
# return d + r * n[level]
@staticmethod
def _calc_char_value_30(level, stata, statb, lva=20, lvb=30):
@@ -93,7 +101,7 @@ class CharacterValue:
def get_value(self, level: Level):
if level.min_level <= level.level <= level.mid_level:
return self._calc_char_value_20(level.level, self.start, self.mid)
return self._calc_char_value_20_math(level.level, self.start, self.mid)
elif level.mid_level < level.level <= level.max_level:
return self._calc_char_value_30(level.level, self.mid, self.end)
else:
@@ -137,7 +145,7 @@ class Character:
class UserCharacter(Character):
'''
用户角色类\
用户角色类
property: `user` - `User`类或子类的实例
'''
database_table_name = 'user_char_full' if Config.CHARACTER_FULL_UNLOCK else 'user_char'
@@ -332,9 +340,10 @@ class UserCharacter(Character):
def upgrade_by_core(self, user=None, core=None):
'''
以太之滴升级注意这里core.amount应该是负数\
parameter: `user` - `User`类或子类的实例\
`core` - `ItemCore`类或子类的实例
以太之滴升级注意这里core.amount应该是负数
parameter: `user` - `User`类或子类的实例
`core` - `ItemCore`类或子类的实例
'''
if user:
self.user = user
@@ -353,7 +362,7 @@ class UserCharacter(Character):
class UserCharacterList:
'''
用户拥有角色列表类\
用户拥有角色列表类
properties: `user` - `User`类或子类的实例
'''
database_table_name = 'user_char_full' if Config.CHARACTER_FULL_UNLOCK else 'user_char'

View File

@@ -333,7 +333,8 @@ class ItemFactory:
elif item_type == 'course_banner':
return CourseBanner(self.c)
else:
raise InputError('The item type `%s` is wrong.' % item_type)
raise InputError(
f'The item type `{item_type}` is invalid.', api_error_code=-120)
@classmethod
def from_dict(cls, d: dict, c=None):

View File

@@ -1,8 +1,7 @@
from time import time
from core.item import ItemFactory
from .error import ArcError, NoData
from .error import ArcError, DataExist, NoData
from .item import ItemFactory
class Present:
@@ -18,15 +17,40 @@ class Present:
def is_expired(self) -> bool:
return self.expire_ts < int(time() * 1000)
def to_dict(self) -> dict:
return {
def to_dict(self, has_items: bool = True) -> dict:
r = {
'present_id': self.present_id,
'expire_ts': self.expire_ts,
'description': self.description,
'items': [x.to_dict() for x in self.items]
'description': self.description
}
if has_items:
r['items'] = [x.to_dict() for x in self.items]
return r
def select(self, present_id: str = None) -> None:
def from_dict(self, d: dict) -> 'Present':
self.present_id = d['present_id']
self.expire_ts = int(d['expire_ts'])
self.description = d.get('description', '')
self.items = []
for i in d.get('items', []):
self.items.append(ItemFactory.from_dict(i))
return self
def from_list(self, l: list) -> 'Present':
self.present_id = l[0]
self.expire_ts = int(l[1]) if l[1] else 0
self.description = l[2] if l[2] else ''
return self
def select_exists(self) -> bool:
'''
查询present是否存在
'''
self.c.execute(
'''select exists(select * from present where present_id=?)''', (self.present_id,))
return bool(self.c.fetchone()[0])
def select(self, present_id: str = None) -> 'Present':
'''
用present_id查询信息
'''
@@ -39,8 +63,8 @@ class Present:
if x is None:
raise NoData('The present `%s` does not exist.' % self.present_id)
self.expire_ts = x[1] if x[1] else 0
self.description = x[2] if x[2] else ''
self.from_list(x)
return self
def select_items(self) -> None:
'''
@@ -48,15 +72,79 @@ class Present:
'''
self.c.execute(
'''select * from present_item where present_id=:a''', {'a': self.present_id})
x = self.c.fetchall()
if not x:
raise NoData('The present `%s` does not have any items.' %
self.present_id)
self.items = [ItemFactory.from_dict({
'item_id': i[1],
'type': i[2],
'amount': i[3] if i[3] else 1
}, self.c) for i in x]
}, self.c) for i in self.c.fetchall()]
def insert_items(self) -> None:
for i in self.items:
self.c.execute('''insert or ignore into item values(?,?,?)''',
(i.item_id, i.item_type, i.is_available))
self.c.execute('''insert or ignore into present_item values(?,?,?,?)''',
(self.present_id, i.item_id, i.item_type, i.amount))
def insert(self) -> None:
self.c.execute('''insert into present values(?,?,?)''',
(self.present_id, self.expire_ts, self.description))
def insert_all(self) -> None:
self.insert()
self.insert_items()
def delete(self) -> None:
self.c.execute(
'''delete from present where present_id=?''', (self.present_id,))
def delete_present_item(self) -> None:
self.c.execute(
'''delete from present_item where present_id=?''', (self.present_id,))
def delete_all(self) -> None:
self.delete_present_item()
self.delete()
def update(self) -> None:
self.c.execute('''update present set expire_ts=?, description=? where present_id=?''',
(self.expire_ts, self.description, self.present_id))
def delete_items(self, items: list) -> None:
'''删除present_item表中的物品'''
for i in items:
if i not in self.items:
raise NoData(
f'No such item `{i.item_type}`: `{i.item_id}` in present `{self.present_id}`', api_error_code=-124)
self.c.executemany('''delete from present_item where present_id=? and item_id=? and type=?''', [
(self.present_id, i.item_id, i.item_type) for i in items])
for i in items:
self.items.remove(i)
def add_items(self, items: list) -> None:
'''添加物品到present_item表'''
for i in items:
if not i.select_exists():
raise NoData(
f'No such item `{i.item_type}`: `{i.item_id}`', api_error_code=-121)
if i in self.items:
raise DataExist(
f'Item `{i.item_type}`: `{i.item_id}` already exists in present `{self.present_id}`', api_error_code=-123)
self.c.executemany('''insert into present_item values(?,?,?,?)''', [
(self.present_id, i.item_id, i.item_type, i.amount) for i in items])
self.items.extend(items)
def update_items(self, items: list) -> None:
'''更新present_item表中的物品'''
for i in items:
if i not in self.items:
raise NoData(
f'No such item `{i.item_type}`: `{i.item_id}` in present `{self.present_id}`', api_error_code=-124)
self.c.executemany('''update present_item set amount=? where present_id=? and item_id=? and type=?''', [
(i.amount, self.present_id, i.item_id, i.item_type) for i in items])
for i in items:
self.items[self.items.index(i)].amount = i.amount
class UserPresent(Present):