[Enhance] Breached World

- Add support for Breached World Map
- Change the recover time of using fragments buying stamina to 23 hours
- For Arcaea 5.3.0
This commit is contained in:
Lost-MSth
2024-01-30 15:16:26 +08:00
parent 2edf559373
commit 9d096f480b
7 changed files with 140 additions and 22 deletions

View File

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

View File

@@ -1,6 +1,6 @@
from .config_manager import Config from .config_manager import Config
ARCAEA_SERVER_VERSION = 'v2.11.3.2' ARCAEA_SERVER_VERSION = 'v2.11.3.3'
ARCAEA_LOG_DATBASE_VERSION = 'v1.1' ARCAEA_LOG_DATBASE_VERSION = 'v1.1'
@@ -11,6 +11,7 @@ class Constant:
MAX_STAMINA = 12 MAX_STAMINA = 12
STAMINA_RECOVER_TICK = 1800000 STAMINA_RECOVER_TICK = 1800000
FRAGSTAM_RECOVER_TICK = 23 * 3600 * 1000
COURSE_STAMINA_COST = 4 COURSE_STAMINA_COST = 4

View File

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

View File

@@ -99,6 +99,7 @@ class Map:
self.map_id: str = map_id self.map_id: str = map_id
self.is_legacy: bool = None self.is_legacy: bool = None
self.is_beyond: bool = None self.is_beyond: bool = None
self.is_breached: bool = None
self.beyond_health: int = None self.beyond_health: int = None
self.character_affinity: list = [] self.character_affinity: list = []
self.affinity_multiplier: list = [] self.affinity_multiplier: list = []
@@ -119,6 +120,11 @@ class Map:
self.require_localunlock_challengeid: str = None self.require_localunlock_challengeid: str = None
self.chain_info: dict = None self.chain_info: dict = None
# self.requires: list[dict] = None
self.disable_over: bool = None
self.new_law: str = None
@property @property
def rewards(self) -> list: def rewards(self) -> list:
if self.__rewards is None: if self.__rewards is None:
@@ -145,6 +151,7 @@ class Map:
'map_id': self.map_id, 'map_id': self.map_id,
'is_legacy': self.is_legacy, 'is_legacy': self.is_legacy,
'is_beyond': self.is_beyond, 'is_beyond': self.is_beyond,
'is_breached': self.is_breached,
'beyond_health': self.beyond_health, 'beyond_health': self.beyond_health,
'character_affinity': self.character_affinity, 'character_affinity': self.character_affinity,
'affinity_multiplier': self.affinity_multiplier, 'affinity_multiplier': self.affinity_multiplier,
@@ -165,11 +172,16 @@ class Map:
} }
if self.chain_info is not None: if self.chain_info is not None:
r['chain_info'] = self.chain_info r['chain_info'] = self.chain_info
if self.disable_over:
r['disable_over'] = self.disable_over
if self.new_law is not None and self.new_law != '':
r['new_law'] = self.new_law
return r return r
def from_dict(self, raw_dict: dict) -> 'Map': def from_dict(self, raw_dict: dict) -> 'Map':
self.is_legacy = raw_dict.get('is_legacy') self.is_legacy = raw_dict.get('is_legacy', False)
self.is_beyond = raw_dict.get('is_beyond') self.is_beyond = raw_dict.get('is_beyond', False)
self.is_breached = raw_dict.get('is_breached', False)
self.beyond_health = raw_dict.get('beyond_health') self.beyond_health = raw_dict.get('beyond_health')
self.character_affinity = raw_dict.get('character_affinity', []) self.character_affinity = raw_dict.get('character_affinity', [])
self.affinity_multiplier = raw_dict.get('affinity_multiplier', []) self.affinity_multiplier = raw_dict.get('affinity_multiplier', [])
@@ -189,6 +201,9 @@ class Map:
'require_localunlock_challengeid', '') 'require_localunlock_challengeid', '')
self.chain_info = raw_dict.get('chain_info') self.chain_info = raw_dict.get('chain_info')
self.steps = [Step().from_dict(s) for s in raw_dict.get('steps')] self.steps = [Step().from_dict(s) for s in raw_dict.get('steps')]
self.disable_over = raw_dict.get('disable_over')
self.new_law = raw_dict.get('new_law')
return self return self
def select_map_info(self): def select_map_info(self):
@@ -696,13 +711,12 @@ class BaseWorldPlay(WorldSkillMixin):
def final_progress(self) -> float: def final_progress(self) -> float:
raise NotImplementedError raise NotImplementedError
def update(self) -> None: def before_update(self) -> None:
'''世界模式更新'''
if self.user_play.prog_boost_multiply != 0: if self.user_play.prog_boost_multiply != 0:
self.user.update_user_one_column('prog_boost', 0) self.user.update_user_one_column('prog_boost', 0)
self.user_play.clear_play_state() self.user_play.clear_play_state()
self.user.select_user_about_world_play() # self.user.select_user_about_world_play()
self.character_used = Character() self.character_used = Character()
@@ -720,10 +734,9 @@ class BaseWorldPlay(WorldSkillMixin):
self.character_used.prog.set_parameter(50, 50, 50) self.character_used.prog.set_parameter(50, 50, 50)
self.character_used.overdrive.set_parameter(50, 50, 50) self.character_used.overdrive.set_parameter(50, 50, 50)
self.user.current_map.select_map_info() # self.user.current_map.select_map_info()
self.before_calculate()
self.user.current_map.climb(self.final_progress) def after_update(self) -> None:
self.after_climb()
for i in self.user.current_map.rewards_for_climbing: # 物品分发 for i in self.user.current_map.rewards_for_climbing: # 物品分发
for j in i['items']: for j in i['items']:
@@ -747,6 +760,14 @@ class BaseWorldPlay(WorldSkillMixin):
self.user.current_map.update() self.user.current_map.update()
def update(self) -> None:
'''世界模式更新'''
self.before_update()
self.before_calculate()
self.user.current_map.climb(self.final_progress)
self.after_climb()
self.after_update()
class WorldPlay(BaseWorldPlay): class WorldPlay(BaseWorldPlay):
def __init__(self, c=None, user=None, user_play=None) -> None: def __init__(self, c=None, user=None, user_play=None) -> None:
@@ -819,9 +840,9 @@ class WorldPlay(BaseWorldPlay):
def progress_normalized(self) -> float: def progress_normalized(self) -> float:
return self.base_progress * (self.partner_adjusted_prog / 50) return self.base_progress * (self.partner_adjusted_prog / 50)
def update(self) -> None: def after_update(self) -> None:
'''世界模式更新''' '''世界模式更新'''
super().update() super().after_update()
# 更新byd大招蓄力条 # 更新byd大招蓄力条
self.user.beyond_boost_gauge += self.beyond_boost_gauge_addition self.user.beyond_boost_gauge += self.beyond_boost_gauge_addition
@@ -892,12 +913,83 @@ class BeyondWorldPlay(BaseWorldPlay):
return r return r
def update(self) -> None: def after_update(self) -> None:
super().update() super().after_update()
if self.user_play.beyond_boost_gauge_usage != 0 and self.user_play.beyond_boost_gauge_usage <= self.user.beyond_boost_gauge: 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 self.user.beyond_boost_gauge -= self.user_play.beyond_boost_gauge_usage
if abs(self.user.beyond_boost_gauge) <= 1e-5: if abs(self.user.beyond_boost_gauge) <= 1e-5:
self.user.beyond_boost_gauge = 0 self.user.beyond_boost_gauge = 0
self.user.update_user_one_column( self.user.update_user_one_column(
'beyond_boost_gauge', self.user.beyond_boost_gauge) 'beyond_boost_gauge', self.user.beyond_boost_gauge)
class WorldLawMixin:
def breached_before_calculate(self) -> None:
factory_dict = {
'over100_step50': self._over100_step50,
'frag50': self._frag50,
'lowlevel': self._lowlevel,
'antiheroism': self._antiheroism
}
if self.user.current_map.new_law in factory_dict:
factory_dict[self.user.current_map.new_law]()
def _over100_step50(self) -> None:
'''PROG = OVER + STEP / 2'''
self.new_law_prog = self.character_used.overdrive_value + \
self.character_used.prog_value / 2
def _frag50(self) -> None:
'''PROG x= FRAG'''
self.new_law_prog = self.character_used.frag_value
def _lowlevel(self) -> None:
'''PROG x= max(1.0, 2.0 - 0.1 x LEVEL)'''
self.new_law_prog = 50 * \
max(1, 2 - 0.1 * self.character_used.level.level)
def _antiheroism(self) -> None:
'''PROG = OVER - ||OVER-FRAG|-|OVER-STEP||'''
over = self.character_used.overdrive_value
x = abs(over - self.character_used.frag_value)
y = abs(over - self.character_used.prog_value)
self.new_law_prog = over - abs(x - y)
class BreachedWorldPlay(BeyondWorldPlay, WorldLawMixin):
def __init__(self, c=None, user=None, user_play=None) -> None:
super().__init__(c, user, user_play)
self.new_law_prog: float = None
@property
def new_law_multiply(self) -> float:
if self.new_law_prog is None:
return 1
return self.new_law_prog / 50
@property
def affinity_multiplier(self) -> float:
return 1
@property
def progress_normalized(self) -> float:
if self.user.current_map.disable_over:
return self.base_progress * self.new_law_multiply
overdrive = self.character_used.overdrive_value
if self.over_skill_increase:
overdrive += self.over_skill_increase
return self.base_progress * (overdrive / 50) * self.new_law_multiply
def to_dict(self) -> dict:
r = super().to_dict()
r['new_law_multiply'] = self.new_law_multiply
return r
def update(self) -> None:
self.before_update()
self.before_calculate()
self.breached_before_calculate()
self.user.current_map.climb(self.final_progress)
self.after_climb()
self.after_update()

View File

@@ -69,10 +69,10 @@ class InitData:
'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']
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'] "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']
world_unlocks = ["scenery_chap1", "scenery_chap2", world_unlocks = ["scenery_chap1", "scenery_chap2",
"scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6", "scenery_chap7"] "scenery_chap3", "scenery_chap4", "scenery_chap5", "scenery_chap6", "scenery_chap7", "scenery_beyond"]
course_banners = ['course_banner_' + str(i) for i in range(1, 12)] course_banners = ['course_banner_' + str(i) for i in range(1, 12)]

View File

@@ -1594,5 +1594,23 @@
], ],
"orig_price": 100, "orig_price": 100,
"price": 100 "price": 100
},
{
"name": "lunarossa",
"items": [
{
"type": "single",
"id": "lunarossa",
"is_available": true
},
{
"type": "core",
"amount": 1,
"id": "core_generic",
"is_available": true
}
],
"orig_price": 100,
"price": 100
} }
] ]

View File

@@ -2,6 +2,7 @@ from time import time
from flask import Blueprint, request from flask import Blueprint, request
from core.constant import Constant
from core.error import InputError, ItemUnavailable, PostError from core.error import InputError, ItemUnavailable, PostError
from core.item import ItemFactory, Stamina6 from core.item import ItemFactory, Stamina6
from core.purchase import Purchase, PurchaseList from core.purchase import Purchase, PurchaseList
@@ -130,7 +131,7 @@ def purchase_stamina(user_id, buy_stamina_type):
return ItemUnavailable('Buying stamina by fragment is not available yet.', 905) return ItemUnavailable('Buying stamina by fragment is not available yet.', 905)
user.update_user_one_column( user.update_user_one_column(
'next_fragstam_ts', now + 24 * 3600 * 1000) 'next_fragstam_ts', now + Constant.FRAGSTAM_RECOVER_TICK)
s = Stamina6(c) s = Stamina6(c)
s.user_claim_item(user) s.user_claim_item(user)
return success_return({ return success_return({