[Refactor][Bug fix] World mode & skills

- Code refactor for world mode
- Try to fix some skills to keep it same with the official server (especially `ayu_uncap`), and adjust the order of World Mode progress calculation (maybe still not right).
- Uncap Kanae

Note: not ready for Kanae's uncapping skill (I do not know its actual effect.)
This commit is contained in:
Lost-MSth
2024-01-13 15:14:54 +08:00
parent de701b4d1b
commit 746712718b
8 changed files with 379 additions and 264 deletions

View File

@@ -12,7 +12,7 @@ class Config:
SONG_FILE_HASH_PRE_CALCULATE = True
GAME_API_PREFIX = '/evolution/23'
GAME_API_PREFIX = '/akeome/24'
ALLOW_APPVERSION = [] # list[str]

View File

@@ -1,6 +1,6 @@
from .config_manager import Config
ARCAEA_SERVER_VERSION = 'v2.11.2.7'
ARCAEA_SERVER_VERSION = 'v2.11.3.2.test'
ARCAEA_LOG_DATBASE_VERSION = 'v1.1'

View File

@@ -11,7 +11,7 @@ from .item import ItemCore
from .song import Chart
from .sql import Connect, Query, Sql
from .util import get_today_timestamp, md5
from .world import WorldPlay
from .world import WorldPlay, BeyondWorldPlay
class Score:
@@ -500,7 +500,8 @@ class UserPlay(UserScore):
# 世界模式判断
if self.is_world_mode:
self.world_play = WorldPlay(self.c, self.user, self)
self.world_play = WorldPlay(
self.c, self.user, self) if self.beyond_gauge == 0 else BeyondWorldPlay(self.c, self.user, self)
self.world_play.update()
# 课题模式判断

View File

@@ -1,7 +1,7 @@
import os
from functools import lru_cache
from json import load
from random import random
from random import randint
from time import time
from .character import Character
@@ -438,226 +438,15 @@ class UserStamina(Stamina):
'a': self.stamina, 'b': self.max_stamina_ts, 'c': self.user.user_id})
class WorldPlay:
'''
世界模式打歌类处理特殊角色技能联动UserMap和UserPlay
parameter: `user` - `UserOnline`类或子类的实例
'user_play` - `UserPlay`类的实例
'''
def __init__(self, c=None, user=None, user_play=None) -> None:
self.c = c
self.user = user
self.user_play = user_play
self.character_used = None
self.base_step_value: float = None
self.step_value: float = None
self.prog_tempest: float = None
self.character_bonus_progress: float = None
self.prog_skill_increase: float = None
self.over_skill_increase: float = None
def to_dict(self) -> dict:
arcmap: 'UserMap' = self.user.current_map
r = {
"rewards": arcmap.rewards_for_climbing_to_dict(),
"exp": self.character_used.level.exp,
"level": self.character_used.level.level,
"base_progress": self.base_step_value,
"progress": self.step_value,
"user_map": {
"user_id": self.user.user_id,
"curr_position": arcmap.curr_position,
"curr_capture": arcmap.curr_capture,
"is_locked": arcmap.is_locked,
"map_id": arcmap.map_id,
"prev_capture": arcmap.prev_capture,
"prev_position": arcmap.prev_position,
"beyond_health": arcmap.beyond_health
},
"char_stats": {
"character_id": self.character_used.character_id,
"frag": self.character_used.frag.get_value(self.character_used.level),
"prog": self.character_used.prog.get_value(self.character_used.level),
"overdrive": self.character_used.overdrive.get_value(self.character_used.level)
},
"current_stamina": self.user.stamina.stamina,
"max_stamina_ts": self.user.stamina.max_stamina_ts,
'world_mode_locked_end_ts': self.user.world_mode_locked_end_ts,
'beyond_boost_gauge': self.user.beyond_boost_gauge
}
if self.over_skill_increase is not None:
r['char_stats']['over_skill_increase'] = self.over_skill_increase
if self.prog_skill_increase is not None:
r['char_stats']['prog_skill_increase'] = self.prog_skill_increase
if self.prog_tempest is not None:
r['char_stats']['prog'] += self.prog_tempest # 没试过要不要这样
r['char_stats']['prog_tempest'] = self.prog_tempest
if self.character_bonus_progress is not None:
# 猜的,为了让客户端正确显示
r['progress'] -= self.character_bonus_progress
r['character_bonus_progress'] = self.character_bonus_progress
if self.character_used.skill_id_displayed == 'skill_maya':
r['char_stats']['skill_state'] = self.character_used.skill_state
if self.user_play.beyond_gauge == 0:
r["user_map"]["steps"] = [
x.to_dict() for x in arcmap.steps_for_climbing]
else:
r["user_map"]["steps"] = len(arcmap.steps_for_climbing)
if self.user_play.stamina_multiply != 1:
r['stamina_multiply'] = self.user_play.stamina_multiply
if self.user_play.fragment_multiply != 100:
r['fragment_multiply'] = self.user_play.fragment_multiply
if self.user_play.prog_boost_multiply != 0:
r['prog_boost_multiply'] = self.user_play.prog_boost_multiply
if self.user_play.beyond_boost_gauge_usage != 0:
r['beyond_boost_gauge_usage'] = self.user_play.beyond_boost_gauge_usage
return r
@property
def beyond_boost_gauge_addition(self) -> float:
# guessed by Lost-MSth
return 2.45 * self.user_play.rating ** 0.5 + 27
@property
def step_times(self) -> float:
prog_boost_multiply = self.user_play.prog_boost_multiply + 100
beyond_boost_times = 1
if self.user_play.beyond_gauge == 1:
if prog_boost_multiply > 100:
prog_boost_multiply -= 100
if self.user_play.beyond_boost_gauge_usage == 100:
beyond_boost_times = 2
elif self.user_play.beyond_boost_gauge_usage == 200:
beyond_boost_times = 3
return self.user_play.stamina_multiply * self.user_play.fragment_multiply / 100 * prog_boost_multiply / 100 * beyond_boost_times
@property
def exp_times(self) -> float:
prog_boost_multiply = self.user_play.prog_boost_multiply + 100
beyond_boost_times = 1
if self.user_play.beyond_gauge == 1:
if prog_boost_multiply > 100:
prog_boost_multiply -= 100
if self.user_play.beyond_boost_gauge_usage == 100:
beyond_boost_times = 2
elif self.user_play.beyond_boost_gauge_usage == 200:
beyond_boost_times = 3
return self.user_play.stamina_multiply * prog_boost_multiply / 100 * beyond_boost_times
def get_step(self) -> None:
if self.user_play.beyond_gauge == 0:
self.base_step_value = 2.5 + 2.45 * self.user_play.rating**0.5
prog = self.character_used.prog.get_value(
self.character_used.level)
if self.prog_tempest:
prog += self.prog_tempest
if self.prog_skill_increase:
prog += self.prog_skill_increase
self.step_value = self.base_step_value * prog / 50 * self.step_times
else:
if self.user_play.clear_type == 0:
self.base_step_value = 25/28 + \
(self.user_play.rating)**0.5 * 0.43
else:
self.base_step_value = 75/28 + \
(self.user_play.rating)**0.5 * 0.43
if self.character_used.character_id in self.user.current_map.character_affinity:
affinity_multiplier = self.user.current_map.affinity_multiplier[self.user.current_map.character_affinity.index(
self.character_used.character_id)]
else:
affinity_multiplier = 1
overdrive = self.character_used.overdrive.get_value(
self.character_used.level)
if self.over_skill_increase:
overdrive += self.over_skill_increase
self.step_value = self.base_step_value * overdrive / \
50 * self.step_times * affinity_multiplier
def update(self) -> None:
'''世界模式更新'''
if self.user_play.prog_boost_multiply != 0:
self.user.update_user_one_column('prog_boost', 0)
self.user_play.clear_play_state()
self.user.select_user_about_world_play()
if self.user_play.beyond_gauge == 0:
# 更新byd大招蓄力条
self.user.beyond_boost_gauge += self.beyond_boost_gauge_addition
self.user.beyond_boost_gauge = min(
self.user.beyond_boost_gauge, 200)
self.user.update_user_one_column(
'beyond_boost_gauge', self.user.beyond_boost_gauge)
elif self.user_play.beyond_boost_gauge_usage != 0 and self.user_play.beyond_boost_gauge_usage <= self.user.beyond_boost_gauge:
self.user.beyond_boost_gauge -= self.user_play.beyond_boost_gauge_usage
if abs(self.user.beyond_boost_gauge) <= 1e-5:
self.user.beyond_boost_gauge = 0
self.user.update_user_one_column(
'beyond_boost_gauge', self.user.beyond_boost_gauge)
self.character_used = Character()
self.user.character.select_character_info()
if not self.user.is_skill_sealed:
self.character_used = self.user.character
else:
self.character_used.character_id = self.user.character.character_id
self.character_used.level.level = self.user.character.level.level
self.character_used.level.exp = self.user.character.level.exp
self.character_used.frag.set_parameter(50, 50, 50)
self.character_used.prog.set_parameter(50, 50, 50)
self.character_used.overdrive.set_parameter(50, 50, 50)
self.user.current_map.select_map_info()
self.before_calculate()
self.get_step()
self.user.current_map.climb(self.step_value)
self.after_climb()
for i in self.user.current_map.rewards_for_climbing: # 物品分发
for j in i['items']:
j.c = self.c
j.user_claim_item(self.user)
x: 'Step' = self.user.current_map.steps_for_climbing[-1]
if x.step_type:
if 'plusstamina' in x.step_type and x.plus_stamina_value:
# 体力格子
self.user.stamina.stamina += x.plus_stamina_value
self.user.stamina.update()
# 角色升级
if self.character_used.database_table_name == 'user_char':
self.character_used.upgrade(
self.user, self.exp_times*self.user_play.rating*6)
if self.user.current_map.curr_position == self.user.current_map.step_count-1 and self.user.current_map.is_repeatable: # 循环图判断
self.user.current_map.curr_position = 0
self.user.current_map.update()
class WorldSkillMixin:
def before_calculate(self) -> None:
factory_dict = {'skill_vita': self._skill_vita, 'skill_mika': self._skill_mika, 'skill_ilith_ivy': self._skill_ilith_ivy,
'ilith_awakened_skill': self._ilith_awakened_skill, 'skill_hikari_vanessa': self._skill_hikari_vanessa}
factory_dict = {'skill_vita': self._skill_vita,
'skill_mika': self._skill_mika,
'skill_ilith_ivy': self._skill_ilith_ivy,
'ilith_awakened_skill': self._ilith_awakened_skill,
'skill_hikari_vanessa': self._skill_hikari_vanessa,
'skill_mithra': self._skill_mithra
}
if self.user_play.beyond_gauge == 0 and self.character_used.character_id == 35 and self.character_used.skill_id_displayed:
self._special_tempest()
@@ -665,8 +454,14 @@ class WorldPlay:
factory_dict[self.character_used.skill_id_displayed]()
def after_climb(self) -> None:
factory_dict = {'eto_uncap': self._eto_uncap, 'ayu_uncap': self._ayu_uncap,
'luna_uncap': self._luna_uncap, 'skill_fatalis': self._skill_fatalis, 'skill_amane': self._skill_amane, 'skill_maya': self._skill_maya, 'skill_mithra': self._skill_mithra}
factory_dict = {'eto_uncap': self._eto_uncap,
'ayu_uncap': self._ayu_uncap,
'skill_fatalis': self._skill_fatalis,
'skill_amane': self._skill_amane,
'skill_maya': self._skill_maya,
'luna_uncap': self._luna_uncap,
'skill_kanae_uncap': self._skill_kanae_uncap
}
if self.character_used.skill_id_displayed in factory_dict:
factory_dict[self.character_used.skill_id_displayed]()
@@ -706,32 +501,27 @@ class WorldPlay:
break
if fragment_flag:
self.character_bonus_progress = Constant.ETO_UNCAP_BONUS_PROGRESS
self.step_value += self.character_bonus_progress
self.character_bonus_progress_normalized = Constant.ETO_UNCAP_BONUS_PROGRESS
self.user.current_map.reclimb(self.step_value)
self.user.current_map.reclimb(self.final_progress)
def _luna_uncap(self) -> None:
'''luna觉醒技能限制格开始时世界模式进度加7'''
'''luna觉醒技能限制格开始时世界模式进度加 7偷懒重爬因为 map 信息还未获取)'''
x: 'Step' = self.user.current_map.steps_for_climbing[0]
if x.restrict_id and x.restrict_type:
self.character_bonus_progress = Constant.LUNA_UNCAP_BONUS_PROGRESS
self.step_value += self.character_bonus_progress
self.user.current_map.reclimb(self.step_value)
self.self.character_bonus_progress_normalized = Constant.LUNA_UNCAP_BONUS_PROGRESS
self.user.current_map.reclimb(self.final_progress)
def _ayu_uncap(self) -> None:
'''ayu觉醒技能世界模式进度+5或-5但不会小于0'''
'''ayu 觉醒技能,世界模式进度随机变动 [-5, -5],但不会小于 0'''
self.character_bonus_progress = Constant.AYU_UNCAP_BONUS_PROGRESS if random(
) >= 0.5 else -Constant.AYU_UNCAP_BONUS_PROGRESS
self.character_bonus_progress_normalized = randint(
-Constant.AYU_UNCAP_BONUS_PROGRESS, Constant.AYU_UNCAP_BONUS_PROGRESS)
self.step_value += self.character_bonus_progress
if self.step_value < 0:
self.character_bonus_progress += self.step_value
self.step_value = 0
if self.progress_normalized + self.character_bonus_progress_normalized < 0:
self.character_bonus_progress_normalized = -self.progress_normalized
self.user.current_map.reclimb(self.step_value)
self.user.current_map.reclimb(self.final_progress)
def _skill_fatalis(self) -> None:
'''hikari fatalis技能世界模式超载打完休息60分钟'''
@@ -743,13 +533,11 @@ class WorldPlay:
def _skill_amane(self) -> None:
'''
amane技能起始格为限速或随机成绩小于EX时世界模式进度减半
偷懒在after_climb里面需要重爬一次
'''
x: 'Step' = self.user.current_map.steps_for_climbing[0]
if ('randomsong' in x.step_type or 'speedlimit' in x.step_type) and self.user_play.song_grade < 5:
self.character_bonus_progress = -self.step_value / 2
self.step_value = self.step_value / 2
self.user.current_map.reclimb(self.step_value)
self.character_bonus_progress_normalized = -self.progress_normalized / 2
self.user.current_map.reclimb(self.final_progress)
def _ilith_awakened_skill(self) -> None:
'''
@@ -773,9 +561,7 @@ class WorldPlay:
mithra 技能,每 150 combo 增加世界模式进度+1
'''
if self.user_play.combo_interval_bonus:
self.character_bonus_progress = self.user_play.combo_interval_bonus
self.step_value += self.character_bonus_progress
self.user.current_map.reclimb(self.step_value)
self.character_bonus_progress_normalized = self.user_play.combo_interval_bonus
def _skill_ilith_ivy(self) -> None:
'''
@@ -804,7 +590,292 @@ class WorldPlay:
maya 技能skill_flag 为 1 时,世界模式进度翻倍
'''
if self.character_used.skill_flag:
self.character_bonus_progress = self.step_value
self.step_value += self.character_bonus_progress
self.user.current_map.reclimb(self.step_value)
self.character_bonus_progress_normalized = self.progress_normalized
self.user.current_map.reclimb(self.final_progress)
self.character_used.change_skill_state()
def _skill_kanae_uncap(self) -> None:
'''
kanae 觉醒技能,保存世界模式 progress 并在下次结算
'''
pass
class BaseWorldPlay(WorldSkillMixin):
'''
世界模式打歌类处理特殊角色技能联动UserMap和UserPlay
parameter: `user` - `UserOnline`类或子类的实例
'user_play` - `UserPlay`类的实例
'''
def __init__(self, c=None, user=None, user_play=None) -> None:
self.c = c
self.user = user
self.user_play = user_play
self.character_used = None
self.progress_normalized: float = None
self.character_bonus_progress_normalized: float = None
# kanae_stored_progress: float
# kanae_added_progress: float
# partner_multiply: float
# wpaid: str
def to_dict(self) -> dict:
arcmap: 'UserMap' = self.user.current_map
r = {
"rewards": arcmap.rewards_for_climbing_to_dict(),
"exp": self.character_used.level.exp,
"level": self.character_used.level.level,
"base_progress": self.base_progress,
"progress": self.final_progress,
"user_map": {
"user_id": self.user.user_id,
"curr_position": arcmap.curr_position,
"curr_capture": arcmap.curr_capture,
"is_locked": arcmap.is_locked,
"map_id": arcmap.map_id,
"prev_capture": arcmap.prev_capture,
"prev_position": arcmap.prev_position,
"beyond_health": arcmap.beyond_health
},
"char_stats": {
"character_id": self.character_used.character_id,
"frag": self.character_used.frag.get_value(self.character_used.level),
"prog": self.character_used.prog.get_value(self.character_used.level),
"overdrive": self.character_used.overdrive.get_value(self.character_used.level)
},
"current_stamina": self.user.stamina.stamina,
"max_stamina_ts": self.user.stamina.max_stamina_ts,
'world_mode_locked_end_ts': self.user.world_mode_locked_end_ts,
'beyond_boost_gauge': self.user.beyond_boost_gauge,
# 'kanae_stored_progress': 7114000, # 往群愿里塞
# 'kanae_added_progress': 514000, # 群愿往外拿
# 'wpaid': 'helloworld', # world play id ???
# 'partner_multiply': 456, #
}
if self.character_used.skill_id_displayed == 'skill_maya':
r['char_stats']['skill_state'] = self.character_used.skill_state
if self.user_play.stamina_multiply != 1:
r['stamina_multiply'] = self.user_play.stamina_multiply
if self.user_play.fragment_multiply != 100:
r['fragment_multiply'] = self.user_play.fragment_multiply
if self.user_play.prog_boost_multiply != 0: # 源韵强化
r['prog_boost_multiply'] = self.user_play.prog_boost_multiply
return r
@property
def beyond_boost_gauge_addition(self) -> float:
# guessed by Lost-MSth
return 2.45 * self.user_play.rating ** 0.5 + 27
@property
def step_times(self) -> float:
raise NotImplementedError
@property
def exp_times(self) -> float:
return self.user_play.stamina_multiply * (self.user_play.prog_boost_multiply / 100 + 1)
@property
def character_bonus_progress(self) -> float:
return self.character_bonus_progress_normalized * self.step_times
@property
def base_progress(self) -> float:
raise NotImplementedError
@property
def final_progress(self) -> float:
raise NotImplementedError
def get_step(self) -> None:
# to get self.progress_normalized
raise NotImplementedError
def update(self) -> None:
'''世界模式更新'''
if self.user_play.prog_boost_multiply != 0:
self.user.update_user_one_column('prog_boost', 0)
self.user_play.clear_play_state()
self.user.select_user_about_world_play()
self.character_used = Character()
self.user.character.select_character_info()
if not self.user.is_skill_sealed:
self.character_used = self.user.character
else:
self.character_used.character_id = self.user.character.character_id
self.character_used.level.level = self.user.character.level.level
self.character_used.level.exp = self.user.character.level.exp
self.character_used.frag.set_parameter(50, 50, 50)
self.character_used.prog.set_parameter(50, 50, 50)
self.character_used.overdrive.set_parameter(50, 50, 50)
self.user.current_map.select_map_info()
self.before_calculate()
self.get_step()
self.user.current_map.climb(self.final_progress)
self.after_climb()
for i in self.user.current_map.rewards_for_climbing: # 物品分发
for j in i['items']:
j.c = self.c
j.user_claim_item(self.user)
x: 'Step' = self.user.current_map.steps_for_climbing[-1]
if x.step_type:
if 'plusstamina' in x.step_type and x.plus_stamina_value:
# 体力格子
self.user.stamina.stamina += x.plus_stamina_value
self.user.stamina.update()
# 角色升级
if self.character_used.database_table_name == 'user_char':
self.character_used.upgrade(
self.user, self.exp_times*self.user_play.rating*6)
if self.user.current_map.curr_position == self.user.current_map.step_count-1 and self.user.current_map.is_repeatable: # 循环图判断
self.user.current_map.curr_position = 0
self.user.current_map.update()
class WorldPlay(BaseWorldPlay):
def __init__(self, c=None, user=None, user_play=None) -> None:
super().__init__(c, user, user_play)
self.prog_tempest: float = None
self.prog_skill_increase: float = None
def to_dict(self) -> dict:
r = super().to_dict()
# 基础进度加上搭档倍数 不带 character_bonus_progress 但是带 kanae 技能
r['progress_partial_after_stat'] = self.progress_normalized
if self.character_bonus_progress_normalized is not None:
r['character_bonus_progress'] = self.character_bonus_progress_normalized
# 不懂为什么两个玩意一样
r['character_bonus_progress_normalized'] = self.character_bonus_progress_normalized
if self.prog_skill_increase is not None:
r['char_stats']['prog_skill_increase'] = self.prog_skill_increase
if self.prog_tempest is not None:
r['char_stats']['prog'] += self.prog_tempest # 没试过要不要这样
r['char_stats']['prog_tempest'] = self.prog_tempest
r['partner_adjusted_prog'] = self.partner_adjusted_prog
r["user_map"]["steps"] = [x.to_dict()
for x in self.user.current_map.steps_for_climbing]
return r
@property
def step_times(self) -> float:
return self.user_play.stamina_multiply * self.user_play.fragment_multiply / 100 * (self.user_play.prog_boost_multiply / 100 + 1)
@property
def character_bonus_progress(self) -> float:
return self.character_bonus_progress_normalized * self.step_times
@property
def base_progress(self) -> float:
return 2.5 + 2.45 * self.user_play.rating**0.5
@property
def final_progress(self) -> float:
return (self.progress_normalized + (self.character_bonus_progress_normalized or 0)) * self.step_times
@property
def partner_adjusted_prog(self) -> float:
prog = self.character_used.prog.get_value(
self.character_used.level)
if self.prog_tempest:
prog += self.prog_tempest
if self.prog_skill_increase:
prog += self.prog_skill_increase
return prog
def get_step(self) -> None:
self.progress_normalized = self.base_progress * \
(self.partner_adjusted_prog / 50)
def update(self) -> None:
'''世界模式更新'''
super().update()
# 更新byd大招蓄力条
self.user.beyond_boost_gauge += self.beyond_boost_gauge_addition
self.user.beyond_boost_gauge = min(self.user.beyond_boost_gauge, 200)
self.user.update_user_one_column(
'beyond_boost_gauge', self.user.beyond_boost_gauge)
class BeyondWorldPlay(BaseWorldPlay):
def __init__(self, c=None, user=None, user_play=None) -> None:
super().__init__(c, user, user_play)
self.over_skill_increase: float = None
@property
def step_times(self) -> float:
return self.user_play.stamina_multiply * self.user_play.fragment_multiply / 100 * (1 + self.user_play.prog_boost_multiply / 100 + self.user_play.beyond_boost_gauge_usage / 100)
@property
def affinity_multiplier(self) -> float:
if self.user.current_map.character_affinity is not None and self.character_used.character_id is not None and self.character_used.character_id in self.user.current_map.character_affinity:
return self.user.current_map.affinity_multiplier[self.user.current_map.character_affinity.index(self.character_used.character_id)]
return 1
@property
def base_progress(self) -> float:
return self.user_play.rating**0.5 * 0.43 + (25/28 if self.user_play.clear_type == 0 else 75/28)
@property
def final_progress(self) -> float:
return self.progress_normalized * self.step_times
def to_dict(self) -> dict:
r = super().to_dict()
# byd 进度 没有加上源韵强化 和 boost 的数值
r['pre_boost_progress'] = self.progress_normalized * \
self.user_play.fragment_multiply / 100
if self.over_skill_increase is not None:
r['char_stats']['over_skill_increase'] = self.over_skill_increase
r["user_map"]["steps"] = len(self.user.current_map.steps_for_climbing)
r['affinity_multiply'] = self.affinity_multiplier
if self.user_play.beyond_boost_gauge_usage != 0:
r['beyond_boost_gauge_usage'] = self.user_play.beyond_boost_gauge_usage
return r
def update(self) -> None:
super().update()
if self.user_play.beyond_boost_gauge_usage != 0 and self.user_play.beyond_boost_gauge_usage <= self.user.beyond_boost_gauge:
self.user.beyond_boost_gauge -= self.user_play.beyond_boost_gauge_usage
if abs(self.user.beyond_boost_gauge) <= 1e-5:
self.user.beyond_boost_gauge = 0
self.user.update_user_one_column(
'beyond_boost_gauge', self.user.beyond_boost_gauge)
def get_step(self) -> None:
overdrive = self.character_used.overdrive.get_value(
self.character_used.level)
if self.over_skill_increase:
overdrive += self.over_skill_increase
self.progress_normalized = self.base_progress * \
(overdrive / 50) * self.affinity_multiplier