mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-24 01:21:25 +00:00
Dev: Extract map worlds and planes, add extract framework
This commit is contained in:
parent
94b7bc4566
commit
1e79353294
@ -3,26 +3,15 @@ import os
|
||||
import re
|
||||
import typing as t
|
||||
from collections import defaultdict
|
||||
from functools import cache, cached_property
|
||||
from functools import cache
|
||||
from hashlib import md5
|
||||
|
||||
from dev_tools.keywords.base import TextMap, UI_LANGUAGES, replace_templates, text_to_variable
|
||||
from module.base.code_generator import CodeGenerator
|
||||
from module.config.utils import deep_get, read_file
|
||||
from module.exception import ScriptError
|
||||
from module.logger import logger
|
||||
|
||||
UI_LANGUAGES = ['cn', 'cht', 'en', 'jp', 'es']
|
||||
|
||||
|
||||
def text_to_variable(text):
|
||||
text = re.sub("'s |s' ", '_', text)
|
||||
text = re.sub('[ \-—:\'/•.]+', '_', text)
|
||||
text = re.sub(r'[(),#"?!&%*]|</?\w+>', '', text)
|
||||
# text = re.sub(r'[#_]?\d+(_times?)?', '', text)
|
||||
text = re.sub(r'<color=#?\w+>', '', text)
|
||||
text = text.replace('é', 'e')
|
||||
return text.strip('_')
|
||||
|
||||
|
||||
def dungeon_name(name: str) -> str:
|
||||
name = text_to_variable(name)
|
||||
@ -61,72 +50,6 @@ def convert_inner_character_to_keyword(name):
|
||||
return convert_dict.get(name, name)
|
||||
|
||||
|
||||
class TextMap:
|
||||
DATA_FOLDER = ''
|
||||
|
||||
def __init__(self, lang: str):
|
||||
self.lang = lang
|
||||
|
||||
def __contains__(self, name: t.Union[int, str]) -> bool:
|
||||
if isinstance(name, int) or (isinstance(name, str) and name.isdigit()):
|
||||
return int(name) in self.data
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
def data(self) -> dict[int, str]:
|
||||
if not os.path.exists(TextMap.DATA_FOLDER):
|
||||
logger.critical('`TextMap.DATA_FOLDER` does not exist, please set it to your path to StarRailData')
|
||||
exit(1)
|
||||
file = os.path.join(TextMap.DATA_FOLDER, 'TextMap', f'TextMap{self.lang.upper()}.json')
|
||||
data = {}
|
||||
for id_, text in read_file(file).items():
|
||||
text = text.replace('\u00A0', '')
|
||||
text = text.replace(r'{NICKNAME}', 'Trailblazer')
|
||||
data[int(id_)] = text
|
||||
return data
|
||||
|
||||
def find(self, name: t.Union[int, str]) -> tuple[int, str]:
|
||||
"""
|
||||
Args:
|
||||
name:
|
||||
|
||||
Returns:
|
||||
text id (hash in TextMap)
|
||||
text
|
||||
"""
|
||||
if isinstance(name, int) or (isinstance(name, str) and name.isdigit()):
|
||||
name = int(name)
|
||||
try:
|
||||
return name, self.data[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
name = str(name)
|
||||
for row_id, row_name in self.data.items():
|
||||
if row_id >= 0 and row_name == name:
|
||||
return row_id, row_name
|
||||
for row_id, row_name in self.data.items():
|
||||
if row_name == name:
|
||||
return row_id, row_name
|
||||
logger.error(f'Cannot find name: "{name}" in language {self.lang}')
|
||||
return 0, ''
|
||||
|
||||
|
||||
def replace_templates(text: str) -> str:
|
||||
"""
|
||||
Replace templates in data to make sure it equals to what is shown in game
|
||||
|
||||
Examples:
|
||||
replace_templates("Complete Echo of War #4 time(s)")
|
||||
== "Complete Echo of War 1 time(s)"
|
||||
"""
|
||||
text = re.sub(r'#4', '1', text)
|
||||
text = re.sub(r'</?\w+>', '', text)
|
||||
text = re.sub(r'<color=#?\w+>', '', text)
|
||||
text = re.sub(r'{.*?}', '', text)
|
||||
return text
|
||||
|
||||
|
||||
class KeywordExtract:
|
||||
def __init__(self):
|
||||
self.text_map: dict[str, TextMap] = {lang: TextMap(lang) for lang in UI_LANGUAGES}
|
||||
@ -438,32 +361,10 @@ class KeywordExtract:
|
||||
self.write_keywords(keyword_class=class_name, output_file=output_file)
|
||||
|
||||
def generate_map_planes(self):
|
||||
planes = {
|
||||
'Special': ['黑塔的办公室', '锋芒崭露'],
|
||||
'Rogue': [ '区域-战斗', '区域-事件', '区域-遭遇', '区域-休整', '区域-精英', '区域-首领', '区域-交易'],
|
||||
'Herta': ['观景车厢', '主控舱段', '基座舱段', '收容舱段', '支援舱段', '禁闭舱段'],
|
||||
'Jarilo': ['行政区', '城郊雪原', '边缘通路', '铁卫禁区', '残响回廊', '永冬岭',
|
||||
'造物之柱', '旧武器试验场', '磐岩镇', '大矿区', '铆钉镇', '机械聚落'],
|
||||
'Luofu': ['星槎海中枢', '流云渡', '迴星港', '长乐天', '金人巷', '太卜司',
|
||||
'工造司', '绥园', '丹鼎司', '鳞渊境'],
|
||||
}
|
||||
|
||||
def text_convert(world_):
|
||||
def text_convert_wrapper(name):
|
||||
name = text_to_variable(name).replace('_', '')
|
||||
name = f'{world_}_{name}'
|
||||
return name
|
||||
|
||||
return text_convert_wrapper
|
||||
|
||||
gen = None
|
||||
for world, plane in planes.items():
|
||||
self.load_keywords(plane)
|
||||
gen = self.write_keywords(keyword_class='MapPlane', output_file='',
|
||||
text_convert=text_convert(world), generator=gen)
|
||||
gen.write('./tasks/map/keywords/plane.py')
|
||||
self.load_keywords(['Herta Space Station', 'Jarilo-VI', 'The Xianzhou Luofu'], lang='en')
|
||||
self.write_keywords(keyword_class='MapWorld', output_file='./tasks/map/keywords/world.py')
|
||||
from dev_tools.keywords.map_world import GenerateMapWorld
|
||||
GenerateMapWorld()()
|
||||
from dev_tools.keywords.map_plane import GenerateMapPlane
|
||||
GenerateMapPlane()()
|
||||
|
||||
def generate_character_keywords(self):
|
||||
self.load_character_name_keywords()
|
||||
|
184
dev_tools/keywords/base.py
Normal file
184
dev_tools/keywords/base.py
Normal file
@ -0,0 +1,184 @@
|
||||
import os
|
||||
import re
|
||||
import typing as t
|
||||
from functools import cached_property
|
||||
|
||||
from module.base.code_generator import CodeGenerator
|
||||
from module.config.utils import read_file
|
||||
from module.logger import logger
|
||||
|
||||
UI_LANGUAGES = ['cn', 'cht', 'en', 'jp', 'es']
|
||||
|
||||
|
||||
class TextMap:
|
||||
DATA_FOLDER = ''
|
||||
|
||||
def __init__(self, lang: str):
|
||||
self.lang = lang
|
||||
|
||||
def __contains__(self, name: t.Union[int, str]) -> bool:
|
||||
if isinstance(name, int) or (isinstance(name, str) and name.isdigit()):
|
||||
return int(name) in self.data
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
def data(self) -> dict[int, str]:
|
||||
if not os.path.exists(TextMap.DATA_FOLDER):
|
||||
logger.critical('`TextMap.DATA_FOLDER` does not exist, please set it to your path to StarRailData')
|
||||
exit(1)
|
||||
file = os.path.join(TextMap.DATA_FOLDER, 'TextMap', f'TextMap{self.lang.upper()}.json')
|
||||
data = {}
|
||||
for id_, text in read_file(file).items():
|
||||
text = text.replace('\u00A0', '')
|
||||
text = text.replace(r'{NICKNAME}', 'Trailblazer')
|
||||
data[int(id_)] = text
|
||||
return data
|
||||
|
||||
def find(self, name: t.Union[int, str]) -> tuple[int, str]:
|
||||
"""
|
||||
Args:
|
||||
name:
|
||||
|
||||
Returns:
|
||||
text id (hash in TextMap)
|
||||
text
|
||||
"""
|
||||
if isinstance(name, int) or (isinstance(name, str) and name.isdigit()):
|
||||
name = int(name)
|
||||
try:
|
||||
return name, self.data[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
name = str(name)
|
||||
for row_id, row_name in self.data.items():
|
||||
if row_id >= 0 and row_name == name:
|
||||
return row_id, row_name
|
||||
for row_id, row_name in self.data.items():
|
||||
if row_name == name:
|
||||
return row_id, row_name
|
||||
logger.error(f'Cannot find name: "{name}" in language {self.lang}')
|
||||
return 0, ''
|
||||
|
||||
|
||||
def text_to_variable(text):
|
||||
text = re.sub("'s |s' ", '_', text)
|
||||
text = re.sub(r'[ \-—:\'/•.]+', '_', text)
|
||||
text = re.sub(r'[(),#"?!&%*]|</?\w+>', '', text)
|
||||
# text = re.sub(r'[#_]?\d+(_times?)?', '', text)
|
||||
text = re.sub(r'<color=#?\w+>', '', text)
|
||||
text = text.replace('é', 'e')
|
||||
return text.strip('_')
|
||||
|
||||
|
||||
def replace_templates(text: str) -> str:
|
||||
"""
|
||||
Replace templates in data to make sure it equals to what is shown in game
|
||||
|
||||
Examples:
|
||||
replace_templates("Complete Echo of War #4 time(s)")
|
||||
== "Complete Echo of War 1 time(s)"
|
||||
"""
|
||||
text = re.sub(r'#4', '1', text)
|
||||
text = re.sub(r'</?\w+>', '', text)
|
||||
text = re.sub(r'<color=#?\w+>', '', text)
|
||||
text = re.sub(r'{.*?}', '', text)
|
||||
return text
|
||||
|
||||
|
||||
class GenerateKeyword:
|
||||
text_map: dict[str, TextMap] = {lang: TextMap(lang) for lang in UI_LANGUAGES}
|
||||
text_map['cn'] = TextMap('chs')
|
||||
|
||||
@staticmethod
|
||||
def read_file(file: str) -> dict:
|
||||
"""
|
||||
Args:
|
||||
file: ./ExcelOutput/GameplayGuideData.json
|
||||
|
||||
Returns:
|
||||
dict:
|
||||
"""
|
||||
file = os.path.join(TextMap.DATA_FOLDER, file)
|
||||
return read_file(file)
|
||||
|
||||
@classmethod
|
||||
def find_keyword(cls, keyword, lang) -> tuple[int, str]:
|
||||
"""
|
||||
Args:
|
||||
keyword: text string or text id
|
||||
lang: Language to find
|
||||
|
||||
Returns:
|
||||
text id (hash in TextMap)
|
||||
text
|
||||
"""
|
||||
text_map = cls.text_map[lang]
|
||||
return text_map.find(keyword)
|
||||
|
||||
output_file = ''
|
||||
|
||||
def __init__(self):
|
||||
self.gen = CodeGenerator()
|
||||
self.keyword_class = self.__class__.__name__.removeprefix('Generate')
|
||||
self.keyword_index = 0
|
||||
self.keyword_format = {
|
||||
'id': 0,
|
||||
'name': 'Unnamed_Keyword'
|
||||
}
|
||||
for lang in UI_LANGUAGES:
|
||||
self.keyword_format[lang] = ''
|
||||
|
||||
def gen_import(self):
|
||||
self.gen.Import(
|
||||
f"""
|
||||
from .classes import {self.keyword_class}
|
||||
"""
|
||||
)
|
||||
|
||||
def iter_keywords(self) -> t.Iterable[dict]:
|
||||
"""
|
||||
Yields
|
||||
dict: {'text_id': 123456, 'any_attr': 1}
|
||||
"""
|
||||
pass
|
||||
|
||||
def convert_name(self, text: str, keyword: dict) -> str:
|
||||
return text_to_variable(text)
|
||||
|
||||
def format_keywords(self, keyword: dict) -> dict | None:
|
||||
base = self.keyword_format.copy()
|
||||
text_id = keyword.pop('text_id')
|
||||
if text_id is None:
|
||||
return
|
||||
# id
|
||||
self.keyword_index += 1
|
||||
base['id'] = self.keyword_index
|
||||
# Attrs
|
||||
base.update(keyword)
|
||||
# Name
|
||||
_, name = self.find_keyword(text_id, lang='en')
|
||||
name = self.convert_name(replace_templates(name), keyword=base)
|
||||
base['name'] = name
|
||||
# Translations
|
||||
for lang in UI_LANGUAGES:
|
||||
value = replace_templates(self.find_keyword(text_id, lang=lang)[1])
|
||||
base[lang] = value
|
||||
return base
|
||||
|
||||
def generate(self):
|
||||
self.gen_import()
|
||||
self.gen.CommentAutoGenerage('dev_tools.keyword_extract')
|
||||
|
||||
for keyword in self.iter_keywords():
|
||||
keyword = self.format_keywords(keyword)
|
||||
with self.gen.Object(key=keyword['name'], object_class=self.keyword_class):
|
||||
for key, value in keyword.items():
|
||||
self.gen.ObjectAttr(key, value)
|
||||
|
||||
if self.output_file:
|
||||
print(f'Write {self.output_file}')
|
||||
self.gen.write(self.output_file)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
self.generate()
|
70
dev_tools/keywords/map_plane.py
Normal file
70
dev_tools/keywords/map_plane.py
Normal file
@ -0,0 +1,70 @@
|
||||
import typing as t
|
||||
|
||||
from dev_tools.keywords.base import GenerateKeyword
|
||||
from module.base.decorator import cached_property
|
||||
from module.config.utils import deep_get
|
||||
|
||||
|
||||
class GenerateMapPlane(GenerateKeyword):
|
||||
output_file = './tasks/map/keywords/plane.py'
|
||||
|
||||
@cached_property
|
||||
def data(self):
|
||||
return self.read_file('./ExcelOutput/AreaMapConfig.json')
|
||||
|
||||
def iter_planes(self) -> t.Iterable[dict]:
|
||||
for plane_id, data in self.data.items():
|
||||
plane_id = int(plane_id)
|
||||
world_id = int(str(plane_id)[-5])
|
||||
sort_id = int(deep_get(data, 'MenuSortID', 0))
|
||||
text_id = deep_get(data, 'Name.Hash')
|
||||
yield dict(
|
||||
text_id=text_id,
|
||||
world_id=world_id,
|
||||
plane_id=plane_id,
|
||||
sort_id=sort_id,
|
||||
)
|
||||
|
||||
def iter_keywords(self) -> t.Iterable[dict]:
|
||||
"""
|
||||
1010201
|
||||
^^ floor
|
||||
^^ plane
|
||||
^ world
|
||||
"""
|
||||
def to_id(name):
|
||||
return self.find_keyword(name, lang='cn')[0]
|
||||
|
||||
domains = ['黑塔的办公室', '锋芒崭露']
|
||||
for index, domain in enumerate(domains):
|
||||
yield dict(
|
||||
text_id=to_id(domain),
|
||||
world_id=-1,
|
||||
plane_id=index + 1,
|
||||
)
|
||||
domains = ['区域-战斗', '区域-事件', '区域-遭遇', '区域-休整', '区域-精英', '区域-首领', '区域-交易']
|
||||
for index, domain in enumerate(domains):
|
||||
yield dict(
|
||||
text_id=to_id(domain),
|
||||
world_id=-2,
|
||||
plane_id=index + 1,
|
||||
)
|
||||
|
||||
keywords = sorted(self.iter_planes(), key=lambda x: (x['world_id'], x['sort_id']))
|
||||
for keyword in keywords:
|
||||
keyword.pop('sort_id')
|
||||
yield keyword
|
||||
|
||||
def convert_name(self, text: str, keyword: dict) -> str:
|
||||
text = super().convert_name(text, keyword=keyword)
|
||||
text = text.replace('_', '')
|
||||
|
||||
from tasks.map.keywords import MapWorld
|
||||
world = MapWorld.find_world_id(keyword['world_id'])
|
||||
if world is None:
|
||||
if text.startswith('Domain'):
|
||||
return f'Rogue_{text}'
|
||||
else:
|
||||
return f'Special_{text}'
|
||||
else:
|
||||
return f'{world.short_name}_{text}'
|
33
dev_tools/keywords/map_world.py
Normal file
33
dev_tools/keywords/map_world.py
Normal file
@ -0,0 +1,33 @@
|
||||
import typing as t
|
||||
|
||||
from dev_tools.keywords.base import GenerateKeyword
|
||||
|
||||
|
||||
class GenerateMapWorld(GenerateKeyword):
|
||||
output_file = './tasks/map/keywords/world.py'
|
||||
|
||||
def iter_keywords(self) -> t.Iterable[dict]:
|
||||
|
||||
def to_id(name):
|
||||
return self.find_keyword(name, lang='en')[0]
|
||||
|
||||
yield dict(
|
||||
text_id=to_id('Herta Space Station'),
|
||||
world_id=0,
|
||||
short_name='Herta'
|
||||
)
|
||||
yield dict(
|
||||
text_id=to_id('Jarilo-VI'),
|
||||
world_id=1,
|
||||
short_name='Jarilo'
|
||||
)
|
||||
yield dict(
|
||||
text_id=to_id('The Xianzhou Luofu'),
|
||||
world_id=2,
|
||||
short_name='Luofu'
|
||||
)
|
||||
yield dict(
|
||||
text_id=to_id('Penacony'),
|
||||
world_id=3,
|
||||
short_name='Penacony'
|
||||
)
|
@ -17,11 +17,11 @@ FLOOR_BUTTONS = [FLOOR_1, FLOOR_2, FLOOR_3]
|
||||
|
||||
|
||||
def world_entrance(plane: MapPlane) -> ButtonWrapper:
|
||||
if plane.is_HertaSpaceStation:
|
||||
if plane.world.is_Herta:
|
||||
return WORLD_HERTA
|
||||
if plane.is_JariloVI:
|
||||
if plane.world.is_Jarilo:
|
||||
return WORLD_JARILO
|
||||
if plane.is_Luofu:
|
||||
if plane.world.is_Luofu:
|
||||
return WORLD_LUOFU
|
||||
raise ScriptError(f'world_entrance() got unknown plane: {plane}')
|
||||
|
||||
|
@ -10,6 +10,11 @@ from module.ocr.keyword import Keyword
|
||||
class MapPlane(Keyword):
|
||||
instances: ClassVar = {}
|
||||
|
||||
# 0, 1, 2, 3
|
||||
world_id: int
|
||||
# 1010201
|
||||
plane_id: int
|
||||
|
||||
# Map floors, 'F1' by default
|
||||
# Example: ['B1', 'F1', 'F2']
|
||||
floors = ['F1']
|
||||
@ -18,33 +23,27 @@ class MapPlane(Keyword):
|
||||
# 'top' or 'bottom'
|
||||
page = 'top'
|
||||
|
||||
@classmethod
|
||||
def find_plane_id(cls, plane_id):
|
||||
"""
|
||||
Args:
|
||||
plane_id:
|
||||
|
||||
Returns:
|
||||
MapPlane: MapPlane object or None
|
||||
"""
|
||||
for instance in cls.instances.values():
|
||||
if instance.plane_id == plane_id:
|
||||
return instance
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def world(self) -> str:
|
||||
def world(self) -> "MapWorld":
|
||||
"""
|
||||
Returns:
|
||||
str: World name. Note that "Parlor Car" is considered as a plane of Herta.
|
||||
"Herta" for Herta Space Station
|
||||
"Jarilo" for Jarilo-VI
|
||||
"Luofu" for The Xianzhou Luofu
|
||||
"" for unknown
|
||||
MapWorld: MapWorld object or None
|
||||
"""
|
||||
for world in ['Herta', 'Jarilo', 'Luofu']:
|
||||
if self.name.startswith(world):
|
||||
return world
|
||||
|
||||
return ''
|
||||
|
||||
@cached_property
|
||||
def is_HertaSpaceStation(self):
|
||||
return self.world == 'Herta'
|
||||
|
||||
@cached_property
|
||||
def is_JariloVI(self):
|
||||
return self.world == 'Jarilo'
|
||||
|
||||
@cached_property
|
||||
def is_Luofu(self):
|
||||
return self.world == 'Luofu'
|
||||
return MapWorld.find_world_id(self.world_id)
|
||||
|
||||
@cached_property
|
||||
def has_multiple_floors(self):
|
||||
@ -135,3 +134,38 @@ class MapPlane(Keyword):
|
||||
@dataclass(repr=False)
|
||||
class MapWorld(Keyword):
|
||||
instances: ClassVar = {}
|
||||
|
||||
# 0, 1, 2, 3
|
||||
world_id: int
|
||||
# Herta
|
||||
short_name: str
|
||||
|
||||
@classmethod
|
||||
def find_world_id(cls, world_id):
|
||||
"""
|
||||
Args:
|
||||
world_id:
|
||||
|
||||
Returns:
|
||||
MapWorld: MapWorld object or None
|
||||
"""
|
||||
for instance in cls.instances.values():
|
||||
if instance.world_id == world_id:
|
||||
return instance
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def is_Herta(self):
|
||||
return self.short_name == 'Herta'
|
||||
|
||||
@cached_property
|
||||
def is_Jarilo(self):
|
||||
return self.short_name == 'Jarilo'
|
||||
|
||||
@cached_property
|
||||
def is_Luofu(self):
|
||||
return self.short_name == 'Luofu'
|
||||
|
||||
@cached_property
|
||||
def is_Penacony(self):
|
||||
return self.short_name == 'Penacony'
|
||||
|
@ -11,6 +11,8 @@ Special_HertaOffice = MapPlane(
|
||||
en="Herta's Office",
|
||||
jp='ヘルタのオフィス',
|
||||
es='Oficina de Herta',
|
||||
world_id=-1,
|
||||
plane_id=1,
|
||||
)
|
||||
Special_AptitudeShowcase = MapPlane(
|
||||
id=2,
|
||||
@ -20,6 +22,8 @@ Special_AptitudeShowcase = MapPlane(
|
||||
en='Aptitude Showcase',
|
||||
jp='躍進する新星',
|
||||
es='Demostración de aptitudes',
|
||||
world_id=-1,
|
||||
plane_id=2,
|
||||
)
|
||||
Rogue_DomainCombat = MapPlane(
|
||||
id=3,
|
||||
@ -29,6 +33,8 @@ Rogue_DomainCombat = MapPlane(
|
||||
en='Domain — Combat',
|
||||
jp='エリア-戦闘',
|
||||
es='Batalla',
|
||||
world_id=-2,
|
||||
plane_id=1,
|
||||
)
|
||||
Rogue_DomainOccurrence = MapPlane(
|
||||
id=4,
|
||||
@ -38,6 +44,8 @@ Rogue_DomainOccurrence = MapPlane(
|
||||
en='Domain — Occurrence',
|
||||
jp='エリア-イベント',
|
||||
es='Evento',
|
||||
world_id=-2,
|
||||
plane_id=2,
|
||||
)
|
||||
Rogue_DomainEncounter = MapPlane(
|
||||
id=5,
|
||||
@ -47,6 +55,8 @@ Rogue_DomainEncounter = MapPlane(
|
||||
en='Domain — Encounter',
|
||||
jp='エリア-遭遇',
|
||||
es='Encuentro',
|
||||
world_id=-2,
|
||||
plane_id=3,
|
||||
)
|
||||
Rogue_DomainRespite = MapPlane(
|
||||
id=6,
|
||||
@ -56,6 +66,8 @@ Rogue_DomainRespite = MapPlane(
|
||||
en='Domain — Respite',
|
||||
jp='エリア-休憩',
|
||||
es='Reposo',
|
||||
world_id=-2,
|
||||
plane_id=4,
|
||||
)
|
||||
Rogue_DomainElite = MapPlane(
|
||||
id=7,
|
||||
@ -65,6 +77,8 @@ Rogue_DomainElite = MapPlane(
|
||||
en='Domain — Elite',
|
||||
jp='エリア-精鋭',
|
||||
es='Élite',
|
||||
world_id=-2,
|
||||
plane_id=5,
|
||||
)
|
||||
Rogue_DomainBoss = MapPlane(
|
||||
id=8,
|
||||
@ -74,6 +88,8 @@ Rogue_DomainBoss = MapPlane(
|
||||
en='Domain — Boss',
|
||||
jp='エリア-ボス',
|
||||
es='Jefe',
|
||||
world_id=-2,
|
||||
plane_id=6,
|
||||
)
|
||||
Rogue_DomainTransaction = MapPlane(
|
||||
id=9,
|
||||
@ -83,6 +99,8 @@ Rogue_DomainTransaction = MapPlane(
|
||||
en='Domain — Transaction',
|
||||
jp='エリア-取引',
|
||||
es='Transacción',
|
||||
world_id=-2,
|
||||
plane_id=7,
|
||||
)
|
||||
Herta_ParlorCar = MapPlane(
|
||||
id=10,
|
||||
@ -92,6 +110,8 @@ Herta_ParlorCar = MapPlane(
|
||||
en='Parlor Car',
|
||||
jp='列車のラウンジ',
|
||||
es='Vagón panorámico',
|
||||
world_id=0,
|
||||
plane_id=1000001,
|
||||
)
|
||||
Herta_MasterControlZone = MapPlane(
|
||||
id=11,
|
||||
@ -101,6 +121,8 @@ Herta_MasterControlZone = MapPlane(
|
||||
en='Master Control Zone',
|
||||
jp='主制御部分',
|
||||
es='Zona de mando principal',
|
||||
world_id=0,
|
||||
plane_id=1000101,
|
||||
)
|
||||
Herta_BaseZone = MapPlane(
|
||||
id=12,
|
||||
@ -110,6 +132,8 @@ Herta_BaseZone = MapPlane(
|
||||
en='Base Zone',
|
||||
jp='ベース部分',
|
||||
es='Zona de la base',
|
||||
world_id=0,
|
||||
plane_id=2000101,
|
||||
)
|
||||
Herta_StorageZone = MapPlane(
|
||||
id=13,
|
||||
@ -119,6 +143,8 @@ Herta_StorageZone = MapPlane(
|
||||
en='Storage Zone',
|
||||
jp='収容部分',
|
||||
es='Zona de almacenamiento',
|
||||
world_id=0,
|
||||
plane_id=2000201,
|
||||
)
|
||||
Herta_SupplyZone = MapPlane(
|
||||
id=14,
|
||||
@ -128,6 +154,8 @@ Herta_SupplyZone = MapPlane(
|
||||
en='Supply Zone',
|
||||
jp='サポート部分',
|
||||
es='Zona de suministros',
|
||||
world_id=0,
|
||||
plane_id=2000301,
|
||||
)
|
||||
Herta_SeclusionZone = MapPlane(
|
||||
id=15,
|
||||
@ -137,6 +165,8 @@ Herta_SeclusionZone = MapPlane(
|
||||
en='Seclusion Zone',
|
||||
jp='封鎖部分',
|
||||
es='Zona de confinamiento',
|
||||
world_id=0,
|
||||
plane_id=2000401,
|
||||
)
|
||||
Jarilo_AdministrativeDistrict = MapPlane(
|
||||
id=16,
|
||||
@ -146,6 +176,8 @@ Jarilo_AdministrativeDistrict = MapPlane(
|
||||
en='Administrative District',
|
||||
jp='行政区',
|
||||
es='Distrito administrativo',
|
||||
world_id=1,
|
||||
plane_id=1010101,
|
||||
)
|
||||
Jarilo_OutlyingSnowPlains = MapPlane(
|
||||
id=17,
|
||||
@ -155,6 +187,8 @@ Jarilo_OutlyingSnowPlains = MapPlane(
|
||||
en='Outlying Snow Plains',
|
||||
jp='郊外雪原',
|
||||
es='Llanuras nevadas de las afueras',
|
||||
world_id=1,
|
||||
plane_id=2010101,
|
||||
)
|
||||
Jarilo_BackwaterPass = MapPlane(
|
||||
id=18,
|
||||
@ -164,6 +198,8 @@ Jarilo_BackwaterPass = MapPlane(
|
||||
en='Backwater Pass',
|
||||
jp='外縁通路',
|
||||
es='Paso del Remanso',
|
||||
world_id=1,
|
||||
plane_id=2011101,
|
||||
)
|
||||
Jarilo_SilvermaneGuardRestrictedZone = MapPlane(
|
||||
id=19,
|
||||
@ -173,6 +209,8 @@ Jarilo_SilvermaneGuardRestrictedZone = MapPlane(
|
||||
en='Silvermane Guard Restricted Zone',
|
||||
jp='シルバーメイン禁区',
|
||||
es='Zona restringida de la Guardia Crinargenta',
|
||||
world_id=1,
|
||||
plane_id=2013101,
|
||||
)
|
||||
Jarilo_CorridorofFadingEchoes = MapPlane(
|
||||
id=20,
|
||||
@ -182,6 +220,8 @@ Jarilo_CorridorofFadingEchoes = MapPlane(
|
||||
en='Corridor of Fading Echoes',
|
||||
jp='残響回廊',
|
||||
es='Pasadizo de los ecos apagados',
|
||||
world_id=1,
|
||||
plane_id=2013201,
|
||||
)
|
||||
Jarilo_EverwinterHill = MapPlane(
|
||||
id=21,
|
||||
@ -191,6 +231,8 @@ Jarilo_EverwinterHill = MapPlane(
|
||||
en='Everwinter Hill',
|
||||
jp='常冬峰',
|
||||
es='Colina del Siempreinvierno',
|
||||
world_id=1,
|
||||
plane_id=2013401,
|
||||
)
|
||||
Jarilo_PillarsofCreation = MapPlane(
|
||||
id=22,
|
||||
@ -200,6 +242,8 @@ Jarilo_PillarsofCreation = MapPlane(
|
||||
en='Pillars of Creation',
|
||||
jp='造物の柱',
|
||||
es='Pilares de la Creación',
|
||||
world_id=1,
|
||||
plane_id=2013501,
|
||||
)
|
||||
Jarilo_OldWeaponTestingGround = MapPlane(
|
||||
id=23,
|
||||
@ -209,6 +253,8 @@ Jarilo_OldWeaponTestingGround = MapPlane(
|
||||
en='Old Weapon Testing Ground',
|
||||
jp='旧武器実験場',
|
||||
es='Antiguo campo de prueba de armas',
|
||||
world_id=1,
|
||||
plane_id=2013601,
|
||||
)
|
||||
Jarilo_BoulderTown = MapPlane(
|
||||
id=24,
|
||||
@ -218,6 +264,8 @@ Jarilo_BoulderTown = MapPlane(
|
||||
en='Boulder Town',
|
||||
jp='ボルダータウン',
|
||||
es='Villarroca',
|
||||
world_id=1,
|
||||
plane_id=1010201,
|
||||
)
|
||||
Jarilo_GreatMine = MapPlane(
|
||||
id=25,
|
||||
@ -227,6 +275,8 @@ Jarilo_GreatMine = MapPlane(
|
||||
en='Great Mine',
|
||||
jp='大鉱区',
|
||||
es='Mina principal',
|
||||
world_id=1,
|
||||
plane_id=2012101,
|
||||
)
|
||||
Jarilo_RivetTown = MapPlane(
|
||||
id=26,
|
||||
@ -236,6 +286,8 @@ Jarilo_RivetTown = MapPlane(
|
||||
en='Rivet Town',
|
||||
jp='リベットタウン',
|
||||
es='Villarremache',
|
||||
world_id=1,
|
||||
plane_id=2012201,
|
||||
)
|
||||
Jarilo_RobotSettlement = MapPlane(
|
||||
id=27,
|
||||
@ -245,6 +297,8 @@ Jarilo_RobotSettlement = MapPlane(
|
||||
en='Robot Settlement',
|
||||
jp='機械集落',
|
||||
es='Asentamiento robot',
|
||||
world_id=1,
|
||||
plane_id=2012301,
|
||||
)
|
||||
Luofu_CentralStarskiffHaven = MapPlane(
|
||||
id=28,
|
||||
@ -254,6 +308,8 @@ Luofu_CentralStarskiffHaven = MapPlane(
|
||||
en='Central Starskiff Haven',
|
||||
jp='星槎海中枢',
|
||||
es='Zona central de la Dársena de astroesquifes',
|
||||
world_id=2,
|
||||
plane_id=1020101,
|
||||
)
|
||||
Luofu_Cloudford = MapPlane(
|
||||
id=29,
|
||||
@ -263,6 +319,8 @@ Luofu_Cloudford = MapPlane(
|
||||
en='Cloudford',
|
||||
jp='流雲渡し',
|
||||
es='Vado de las Nubes',
|
||||
world_id=2,
|
||||
plane_id=2021101,
|
||||
)
|
||||
Luofu_StargazerNavalia = MapPlane(
|
||||
id=30,
|
||||
@ -272,6 +330,8 @@ Luofu_StargazerNavalia = MapPlane(
|
||||
en='Stargazer Navalia',
|
||||
jp='廻星港',
|
||||
es='Puerto Miraestrellas',
|
||||
world_id=2,
|
||||
plane_id=2021201,
|
||||
)
|
||||
Luofu_ExaltingSanctum = MapPlane(
|
||||
id=31,
|
||||
@ -281,6 +341,8 @@ Luofu_ExaltingSanctum = MapPlane(
|
||||
en='Exalting Sanctum',
|
||||
jp='長楽天',
|
||||
es='Sánctum de la Exaltación',
|
||||
world_id=2,
|
||||
plane_id=1020201,
|
||||
)
|
||||
Luofu_AurumAlley = MapPlane(
|
||||
id=32,
|
||||
@ -290,6 +352,8 @@ Luofu_AurumAlley = MapPlane(
|
||||
en='Aurum Alley',
|
||||
jp='金人巷',
|
||||
es='Callejón Aurum',
|
||||
world_id=2,
|
||||
plane_id=1020204,
|
||||
)
|
||||
Luofu_DivinationCommission = MapPlane(
|
||||
id=33,
|
||||
@ -299,6 +363,8 @@ Luofu_DivinationCommission = MapPlane(
|
||||
en='Divination Commission',
|
||||
jp='太卜司',
|
||||
es='Comisión de Adivinación',
|
||||
world_id=2,
|
||||
plane_id=2022101,
|
||||
)
|
||||
Luofu_ArtisanshipCommission = MapPlane(
|
||||
id=34,
|
||||
@ -308,6 +374,8 @@ Luofu_ArtisanshipCommission = MapPlane(
|
||||
en='Artisanship Commission',
|
||||
jp='工造司',
|
||||
es='Comisión de Artesanía',
|
||||
world_id=2,
|
||||
plane_id=2022201,
|
||||
)
|
||||
Luofu_FyxestrollGarden = MapPlane(
|
||||
id=35,
|
||||
@ -317,6 +385,8 @@ Luofu_FyxestrollGarden = MapPlane(
|
||||
en='Fyxestroll Garden',
|
||||
jp='綏園',
|
||||
es='Jardín del Sosiego',
|
||||
world_id=2,
|
||||
plane_id=2022301,
|
||||
)
|
||||
Luofu_AlchemyCommission = MapPlane(
|
||||
id=36,
|
||||
@ -326,6 +396,8 @@ Luofu_AlchemyCommission = MapPlane(
|
||||
en='Alchemy Commission',
|
||||
jp='丹鼎司',
|
||||
es='Comisión de Alquimia',
|
||||
world_id=2,
|
||||
plane_id=2023101,
|
||||
)
|
||||
Luofu_ScalegorgeWaterscape = MapPlane(
|
||||
id=37,
|
||||
@ -335,4 +407,61 @@ Luofu_ScalegorgeWaterscape = MapPlane(
|
||||
en='Scalegorge Waterscape',
|
||||
jp='鱗淵境',
|
||||
es='Desfiladero de Escamas',
|
||||
world_id=2,
|
||||
plane_id=2023201,
|
||||
)
|
||||
Penacony_TheReverieReality = MapPlane(
|
||||
id=38,
|
||||
name='Penacony_TheReverieReality',
|
||||
cn='「白日梦」酒店-现实',
|
||||
cht='「白日夢」飯店-現實',
|
||||
en='The Reverie (Reality)',
|
||||
jp='ホテル・レバリー-現実',
|
||||
es='Hotel Fantasía (realidad)',
|
||||
world_id=3,
|
||||
plane_id=1030501,
|
||||
)
|
||||
Penacony_GoldenHour = MapPlane(
|
||||
id=39,
|
||||
name='Penacony_GoldenHour',
|
||||
cn='黄金的时刻',
|
||||
cht='黃金的時刻',
|
||||
en='Golden Hour',
|
||||
jp='黄金の刻',
|
||||
es='Momento Dorado',
|
||||
world_id=3,
|
||||
plane_id=1030101,
|
||||
)
|
||||
Penacony_DreamEdge = MapPlane(
|
||||
id=40,
|
||||
name='Penacony_DreamEdge',
|
||||
cn='筑梦边境',
|
||||
cht='築夢邊境',
|
||||
en="Dream's Edge",
|
||||
jp='ドリームボーダー',
|
||||
es='Frontera de los Sueños',
|
||||
world_id=3,
|
||||
plane_id=2031301,
|
||||
)
|
||||
Penacony_AChildDream = MapPlane(
|
||||
id=41,
|
||||
name='Penacony_AChildDream',
|
||||
cn='稚子的梦',
|
||||
cht='稚子的夢',
|
||||
en="A Child's Dream",
|
||||
jp='稚児の夢',
|
||||
es='Sueño infantil',
|
||||
world_id=3,
|
||||
plane_id=2031201,
|
||||
)
|
||||
Penacony_TheReverieDreamscape = MapPlane(
|
||||
id=42,
|
||||
name='Penacony_TheReverieDreamscape',
|
||||
cn='「白日梦」酒店-梦境',
|
||||
cht='「白日夢」飯店-夢境',
|
||||
en='The Reverie (Dreamscape)',
|
||||
jp='ホテル・レバリー-夢境',
|
||||
es='Hotel Fantasía (paisaje onírico)',
|
||||
world_id=3,
|
||||
plane_id=2031101,
|
||||
)
|
||||
|
@ -11,6 +11,8 @@ Herta_Space_Station = MapWorld(
|
||||
en='Herta Space Station',
|
||||
jp='宇宙ステーション「ヘルタ」',
|
||||
es='Estación Espacial Herta',
|
||||
world_id=0,
|
||||
short_name='Herta',
|
||||
)
|
||||
Jarilo_VI = MapWorld(
|
||||
id=2,
|
||||
@ -20,6 +22,8 @@ Jarilo_VI = MapWorld(
|
||||
en='Jarilo-VI',
|
||||
jp='ヤリーロ-VI',
|
||||
es='Jarilo-VI',
|
||||
world_id=1,
|
||||
short_name='Jarilo',
|
||||
)
|
||||
The_Xianzhou_Luofu = MapWorld(
|
||||
id=3,
|
||||
@ -29,4 +33,17 @@ The_Xianzhou_Luofu = MapWorld(
|
||||
en='The Xianzhou Luofu',
|
||||
jp='仙舟「羅浮」',
|
||||
es='El Luofu de Xianzhou',
|
||||
world_id=2,
|
||||
short_name='Luofu',
|
||||
)
|
||||
Penacony = MapWorld(
|
||||
id=4,
|
||||
name='Penacony',
|
||||
cn='匹诺康尼',
|
||||
cht='匹諾康尼',
|
||||
en='Penacony',
|
||||
jp='ピノコニー',
|
||||
es='Colonipenal',
|
||||
world_id=3,
|
||||
short_name='Penacony',
|
||||
)
|
||||
|
@ -79,9 +79,9 @@ class MapResource(ResourceConst):
|
||||
@cached_property
|
||||
def assets_file_basename(self):
|
||||
if self.plane.has_multiple_floors or self.is_special_plane:
|
||||
return f'./position/{self.plane.world}/{self.plane.name}_{self.floor}'
|
||||
return f'./position/{self.plane.world.short_name}/{self.plane.name}_{self.floor}'
|
||||
else:
|
||||
return f'./position/{self.plane.world}/{self.plane.name}'
|
||||
return f'./position/{self.plane.world.short_name}/{self.plane.name}'
|
||||
|
||||
@cached_property
|
||||
def assets_floor(self):
|
||||
|
Loading…
Reference in New Issue
Block a user