Fix: No kids as low camera height may miss enemy aim icon

This commit is contained in:
LmeSzinc 2023-12-21 00:15:46 +08:00
parent 0f11911e5c
commit 21307e209e
7 changed files with 115 additions and 17 deletions

View File

@ -8,6 +8,7 @@ from hashlib import md5
from module.base.code_generator import CodeGenerator from module.base.code_generator import CodeGenerator
from module.config.utils import deep_get, read_file from module.config.utils import deep_get, read_file
from module.exception import ScriptError
from module.logger import logger from module.logger import logger
UI_LANGUAGES = ['cn', 'cht', 'en', 'jp', 'es'] UI_LANGUAGES = ['cn', 'cht', 'en', 'jp', 'es']
@ -38,15 +39,24 @@ def blessing_name(name: str) -> str:
return name return name
nickname_count = 0
def character_name(name: str) -> str: def character_name(name: str) -> str:
name = text_to_variable(name) name = text_to_variable(name)
name = re.sub('_', '', name) name = re.sub('_', '', name)
return name return name
def convert_inner_character_to_keyword(name):
convert_dict = {
'Silwolf': 'SilverWolf',
'Klara': 'Clara',
'Mar_7th': 'March7th',
'PlayerGirl': 'TrailblazerFemale',
'PlayerBoy': 'TrailblazerMale',
'Ren': 'Blade',
}
return convert_dict.get(name, name)
class TextMap: class TextMap:
DATA_FOLDER = '' DATA_FOLDER = ''
@ -381,6 +391,30 @@ class KeywordExtract:
self.load_character_name_keywords() self.load_character_name_keywords()
self.write_keywords(keyword_class='CharacterList', output_file='./tasks/character/keywords/character_list.py', self.write_keywords(keyword_class='CharacterList', output_file='./tasks/character/keywords/character_list.py',
text_convert=character_name) text_convert=character_name)
# Generate character height
characters = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'FreeStyleCharacterConfig.json'))
regex = re.compile(r'NPC_Avatar_(?P<height>.*?)_(?P<character>.*?)_00')
gen = CodeGenerator()
dict_height = {}
height_index = ['Kid', 'Girl', 'Boy', 'Maid', 'Miss', 'Lady', 'Lad', 'Male']
for key in characters.keys():
if res := regex.search(key):
character, height = res.group('character'), res.group('height')
if height not in height_index:
continue
dict_height[character] = height
dict_height = {k: v for k, v in sorted(dict_height.items(), key=lambda item: height_index.index(item[1]))}
from tasks.character.keywords.classes import CharacterList
with gen.Dict('CHARACTER_HEIGHT'):
for character, height in dict_height.items():
character = convert_inner_character_to_keyword(character)
try:
CharacterList.find_name(character)
except ScriptError:
print(f'Character height data {character} is not defined')
continue
gen.DictItem(key=character, value=height)
gen.write('./tasks/character/keywords/height.py')
def generate_battle_pass_quests(self): def generate_battle_pass_quests(self):
battle_pass_quests = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'BattlePassConfig.json')) battle_pass_quests = read_file(os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', 'BattlePassConfig.json'))

View File

@ -180,3 +180,24 @@ class Keyword:
# Not found # Not found
raise ScriptError(f'Cannot find a {cls.__name__} instance that matches "{name}"') raise ScriptError(f'Cannot find a {cls.__name__} instance that matches "{name}"')
@classmethod
def find_name(cls, name):
"""
Args:
name: Attribute name of keyword.
Returns:
Keyword instance.
Raises:
ScriptError: If nothing found.
"""
if isinstance(name, Keyword):
return name
for instance in cls.instances.values():
if name == instance.name:
return instance
# Not found
raise ScriptError(f'Cannot find a {cls.__name__} instance that matches "{name}"')

View File

@ -9,9 +9,19 @@ from module.ocr.keyword import Keyword
class CharacterList(Keyword): class CharacterList(Keyword):
instances: ClassVar = {} instances: ClassVar = {}
def __hash__(self) -> int:
return super().__hash__()
@cached_property @cached_property
def is_trailblazer(self) -> bool: def is_trailblazer(self) -> bool:
return 'Trailblazer' in self.name return 'Trailblazer' in self.name
def __hash__(self) -> int: @cached_property
return super().__hash__() def height(self) -> str:
"""
Returns:
str: Character height, from list ['Kid', 'Girl', 'Boy', 'Maid', 'Miss', 'Lady', 'Lad', 'Male']
or 'Unknown' if no data
"""
from tasks.character.keywords.height import CHARACTER_HEIGHT
return CHARACTER_HEIGHT.get(self.name, 'Unknown')

View File

@ -0,0 +1,31 @@
CHARACTER_HEIGHT = {
'Hook': 'Kid',
'Bailu': 'Kid',
'SilverWolf': 'Girl',
'Qingque': 'Girl',
'Pela': 'Girl',
'Clara': 'Girl',
'Herta': 'Girl',
'FuXuan': 'Girl',
'Yanqing': 'Boy',
'Arlan': 'Boy',
'Tingyun': 'Maid',
'Sushang': 'Maid',
'Seele': 'Maid',
'March7th': 'Maid',
'Jingliu': 'Maid',
'Bronya': 'Maid',
'Asta': 'Maid',
'Yukong': 'Lady',
'Serval': 'Lady',
'Natasha': 'Lady',
'Kafka': 'Lady',
'Himeko': 'Lady',
'DanHeng': 'Lad',
'Welt': 'Male',
'Sampo': 'Male',
'Blade': 'Male',
'Luocha': 'Male',
'JingYuan': 'Male',
'Gepard': 'Male',
}

View File

@ -1,3 +1,5 @@
import re
import cv2 import cv2
import numpy as np import numpy as np
from scipy import signal from scipy import signal
@ -17,6 +19,8 @@ class OcrCharacterName(OcrWhiteLetterOnComplexBackground):
def after_process(self, result): def after_process(self, result):
result = result.replace('', '') result = result.replace('', '')
# Dan Heng o.ImbibitorLunae
result = re.sub(r'[0Oo\-. ]{1,3}Imbi', 'Imbi', result)
return super().after_process(result) return super().after_process(result)
@ -140,7 +144,7 @@ class CharacterSwitch(UI):
return selected return selected
def _convert_selected_to_character(self, selected: list[int]) -> CharacterList | None: def _convert_selected_to_character(self, selected: list[int]) -> CharacterList | None:
expected_peaks = np.array([201, 279, 357, 435]) expected_peaks = [201, 279, 357, 435]
if not selected: if not selected:
logger.warning(f'No current character') logger.warning(f'No current character')
logger.attr('CurrentCharacter', None) logger.attr('CurrentCharacter', None)
@ -227,6 +231,14 @@ class CharacterSwitch(UI):
if ranged_character in self.characters: if ranged_character in self.characters:
logger.info(f'Use ranged character: {ranged_character}, range={level}') logger.info(f'Use ranged character: {ranged_character}, range={level}')
return ranged_character return ranged_character
# No kids, as low camera height may miss enemy aim icon
if self.character_current.height == 'Kid':
# Switch to whoever tall
for height in ['Male', 'Lad', 'Lady', 'Miss', 'Maid', 'Boy', 'Girl']:
for tall_character in self.characters:
if tall_character.height == height:
logger.info(f'No kids, use tall character: {tall_character}')
return tall_character
# No ranged characters # No ranged characters
logger.info('No ranged characters in team') logger.info('No ranged characters in team')
return False return False

View File

@ -155,7 +155,7 @@ class RoguePathHandler(RogueUI):
or page_main if previous rogue run had bonus selected but didn't finish any domain or page_main if previous rogue run had bonus selected but didn't finish any domain
""" """
logger.hr('Rogue path select', level=2) logger.hr('Rogue path select', level=2)
path: RoguePath = RoguePath.find_path(path) path: RoguePath = RoguePath.find_name(path)
logger.info(f'Select path: {path}') logger.info(f'Select path: {path}')
entry = self._get_path_click(path) entry = self._get_path_click(path)
while 1: while 1:

View File

@ -36,16 +36,6 @@ class RoguePath(Keyword):
return [self.__getattribute__(f"{server}_parsed").replace("the", '') return [self.__getattribute__(f"{server}_parsed").replace("the", '')
for server in UI_LANGUAGES if hasattr(self, f"{server}_parsed")] for server in UI_LANGUAGES if hasattr(self, f"{server}_parsed")]
@classmethod
def find_path(cls, name):
if isinstance(name, RoguePath):
return name
for instance in cls.instances.values():
if name == instance.name:
return instance
# Not found
raise ScriptError(f'Cannot find a {cls.__name__} instance that matches "{name}"')
@dataclass(repr=False) @dataclass(repr=False)
class RogueResonance(Keyword): class RogueResonance(Keyword):