Add: Ocr and select rogue event options

This commit is contained in:
Zebartin 2023-10-07 21:52:41 +08:00
parent 5289b7abcf
commit e48eb27fbc
15 changed files with 1252 additions and 839 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -396,8 +396,12 @@ class KeywordExtract:
for group_title_ids in event_title_texts.values():
group_option_ids = []
for title_id in group_title_ids:
# Special case for Nildis (尼尔迪斯牌)
# Missing option: Give up
if title_id == '13501':
group_option_ids.append(13506)
option_id = title_id
# Name ids in Swarm Disaster(寰宇蝗灾) have a "1" prefix
# Name ids in Swarm Disaster (寰宇蝗灾) have a "1" prefix
if option_id not in option_ids:
option_id = title_id[1:]
# Some name may not has corresponding options
@ -409,8 +413,12 @@ class KeywordExtract:
))
if group_option_ids:
options_grouped[group_title_ids[0]] = group_option_ids
for title_id, options in options_grouped.items():
options_grouped[title_id] = list(clean_options(options))
for title_id in list(options_grouped.keys()):
if len(options_grouped[title_id]) == 0:
options_grouped.pop(title_id)
option_dup_count = defaultdict(int)
for option_hash_list in options_grouped.values():
for option_hash in option_hash_list:

View File

@ -6,12 +6,13 @@ from typing import ClassVar
import module.config.server as server
from module.exception import ScriptError
REGEX_PUNCTUATION = re.compile(r'[ ,.\'"“”,。:;!??·•\-—/\\\n\t()\[\]()「」『』【】《》[]]')
# ord('') = 65294
REGEX_PUNCTUATION = re.compile(r'[ ,.\'"“”,。:;!??·•\-—/\\\n\t()\[\]()「」『』【】《》[]]')
def parse_name(n):
n = REGEX_PUNCTUATION.sub('', str(n)).lower()
return n
return n.strip()
@dataclass

View File

@ -33,13 +33,43 @@ CHOOSE_STORY = ButtonWrapper(
button=(848, 488, 1155, 525),
),
)
OCR_EVENT = ButtonWrapper(
name='OCR_EVENT',
OCR_OPTION = ButtonWrapper(
name='OCR_OPTION',
share=Button(
file='./assets/share/rogue/event/OCR_EVENT.png',
file='./assets/share/rogue/event/OCR_OPTION.png',
area=(789, 71, 1204, 647),
search=(769, 51, 1224, 667),
color=(25, 25, 25),
button=(789, 71, 1204, 647),
),
)
OCR_TITLE = ButtonWrapper(
name='OCR_TITLE',
share=Button(
file='./assets/share/rogue/event/OCR_TITLE.png',
area=(157, 639, 721, 689),
search=(137, 619, 741, 709),
color=(37, 35, 33),
button=(157, 639, 721, 689),
),
)
OPTION_SCROLL = ButtonWrapper(
name='OPTION_SCROLL',
share=Button(
file='./assets/share/rogue/event/OPTION_SCROLL.png',
area=(1214, 72, 1217, 648),
search=(1194, 52, 1237, 668),
color=(192, 171, 129),
button=(1214, 72, 1217, 648),
),
)
REST_AREA = ButtonWrapper(
name='REST_AREA',
share=Button(
file='./assets/share/rogue/event/REST_AREA.png',
area=(338, 222, 498, 382),
search=(318, 202, 518, 402),
color=(140, 127, 184),
button=(338, 222, 498, 382),
),
)

View File

@ -70,31 +70,29 @@ class RogueBuffOcr(Ocr):
"云[摘销锅]?逐步离": "云镝逐步离",
"制桑": "制穹桑",
"乌号基": "乌号綦",
"追摩物": "追孽物",
"流岚追摩?": "流岚追孽物",
"特月": "狩月",
"彤弓素.*": "彤弓素矰",
"白决射御": "白矢决射御",
"苦表": "苦衷",
"[沦沧]肌髓": "沦浃肌髓",
"[沦沧][決]?肌髓": "沦浃肌髓",
"进发": "迸发",
"永缩体": "永坍缩体",
"完美体验:绒默": "完美体验:缄默",
"灭回归不等式": "湮灭回归不等式",
"[涯]?灭回归不等式": "湮灭回归不等式",
r".*灾$": "禳灾",
"虚安供品": "虚妄供品",
"原初的苦$": "原初的苦衷",
"厌离邪": "厌离邪秽苦",
"厌离邪[移]?": "厌离邪秽苦",
r".*繁.*": "葳蕤繁祉,延彼遐龄",
}
for pat, replace in replace_pattern_dict.items():
result = re.sub(pat, replace, result)
elif self.lang == 'en':
replace_pattern_dict = {
"RestIin": "Restin",
}
for pat, replace in replace_pattern_dict.items():
result = re.sub(pat, replace, result)
return result
for pat, replace in replace_pattern_dict.items():
after = re.sub(pat, replace, result)
return after
class RogueBlessingSelector(RogueSelector):

View File

@ -1,12 +1,158 @@
import random
import re
from dataclasses import dataclass
from functools import cached_property
from pponnxcr.predict_system import BoxedResult
from module.base.button import ClickButton
from module.base.utils import area_limit
from module.base.decorator import del_cached_property
from module.base.utils import area_limit, area_offset
from module.exception import ScriptError
from module.logger import logger
from tasks.rogue.assets.assets_rogue_event import CHOOSE_OPTION, CHOOSE_OPTION_CONFIRM, CHOOSE_STORY, OCR_EVENT
from module.ocr.ocr import Ocr, OcrResultButton
from module.ui.scroll import Scroll
from tasks.rogue.assets.assets_rogue_event import *
from tasks.rogue.assets.assets_rogue_ui import BLESSING_CONFIRM, PAGE_EVENT
from tasks.rogue.bleesing.ui import RogueUI
from tasks.rogue.event.preset import STRATEGIES, STRATEGY_COMMON
from tasks.rogue.keywords import (KEYWORDS_ROGUE_EVENT_OPTION,
KEYWORDS_ROGUE_EVENT_TITLE, RogueEventOption,
RogueEventTitle)
@dataclass
class OptionButton:
prefix_icon: ClickButton
button: OcrResultButton = None
is_valid: bool = True # Option with requirements might be disabled
is_bottom_page: bool = False
def __str__(self) -> str:
if self.button is not None:
return str(self.button.matched_keyword)
return super().__str__()
class OcrRogueEvent(Ocr):
merge_thres_y = 5
OCR_REPLACE = {
'cn': [],
'en': []
}
@cached_property
def ocr_regex(self) -> re.Pattern | None:
rules = self.OCR_REPLACE.get(self.lang)
if not rules:
return None
return re.compile('|'.join(
f'(?P<{kw.name}>{pat})'
for kw, pat in rules
))
def _after_process(self, result, keyword_class):
result = super().after_process(result)
if self.ocr_regex is None:
return result
matched = self.ocr_regex.fullmatch(result)
if matched is None:
return result
if not hasattr(keyword_class, matched.lastgroup):
raise ScriptError(f'No keyword found for {matched.lastgroup}')
matched = getattr(keyword_class, matched.lastgroup)
matched = getattr(matched, self.lang)
return matched
class OcrRogueEventTitle(OcrRogueEvent):
OCR_REPLACE = {
'cn': [
(KEYWORDS_ROGUE_EVENT_TITLE.Rock_Paper_Scissors, '^猜拳.*'),
(KEYWORDS_ROGUE_EVENT_TITLE.Ka_ching_IPC_Banking_Part_1, '^咔.*其一.*'),
(KEYWORDS_ROGUE_EVENT_TITLE.Ka_ching_IPC_Banking_Part_2, '^咔.*其二.*'),
],
'en': [
(KEYWORDS_ROGUE_EVENT_TITLE.Nomadic_Miners, '^Nomadic.*'),
(KEYWORDS_ROGUE_EVENT_TITLE.Nildis, '^Nildis.*'),
(KEYWORDS_ROGUE_EVENT_TITLE.Tavern, '^Tavern.*'),
(KEYWORDS_ROGUE_EVENT_TITLE.Insights_from_the_Universal_Dancer, '.*Dancer$'),
]
}
def after_process(self, result):
result = result.replace('卫成', '卫戍') # 虫潮·虫巢探险X级卫戍
return self._after_process(result, KEYWORDS_ROGUE_EVENT_TITLE)
class OcrRogueEventOption(OcrRogueEvent):
expected_options: list[OptionButton] = []
OCR_REPLACE = {
'cn': [
# Special cases with placeholder
(KEYWORDS_ROGUE_EVENT_OPTION.Deposit_2_Cosmic_Fragments_91, '存入\d+.*'),
(KEYWORDS_ROGUE_EVENT_OPTION.Withdraw_2_Cosmic_Fragments_91, '取出\d+.*'),
(KEYWORDS_ROGUE_EVENT_OPTION.Record_of_the_Aeon_of_1, '^关于.*'),
(KEYWORDS_ROGUE_EVENT_OPTION.I_ll_buy_it, '我买下?了'),
(KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_them, '^等待.*'),
(KEYWORDS_ROGUE_EVENT_OPTION.Choose_number_two_It_snores_like_Andatur_Zazzalo, '.*二号.*安达.*'),
(KEYWORDS_ROGUE_EVENT_OPTION.Choose_number_three_Its_teeth_are_rusted, '.*三号.*牙齿.*'),
],
'en': [
(KEYWORDS_ROGUE_EVENT_OPTION.Deposit_2_Cosmic_Fragments_91, 'Deposit \d+.*'),
(KEYWORDS_ROGUE_EVENT_OPTION.Withdraw_2_Cosmic_Fragments_91, 'Withdraw \d+.*'),
(KEYWORDS_ROGUE_EVENT_OPTION.Record_of_the_Aeon_of_1,
'^Record of the Aeon.*'),
]
}
def filter_detected(self, result: BoxedResult) -> bool:
if not self.expected_options:
return True
right_bound = self.expected_options[0].prefix_icon.area[2]
if result.box[0] < right_bound:
return False
return True
def pre_process(self, image):
# Mask starlike icons to avoid them to be recognized as */#/+/米
offset = tuple(-x for x in self.button.area[:2])
for option in self.expected_options:
x1, y1, x2, y2 = area_offset(option.prefix_icon.area, offset)
image[y1:y2, x1:x2] = (0, 0, 0)
return image
def after_process(self, result):
return self._after_process(result, KEYWORDS_ROGUE_EVENT_OPTION)
class OptionScroll(Scroll):
def position_to_screen(self, position, random_range=(-0.05, 0.05)):
# This scroll itself can not be dragged, but OCR_OPTION.area can
area = super().position_to_screen(position, random_range)
ocr_area_width = OCR_OPTION.area[2] - OCR_OPTION.area[0]
# A fixed offset is easy to fail for some reason
random_offset = random.uniform(0.2, 0.8) * ocr_area_width
area = area_offset(area, (-random_offset, 0))
# Flip drag direction upside down
return (
area[0], self.area[1] + self.area[3] - area[1],
area[2], self.area[1] + self.area[3] - area[3],
)
SCROLL_OPTION = OptionScroll(OPTION_SCROLL, color=(
219, 194, 145), name='SCROLL_OPTION')
class RogueEvent(RogueUI):
title: RogueEventTitle = None
options: list[OptionButton] = []
@cached_property
def valid_options(self) -> list[OptionButton]:
return [x for x in self.options if x.is_valid]
def handle_event_continue(self):
if self.appear(PAGE_EVENT, interval=0.6):
logger.info(f'{PAGE_EVENT} -> {BLESSING_CONFIRM}')
@ -25,34 +171,147 @@ class RogueEvent(RogueUI):
return False
def handle_event_option(self):
options = CHOOSE_OPTION.match_multi_template(self.device.image)
# Check color also, option with requirements might be disabled
options = [
option for option in options
if self.image_color_count(option.area, color=(181, 162, 126), threshold=221, count=25)
]
count = len(options)
"""
self.title SHOULD be set to None before calling this function
Pages:
in: page_rogue
"""
self.options = []
del_cached_property(self, 'valid_options')
self._event_option_match()
count = len(self.valid_options)
if count == 0:
return False
logger.attr('EventOption', count)
for button in options:
button.button = area_limit(button.button, OCR_EVENT.area)
logger.attr('EventOption', f'{count}/{len(self.options)}')
# Only one option, click directly
if count == 1:
if self.interval_is_reached(CHOOSE_OPTION, interval=2):
self.device.click(options[0])
self.device.click(self.valid_options[0].prefix_icon)
self.interval_reset(CHOOSE_OPTION)
return True
if self.interval_is_reached(CHOOSE_OPTION, interval=2):
option = self._event_option_filter(options)
self.device.click(option)
option = self._event_option_filter()
if SCROLL_OPTION.appear(main=self):
if option.is_bottom_page:
SCROLL_OPTION.set_bottom(main=self)
else:
SCROLL_OPTION.set_top(main=self)
self.device.click(option.prefix_icon)
self.interval_reset(CHOOSE_OPTION)
return True
return False
def _event_option_filter(self, options: list[ClickButton]) -> ClickButton:
# TODO: OCR options instead of choosing the last one
return options[-1]
def _event_option_match(self, is_bottom_page=False) -> int:
"""
Returns:
int: Number of option icons matched
"""
option_icons = CHOOSE_OPTION.match_multi_template(self.device.image)
for button in option_icons:
button.button = area_limit(button.button, OCR_OPTION.area)
self.options += [OptionButton(
prefix_icon=icon,
is_valid=self.image_color_count(icon.area, color=(
181, 162, 126), threshold=221, count=25),
is_bottom_page=is_bottom_page
) for icon in option_icons]
if option_icons:
del_cached_property(self, 'valid_options')
return len(option_icons)
def _event_option_ocr(self, expected_count: int) -> None:
"""
Reason why _keywords_to_find()[0] is used to compare:
Text of options in different events can be the same,
so it is possible that keywords returned by matched_ocr
is not exactly the same as options in RogueEventTitle.option_ids.
Args:
expected_count (int): Number of option icons matched
"""
expected_options = self.options[-expected_count:]
ocr = OcrRogueEventOption(OCR_OPTION)
ocr.expected_options = expected_options
possible_options = {
RogueEventOption.find(option_id)._keywords_to_find()[0]
for option_id in self.title.option_ids
}
ocr_results = ocr.matched_ocr(self.device.image, [RogueEventOption])
ocr_results = [
x for x in ocr_results
if x.matched_keyword._keywords_to_find()[0] in possible_options
]
# Pair icons and ocr results
index = 0
all_matched = True
for option in expected_options:
_, y1, _, y2 = option.prefix_icon.area
for index in range(index, len(ocr_results)):
_, yy1, _, yy2 = ocr_results[index].area
if yy2 < y1:
continue
if yy1 > y2:
break
option.button = ocr_results[index]
break
if option.button is None:
option.is_valid = False
all_matched = False
if not all_matched:
logger.warning('Count of OCR_OPTION results is not as expected')
del_cached_property(self, 'valid_options')
def _event_option_filter(self) -> OptionButton:
if self.title is None:
# OCR area of rest area is different from other occurrences
if self.appear(REST_AREA):
self.title = KEYWORDS_ROGUE_EVENT_TITLE.Rest_Area
else:
# Title may contains multi lines
results = OcrRogueEventTitle(OCR_TITLE).matched_ocr(
self.device.image,
[RogueEventTitle]
)
if results:
self.title = results[0].matched_keyword
if self.title is None:
random_index = random.choice(range(len(self.valid_options)))
logger.warning('Failed to OCR title')
logger.info(f'Randomly select option {random_index+1}')
return self.valid_options[random_index]
strategy_name = self.config.RoguePath_DomainStrategy
logger.attr('DomainStrategy', strategy_name)
if strategy_name not in STRATEGIES:
logger.warning(
'Unknown domain strategy, fall back to STRATEGY_COMMON'
)
strategy = STRATEGIES.get(strategy_name, STRATEGY_COMMON)
if self.title not in strategy:
random_index = random.choice(range(len(self.valid_options)))
logger.info(f'No strategy preset for {self.title}')
logger.info(f'Randomly select option {random_index+1}')
return self.valid_options[random_index]
# Try ocr
if not self.options:
self._event_option_match()
self._event_option_ocr(len(self.options))
# Check next page if there is scroll
if SCROLL_OPTION.appear(main=self):
if SCROLL_OPTION.set_bottom(main=self):
expected = self._event_option_match(is_bottom_page=True)
self._event_option_ocr(expected)
for expect in strategy[self.title]:
for i, option in enumerate(self.valid_options):
ocr_text = option.button.matched_keyword._keywords_to_find()[0]
expect_text = expect._keywords_to_find()[0]
if ocr_text == expect_text:
logger.info(f'Select option {i+1}: {option}')
return option
logger.error('No option was selected, return the last instead')
logger.info(f'Select last option: {self.valid_options[-1]}')
return self.valid_options[-1]

114
tasks/rogue/event/preset.py Normal file
View File

@ -0,0 +1,114 @@
from tasks.rogue.keywords import KEYWORDS_ROGUE_EVENT_TITLE, KEYWORDS_ROGUE_EVENT_OPTION
# TODO: events that only come up in Swarm Disaster (寰宇蝗灾)
STRATEGY_COMMON = {
KEYWORDS_ROGUE_EVENT_TITLE.Rest_Area: [
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_1_Curio,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_1_star_Blessing,
KEYWORDS_ROGUE_EVENT_OPTION.Enhance_2_random_Blessings
],
KEYWORDS_ROGUE_EVENT_TITLE.Shopping_Channel: [
KEYWORDS_ROGUE_EVENT_OPTION.A_lotus_that_can_sing_the_Happy_Birthday_song,
KEYWORDS_ROGUE_EVENT_OPTION.A_mechanical_box,
KEYWORDS_ROGUE_EVENT_OPTION.A_box_of_expired_doughnuts
],
KEYWORDS_ROGUE_EVENT_TITLE.Interactive_Arts: [
KEYWORDS_ROGUE_EVENT_OPTION.Action,
KEYWORDS_ROGUE_EVENT_OPTION.Musical
],
KEYWORDS_ROGUE_EVENT_TITLE.I_O_U_Dispenser: [
KEYWORDS_ROGUE_EVENT_OPTION.You_re_not_a_reliable_investment_manager,
KEYWORDS_ROGUE_EVENT_OPTION.I_hate_this_era,
KEYWORDS_ROGUE_EVENT_OPTION.I_don_t_want_anything_This_is_very_nihilistic,
KEYWORDS_ROGUE_EVENT_OPTION.I_don_t_need_it
],
KEYWORDS_ROGUE_EVENT_TITLE.Statue: [
KEYWORDS_ROGUE_EVENT_OPTION.Believe_in_them_with_pure_devotion,
KEYWORDS_ROGUE_EVENT_OPTION.Discard_the_statue_Be_decisive
],
KEYWORDS_ROGUE_EVENT_TITLE.Unending_Darkness: [
KEYWORDS_ROGUE_EVENT_OPTION.Fight_the_pull,
KEYWORDS_ROGUE_EVENT_OPTION.Head_into_the_darkness,
],
KEYWORDS_ROGUE_EVENT_TITLE.Cosmic_Merchant_Part_1: [
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_metal_Wish_In_A_Bottle,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_silver_ore_Wish_In_A_Bottle_18,
KEYWORDS_ROGUE_EVENT_OPTION.Leave_18
],
KEYWORDS_ROGUE_EVENT_TITLE.Cosmic_Con_Job_Part_2: [
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_an_amber_Wish_In_A_Bottle_19,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_supernium_Wish_In_A_Bottle_19,
KEYWORDS_ROGUE_EVENT_OPTION.Leave_19
],
KEYWORDS_ROGUE_EVENT_TITLE.Cosmic_Altruist_Part_3: [
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_diamond_box_20,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_an_ore_box_20,
KEYWORDS_ROGUE_EVENT_OPTION.Leave_20
],
KEYWORDS_ROGUE_EVENT_TITLE.Make_A_Wish: [
KEYWORDS_ROGUE_EVENT_OPTION.Exchange_for_a_3_star_Blessing,
KEYWORDS_ROGUE_EVENT_OPTION.Exchange_for_a_2_star_Blessing,
KEYWORDS_ROGUE_EVENT_OPTION.Leave_33
],
KEYWORDS_ROGUE_EVENT_TITLE.Robot_Sales_Terminal: [
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_1_3_star_Blessing,
KEYWORDS_ROGUE_EVENT_OPTION.Purchase_a_1_2_star_Blessing,
KEYWORDS_ROGUE_EVENT_OPTION.Leave_34
],
KEYWORDS_ROGUE_EVENT_TITLE.Insights_from_the_Universal_Dancer: [
KEYWORDS_ROGUE_EVENT_OPTION.Tell_fortune,
KEYWORDS_ROGUE_EVENT_OPTION.Refuse_invitation
]
}
STRATEGY_FIGHT = {
KEYWORDS_ROGUE_EVENT_TITLE.Insect_Nest: [
KEYWORDS_ROGUE_EVENT_OPTION.Go_deeper_into_the_insect_nest,
KEYWORDS_ROGUE_EVENT_OPTION.Hug_it,
KEYWORDS_ROGUE_EVENT_OPTION.Stop_at_the_entrance_of_the_nest,
KEYWORDS_ROGUE_EVENT_OPTION.Wait_for_them
],
KEYWORDS_ROGUE_EVENT_TITLE.Three_Little_Pigs: [
KEYWORDS_ROGUE_EVENT_OPTION.Leave_14,
KEYWORDS_ROGUE_EVENT_OPTION.Play_a_bit_with_Sequence_Trotters
],
KEYWORDS_ROGUE_EVENT_TITLE.Kindling_of_the_Self_Annihilator: [
KEYWORDS_ROGUE_EVENT_OPTION.Accept_the_flames_of_Self_destruction_and_destroy_the_black_box,
KEYWORDS_ROGUE_EVENT_OPTION.Refuse_17
],
KEYWORDS_ROGUE_EVENT_TITLE.Societal_Dreamscape: [
KEYWORDS_ROGUE_EVENT_OPTION.Swallow_the_other_fish_eye_and_continue_to_enjoy_the_massage,
KEYWORDS_ROGUE_EVENT_OPTION.Return_to_work
],
KEYWORDS_ROGUE_EVENT_TITLE.Bounty_Hunter: [
KEYWORDS_ROGUE_EVENT_OPTION.Give_him_the_fur_you_re_wearing,
KEYWORDS_ROGUE_EVENT_OPTION.Walk_away_25
],
KEYWORDS_ROGUE_EVENT_TITLE.Implement_of_Error: [
KEYWORDS_ROGUE_EVENT_OPTION.Pick_an_Error_Code_Curio,
KEYWORDS_ROGUE_EVENT_OPTION.Leave_26
],
KEYWORDS_ROGUE_EVENT_TITLE.We_Are_Cowboys: [
KEYWORDS_ROGUE_EVENT_OPTION.Protect_the_cowboy_final_honor,
KEYWORDS_ROGUE_EVENT_OPTION.Pay
],
KEYWORDS_ROGUE_EVENT_TITLE.Nildis: [
KEYWORDS_ROGUE_EVENT_OPTION.Flip_the_card,
KEYWORDS_ROGUE_EVENT_OPTION.Give_up
],
KEYWORDS_ROGUE_EVENT_TITLE.Rock_Paper_Scissors: [
KEYWORDS_ROGUE_EVENT_OPTION.Fight_for_the_0_63_chance,
KEYWORDS_ROGUE_EVENT_OPTION.Pick_the_100_security
],
KEYWORDS_ROGUE_EVENT_TITLE.Tavern: [
KEYWORDS_ROGUE_EVENT_OPTION.Fight_both_together,
KEYWORDS_ROGUE_EVENT_OPTION.Challenge_Mr_France_security_team,
KEYWORDS_ROGUE_EVENT_OPTION.Challenge_the_burly_Avila_mercenary_company
]
}
STRATEGY_LEAVE = dict()
for k, v in STRATEGY_FIGHT.items():
STRATEGY_LEAVE[k] = list(reversed(v))
STRATEGIES = {
'leave': {**STRATEGY_LEAVE, **STRATEGY_COMMON},
'fight': {**STRATEGY_FIGHT, **STRATEGY_COMMON}
}

View File

@ -75,6 +75,9 @@ class RogueEventTitle(Keyword):
instances: ClassVar = {}
option_ids: list[int]
def __hash__(self):
return super().__hash__()
@dataclass(repr=False)
class RogueEventOption(Keyword):

File diff suppressed because it is too large Load Diff

View File

@ -281,7 +281,7 @@ Nildis = RogueEventTitle(
en='Nildis',
jp='ニールディスカード',
es='Nildis',
option_ids=[121],
option_ids=[121, 122],
)
Rock_Paper_Scissors = RogueEventTitle(
id=29,
@ -291,7 +291,7 @@ Rock_Paper_Scissors = RogueEventTitle(
en='Rock, Paper, Scissors',
jp='じゃんけん',
es='Piedra, papel o tijera',
option_ids=[122, 123, 124, 125],
option_ids=[123, 124, 125, 126],
)
Tavern = RogueEventTitle(
id=30,
@ -301,7 +301,7 @@ Tavern = RogueEventTitle(
en='Tavern',
jp='パブ',
es='Taberna',
option_ids=[126, 127, 128, 129, 130],
option_ids=[127, 128, 129, 130, 131],
)
Periodic_Demon_Lord = RogueEventTitle(
id=31,
@ -311,7 +311,7 @@ Periodic_Demon_Lord = RogueEventTitle(
en='Periodic Demon Lord',
jp='周期性大魔王',
es='Rey Demonio Cíclico',
option_ids=[131, 132],
option_ids=[132, 133],
)
Let_Exchange_Gifts = RogueEventTitle(
id=32,
@ -321,7 +321,7 @@ Let_Exchange_Gifts = RogueEventTitle(
en="Let's Exchange Gifts",
jp='プレゼントを交換しようよ',
es='¡Intercambiemos regalos!',
option_ids=[133, 134, 135, 136, 137],
option_ids=[134, 135, 136, 137, 138],
)
Make_A_Wish = RogueEventTitle(
id=33,
@ -331,7 +331,7 @@ Make_A_Wish = RogueEventTitle(
en='Make A Wish',
jp='願い事しようよ',
es='Pide un deseo',
option_ids=[138, 139, 140, 141],
option_ids=[139, 140, 141, 142],
)
Robot_Sales_Terminal = RogueEventTitle(
id=34,
@ -341,7 +341,7 @@ Robot_Sales_Terminal = RogueEventTitle(
en='Robot Sales Terminal',
jp='ロボット販売端末',
es='Terminal de venta de robots',
option_ids=[142, 143, 144, 145, 146],
option_ids=[143, 144, 145, 146, 147],
)
Sand_King_Tayzzyronth_Part_1 = RogueEventTitle(
id=35,
@ -351,7 +351,7 @@ Sand_King_Tayzzyronth_Part_1 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 1)',
jp='「砂の王-タイズルス」・その1',
es='Rey de la Arena: Tayzzyronth(I)',
option_ids=[147, 148],
option_ids=[148, 149],
)
Sand_King_Tayzzyronth_Part_2 = RogueEventTitle(
id=36,
@ -361,7 +361,7 @@ Sand_King_Tayzzyronth_Part_2 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 2)',
jp='「砂の王-タイズルス」・その2',
es='Rey de la Arena: Tayzzyronth(II)',
option_ids=[149, 150],
option_ids=[150, 151],
)
Sand_King_Tayzzyronth_Part_3 = RogueEventTitle(
id=37,
@ -371,7 +371,7 @@ Sand_King_Tayzzyronth_Part_3 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 3)',
jp='「砂の王-タイズルス」・その3',
es='Rey de la Arena: Tayzzyronth(III)',
option_ids=[151, 152],
option_ids=[152, 153],
)
Sand_King_Tayzzyronth_Part_4 = RogueEventTitle(
id=38,
@ -381,7 +381,7 @@ Sand_King_Tayzzyronth_Part_4 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 4)',
jp='「砂の王-タイズルス」・その4',
es='Rey de la Arena: Tayzzyronth(IV)',
option_ids=[153, 154, 155, 156],
option_ids=[154, 155, 156, 157],
)
Sand_King_Tayzzyronth_Part_5 = RogueEventTitle(
id=39,
@ -391,7 +391,7 @@ Sand_King_Tayzzyronth_Part_5 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 5)',
jp='「砂の王-タイズルス」・その5',
es='Rey de la Arena: Tayzzyronth(V)',
option_ids=[157, 158],
option_ids=[158, 159],
)
Sand_King_Tayzzyronth_Part_6 = RogueEventTitle(
id=40,
@ -401,7 +401,7 @@ Sand_King_Tayzzyronth_Part_6 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 6)',
jp='「砂の王-タイズルス」・その6',
es='Rey de la Arena: Tayzzyronth(VI)',
option_ids=[159, 160, 161],
option_ids=[160, 161, 162],
)
Sand_King_Tayzzyronth_Part_7 = RogueEventTitle(
id=41,
@ -411,7 +411,7 @@ Sand_King_Tayzzyronth_Part_7 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 7)',
jp='「砂の王-タイズルス」・その7',
es='Rey de la Arena: Tayzzyronth(VII)',
option_ids=[162, 163],
option_ids=[163, 164],
)
Sand_King_Tayzzyronth_Part_8 = RogueEventTitle(
id=42,
@ -421,7 +421,7 @@ Sand_King_Tayzzyronth_Part_8 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 8)',
jp='「砂の王-タイズルス」・その8',
es='Rey de la Arena: Tayzzyronth(VIII)',
option_ids=[164, 165],
option_ids=[165, 166],
)
Sand_King_Tayzzyronth_Part_9 = RogueEventTitle(
id=43,
@ -431,7 +431,7 @@ Sand_King_Tayzzyronth_Part_9 = RogueEventTitle(
en='Sand King: Tayzzyronth (Part 9)',
jp='「砂の王-タイズルス」・その9',
es='Rey de la Arena: Tayzzyronth(IX)',
option_ids=[166, 167],
option_ids=[167, 168],
)
Lepismat_System_Massacre_Saga_Part_1 = RogueEventTitle(
id=44,
@ -441,7 +441,7 @@ Lepismat_System_Massacre_Saga_Part_1 = RogueEventTitle(
en='Lepismat System: Massacre Saga (Part 1)',
jp='「蟲星系-虐殺紀」・その1',
es='Galaxia de Insectiria: saga de la masacre(I)',
option_ids=[168, 169],
option_ids=[169, 170],
)
Lepismat_System_Massacre_Saga_Part_2 = RogueEventTitle(
id=45,
@ -451,7 +451,7 @@ Lepismat_System_Massacre_Saga_Part_2 = RogueEventTitle(
en='Lepismat System: Massacre Saga (Part 2)',
jp='「蟲星系-虐殺紀」・その2',
es='Galaxia de Insectiria: saga de la masacre(II)',
option_ids=[170, 171],
option_ids=[171, 172],
)
Lepismat_System_Massacre_Saga_Part_3 = RogueEventTitle(
id=46,
@ -461,7 +461,7 @@ Lepismat_System_Massacre_Saga_Part_3 = RogueEventTitle(
en='Lepismat System: Massacre Saga (Part 3)',
jp='「蟲星系-虐殺紀」・その3',
es='Galaxia de Insectiria: saga de la masacre(III)',
option_ids=[172, 173],
option_ids=[173, 174],
)
Lepismat_System_Massacre_Saga_Part_4 = RogueEventTitle(
id=47,
@ -471,7 +471,7 @@ Lepismat_System_Massacre_Saga_Part_4 = RogueEventTitle(
en='Lepismat System: Massacre Saga (Part 4)',
jp='「蟲星系-虐殺紀」・その4',
es='Galaxia de Insectiria: saga de la masacre(IV)',
option_ids=[174, 175],
option_ids=[175, 176],
)
Lepismat_System_Massacre_Saga_Part_5 = RogueEventTitle(
id=48,
@ -481,7 +481,7 @@ Lepismat_System_Massacre_Saga_Part_5 = RogueEventTitle(
en='Lepismat System: Massacre Saga (Part 5)',
jp='「蟲星系-虐殺紀」・その5',
es='Galaxia de Insectiria: saga de la masacre(V)',
option_ids=[176, 177],
option_ids=[177, 178],
)
Lepismat_System_Massacre_Saga_Part_6 = RogueEventTitle(
id=49,
@ -491,7 +491,7 @@ Lepismat_System_Massacre_Saga_Part_6 = RogueEventTitle(
en='Lepismat System: Massacre Saga (Part 6)',
jp='「蟲星系-虐殺紀」・その6',
es='Galaxia de Insectiria: saga de la masacre(VI)',
option_ids=[178, 179],
option_ids=[179, 180],
)
Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_1 = RogueEventTitle(
id=50,
@ -501,7 +501,7 @@ Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_1 = RogueEventTitle(
en='Bounty Hunter: Crimson Cleansing Chronicle (Part 1)',
jp='「賞金稼ぎ-洗狩紀」・その1',
es='Cazarrecompensas: crónica de la depuración carmesí(I)',
option_ids=[180, 181],
option_ids=[181, 182],
)
Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_2 = RogueEventTitle(
id=51,
@ -511,7 +511,7 @@ Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_2 = RogueEventTitle(
en='Bounty Hunter: Crimson Cleansing Chronicle (Part 2)',
jp='「賞金稼ぎ-洗狩紀」・その2',
es='Cazarrecompensas: crónica de la depuración carmesí(II)',
option_ids=[182],
option_ids=[183],
)
Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_3 = RogueEventTitle(
id=52,
@ -521,7 +521,7 @@ Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_3 = RogueEventTitle(
en='Bounty Hunter: Crimson Cleansing Chronicle (Part 3)',
jp='「賞金稼ぎ-洗狩紀」・その3',
es='Cazarrecompensas: crónica de la depuración carmesí(III)',
option_ids=[183, 184],
option_ids=[184, 185],
)
Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_4 = RogueEventTitle(
id=53,
@ -531,7 +531,7 @@ Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_4 = RogueEventTitle(
en='Bounty Hunter: Crimson Cleansing Chronicle (Part 4)',
jp='「賞金稼ぎ-洗狩紀」・その4',
es='Cazarrecompensas: crónica de la depuración carmesí(IV)',
option_ids=[185, 186],
option_ids=[186, 187],
)
Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_5 = RogueEventTitle(
id=54,
@ -541,7 +541,7 @@ Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_5 = RogueEventTitle(
en='Bounty Hunter: Crimson Cleansing Chronicle (Part 5)',
jp='「賞金稼ぎ-洗狩紀」・その5',
es='Cazarrecompensas: crónica de la depuración carmesí(V)',
option_ids=[187, 188],
option_ids=[188, 189],
)
Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_6 = RogueEventTitle(
id=55,
@ -551,7 +551,7 @@ Bounty_Hunter_Crimson_Cleansing_Chronicle_Part_6 = RogueEventTitle(
en='Bounty Hunter: Crimson Cleansing Chronicle (Part 6)',
jp='「賞金稼ぎ-洗狩紀」・その6',
es='Cazarrecompensas: crónica de la depuración carmesí(VI)',
option_ids=[189],
option_ids=[190],
)
Tragedy_and_Insects_The_Dwindling_of_Stars_Part_1 = RogueEventTitle(
id=56,
@ -561,7 +561,7 @@ Tragedy_and_Insects_The_Dwindling_of_Stars_Part_1 = RogueEventTitle(
en='Tragedy and Insects: The Dwindling of Stars (Part 1)',
jp='「凶と虫-諸星消滅紀」・その1',
es='Tragedia e insectos: el ocaso de las estrellas(I)',
option_ids=[190, 191],
option_ids=[191, 192],
)
Tragedy_and_Insects_The_Dwindling_of_Stars_Part_2 = RogueEventTitle(
id=57,
@ -571,7 +571,7 @@ Tragedy_and_Insects_The_Dwindling_of_Stars_Part_2 = RogueEventTitle(
en='Tragedy and Insects: The Dwindling of Stars (Part 2)',
jp='「凶と虫-諸星消滅紀」・その2',
es='Tragedia e insectos: el ocaso de las estrellas(II)',
option_ids=[192, 193],
option_ids=[193, 194],
)
Tragedy_and_Insects_The_Dwindling_of_Stars_Part_3 = RogueEventTitle(
id=58,
@ -581,7 +581,7 @@ Tragedy_and_Insects_The_Dwindling_of_Stars_Part_3 = RogueEventTitle(
en='Tragedy and Insects: The Dwindling of Stars (Part 3)',
jp='「凶と虫-諸星消滅紀」・その3',
es='Tragedia e insectos: el ocaso de las estrellas(III)',
option_ids=[194, 195],
option_ids=[195, 196],
)
Tragedy_and_Insects_The_Dwindling_of_Stars_Part_4 = RogueEventTitle(
id=59,
@ -591,7 +591,7 @@ Tragedy_and_Insects_The_Dwindling_of_Stars_Part_4 = RogueEventTitle(
en='Tragedy and Insects: The Dwindling of Stars (Part 4)',
jp='「凶と虫-諸星消滅紀」・その4',
es='Tragedia e insectos: el ocaso de las estrellas(IV)',
option_ids=[196, 197],
option_ids=[197, 198],
)
Tragedy_and_Insects_The_Dwindling_of_Stars_Part_5 = RogueEventTitle(
id=60,
@ -601,7 +601,7 @@ Tragedy_and_Insects_The_Dwindling_of_Stars_Part_5 = RogueEventTitle(
en='Tragedy and Insects: The Dwindling of Stars (Part 5)',
jp='「凶と虫-諸星消滅紀」・その5',
es='Tragedia e insectos: el ocaso de las estrellas(V)',
option_ids=[198, 199],
option_ids=[199, 200],
)
Tragedy_and_Insects_The_Dwindling_of_Stars_Part_6 = RogueEventTitle(
id=61,
@ -611,7 +611,7 @@ Tragedy_and_Insects_The_Dwindling_of_Stars_Part_6 = RogueEventTitle(
en='Tragedy and Insects: The Dwindling of Stars (Part 6)',
jp='「凶と虫-諸星消滅紀」・その6',
es='Tragedia e insectos: el ocaso de las estrellas(VI)',
option_ids=[200, 201, 202],
option_ids=[201, 202, 203],
)
Genius_Society_Regular_Experiments_Part_1 = RogueEventTitle(
id=62,
@ -621,7 +621,7 @@ Genius_Society_Regular_Experiments_Part_1 = RogueEventTitle(
en='Genius Society: Regular Experiments (Part 1)',
jp='「天才クラブ-通常実験」・その1',
es='Círculo de Genios: experimentos cotidianos(I)',
option_ids=[203, 204],
option_ids=[204, 205],
)
Genius_Society_Regular_Experiments_Part_2 = RogueEventTitle(
id=63,
@ -631,7 +631,7 @@ Genius_Society_Regular_Experiments_Part_2 = RogueEventTitle(
en='Genius Society: Regular Experiments (Part 2)',
jp='「天才クラブ-通常実験」・その2',
es='Círculo de Genios: experimentos cotidianos(II)',
option_ids=[205, 206],
option_ids=[206, 207],
)
Genius_Society_Regular_Experiments_Part_3 = RogueEventTitle(
id=64,
@ -641,7 +641,7 @@ Genius_Society_Regular_Experiments_Part_3 = RogueEventTitle(
en='Genius Society: Regular Experiments (Part 3)',
jp='「天才クラブ-通常実験」・その3',
es='Círculo de Genios: experimentos cotidianos(III)',
option_ids=[207, 208],
option_ids=[208, 209],
)
Gondola_Helping_Gods_Part_1 = RogueEventTitle(
id=65,
@ -651,7 +651,7 @@ Gondola_Helping_Gods_Part_1 = RogueEventTitle(
en='Gondola: Helping Gods! (Part 1)',
jp='「ゴンドラ-神を助ける」・その1',
es='Góndola: ¡ayudando a los dioses!(I)',
option_ids=[209, 210],
option_ids=[210, 211],
)
Gondola_Helping_Gods_Part_2 = RogueEventTitle(
id=66,
@ -661,7 +661,7 @@ Gondola_Helping_Gods_Part_2 = RogueEventTitle(
en='Gondola: Helping Gods! (Part 2)',
jp='「ゴンドラ-神を助ける」・その2',
es='Góndola: ¡ayudando a los dioses!(II)',
option_ids=[211, 212],
option_ids=[212, 213],
)
Gondola_Helping_Gods_Part_3 = RogueEventTitle(
id=67,
@ -671,7 +671,7 @@ Gondola_Helping_Gods_Part_3 = RogueEventTitle(
en='Gondola: Helping Gods! (Part 3)',
jp='「ゴンドラ-神を助ける」・その3',
es='Góndola: ¡ayudando a los dioses!(III)',
option_ids=[213, 214],
option_ids=[214, 215],
)
Gondola_Helping_Gods_Part_4 = RogueEventTitle(
id=68,
@ -681,7 +681,7 @@ Gondola_Helping_Gods_Part_4 = RogueEventTitle(
en='Gondola: Helping Gods! (Part 4)',
jp='「ゴンドラ-神を助ける」・その4',
es='Góndola: ¡ayudando a los dioses!(IV)',
option_ids=[215, 216],
option_ids=[216, 217],
)
Gondola_Helping_Gods_Part_5 = RogueEventTitle(
id=69,
@ -691,7 +691,7 @@ Gondola_Helping_Gods_Part_5 = RogueEventTitle(
en='Gondola: Helping Gods! (Part 5)',
jp='「ゴンドラ-神を助ける」・その5',
es='Góndola: ¡ayudando a los dioses!(V)',
option_ids=[217, 218],
option_ids=[218, 219],
)
Gondola_Helping_Gods_Part_6 = RogueEventTitle(
id=70,
@ -701,7 +701,7 @@ Gondola_Helping_Gods_Part_6 = RogueEventTitle(
en='Gondola: Helping Gods! (Part 6)',
jp='「ゴンドラ-神を助ける」・その6',
es='Góndola: ¡ayudando a los dioses!(VI)',
option_ids=[219, 220],
option_ids=[220, 221],
)
Beyond_the_Sky_Choir_Anomaly_Archives_Part_1 = RogueEventTitle(
id=71,
@ -711,7 +711,7 @@ Beyond_the_Sky_Choir_Anomaly_Archives_Part_1 = RogueEventTitle(
en='Beyond the Sky Choir: Anomaly Archives (Part 1)',
jp='「天外聖歌隊-異象紀」・その1',
es='Coro del Firmamento: crónicas sobre anomalías(I)',
option_ids=[221, 222],
option_ids=[222, 223],
)
Beyond_the_Sky_Choir_Anomaly_Archives_Part_2 = RogueEventTitle(
id=72,
@ -721,7 +721,7 @@ Beyond_the_Sky_Choir_Anomaly_Archives_Part_2 = RogueEventTitle(
en='Beyond the Sky Choir: Anomaly Archives (Part 2)',
jp='「天外聖歌隊-異象紀」・その2',
es='Coro del Firmamento: crónicas sobre anomalías(II)',
option_ids=[223, 224],
option_ids=[224, 225],
)
Beyond_the_Sky_Choir_Anomaly_Archives_Part_3 = RogueEventTitle(
id=73,
@ -731,7 +731,7 @@ Beyond_the_Sky_Choir_Anomaly_Archives_Part_3 = RogueEventTitle(
en='Beyond the Sky Choir: Anomaly Archives (Part 3)',
jp='「天外聖歌隊-異象紀」・その3',
es='Coro del Firmamento: crónicas sobre anomalías(III)',
option_ids=[225, 226],
option_ids=[226, 227],
)
The_Architects_Annals_of_Fortification_Part_1 = RogueEventTitle(
id=74,
@ -741,7 +741,7 @@ The_Architects_Annals_of_Fortification_Part_1 = RogueEventTitle(
en='The Architects: Annals of Fortification (Part 1)',
jp='「建創者-修築紀」・その1',
es='Los Arquitectos: anales de la fortificación(I)',
option_ids=[227, 228],
option_ids=[228, 229],
)
The_Architects_Annals_of_Fortification_Part_2 = RogueEventTitle(
id=75,
@ -751,7 +751,7 @@ The_Architects_Annals_of_Fortification_Part_2 = RogueEventTitle(
en='The Architects: Annals of Fortification (Part 2)',
jp='「建創者-修築紀」・その2',
es='Los Arquitectos: anales de la fortificación(II)',
option_ids=[229, 230],
option_ids=[230, 231],
)
The_Architects_Annals_of_Fortification_Part_3 = RogueEventTitle(
id=76,
@ -761,405 +761,395 @@ The_Architects_Annals_of_Fortification_Part_3 = RogueEventTitle(
en='The Architects: Annals of Fortification (Part 3)',
jp='「建創者-修築紀」・その3',
es='Los Arquitectos: anales de la fortificación(III)',
option_ids=[231, 232],
)
Herta_Curio_Store = RogueEventTitle(
id=77,
name='Herta_Curio_Store',
cn='黑塔奇物商店',
cht='黑塔奇物商店',
en="Herta's Curio Store",
jp='ヘルタの奇物ショップ',
es='Tienda de objetos raros de Herta',
option_ids=[],
option_ids=[232, 233],
)
Screwllum_Blessing_Store = RogueEventTitle(
id=78,
id=77,
name='Screwllum_Blessing_Store',
cn='螺丝咕姆祝福商店',
cht='螺絲咕姆祝福商店',
en="Screwllum's Blessing Store",
jp='スクリューガムの祝福ショップ',
es='Tienda de bendiciones de Tornillum',
option_ids=[233],
option_ids=[234],
)
Knights_of_Beauty_to_the_Rescue = RogueEventTitle(
id=79,
id=78,
name='Knights_of_Beauty_to_the_Rescue',
cn='纯美骑士的帮助',
cht='純美騎士的幫助',
en='Knights of Beauty to the Rescue',
jp='純美の騎士の助け',
es='Caballeros de la Belleza al rescate',
option_ids=[234, 235, 236, 237, 238, 239, 240, 241],
option_ids=[235, 236, 237, 238, 239, 240, 241, 242],
)
Cosmic_Crescendo = RogueEventTitle(
id=80,
id=79,
name='Cosmic_Crescendo',
cn='天外大合唱',
cht='天外大合唱',
en='Cosmic Crescendo',
jp='天外大合唱',
es='Crescendo cósmico',
option_ids=[242, 243, 244],
option_ids=[243, 244, 245],
)
Genius_Society_55_Yu_Qingtu = RogueEventTitle(
id=81,
id=80,
name='Genius_Society_55_Yu_Qingtu',
cn='天才俱乐部#55余清涂',
cht='天才俱樂部#55余清涂',
en='Genius Society #55 Yu Qingtu',
jp='天才クラブ#55余清塗',
es='Yu Qingtu, miembro n.º 55 del Círculo de Genios',
option_ids=[245, 246, 247, 248, 249, 250, 251, 252, 253],
option_ids=[246, 247, 248, 249, 250, 251, 252, 253, 254],
)
Beast_Horde_Voracious_Catastrophe = RogueEventTitle(
id=82,
id=81,
name='Beast_Horde_Voracious_Catastrophe',
cn='兽群•贪饕灾厄',
cht='獸群•貪饕災厄',
en='Beast Horde: Voracious Catastrophe',
jp='獣の群れ・貪慾の災厄',
es='Horda de bestias: catástrofe voraz',
option_ids=[254, 255, 256],
option_ids=[255, 256, 257],
)
The_Curio_Fixer = RogueEventTitle(
id=83,
id=82,
name='The_Curio_Fixer',
cn='奇物修理专家',
cht='奇物修理專家',
en='The Curio Fixer',
jp='奇物修理エキスパート',
es='Reparador de objetos raros',
option_ids=[257, 258, 259, 260, 261],
option_ids=[258, 259, 260, 261, 262],
)
Showman_Sleight = RogueEventTitle(
id=84,
id=83,
name='Showman_Sleight',
cn='伶人戏法',
cht='伶人戲法',
en="Showman's Sleight",
jp='伶人の手品',
es='El truco del actor',
option_ids=[262, 263],
option_ids=[263, 264],
)
The_Double_Lottery_Experience = RogueEventTitle(
id=85,
id=84,
name='The_Double_Lottery_Experience',
cn='双乐透体验',
cht='雙樂透體驗',
en='The Double Lottery Experience',
jp='ダブルロッタリー体験',
es='La experiencia de la doble lotería',
option_ids=[264, 265, 266],
option_ids=[265, 266, 267],
)
Ruan_Mei_Part_2 = RogueEventTitle(
id=86,
id=85,
name='Ruan_Mei_Part_2',
cn='阮•梅(其二)',
cht='阮•梅(其二)',
en='Ruan Mei (Part 2)',
jp='ルアン・メェイ2',
es='Ruan Mei II',
option_ids=[267, 268, 269],
option_ids=[268, 269, 270],
)
The_Perfect_Grand_Challenge = RogueEventTitle(
id=87,
id=86,
name='The_Perfect_Grand_Challenge',
cn='*完美*大挑战!',
cht='*完美*大挑戰!',
en='The *Perfect* Grand Challenge!',
jp='※完璧※大挑戦!',
es='¡El gran desafío perfecto!',
option_ids=[270, 271, 272, 273],
option_ids=[271, 272, 273, 274],
)
The_IPC_Promotion_Saga_Part_1 = RogueEventTitle(
id=88,
id=87,
name='The_IPC_Promotion_Saga_Part_1',
cn='星际和平公司「升职记」(其一)',
cht='星際和平公司「升職記」(其一)',
en='The IPC Promotion Saga (Part 1)',
jp='スターピースカンパニー「昇進記」1',
es='La saga del ascenso de la Corporación I',
option_ids=[274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288],
option_ids=[275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289],
)
The_IPC_Promotion_Saga_Part_2 = RogueEventTitle(
id=89,
id=88,
name='The_IPC_Promotion_Saga_Part_2',
cn='星际和平公司「升职记」(其二)',
cht='星際和平公司「升職記」(其二)',
en='The IPC Promotion Saga (Part 2)',
jp='スターピースカンパニー「昇進記」2',
es='La saga del ascenso de la Corporación II',
option_ids=[289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302],
option_ids=[290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303],
)
The_IPC_Promotion_Saga_Part_3 = RogueEventTitle(
id=90,
id=89,
name='The_IPC_Promotion_Saga_Part_3',
cn='星际和平公司「升职记」(其三)',
cht='星際和平公司「升職記」(其三)',
en='The IPC Promotion Saga (Part 3)',
jp='スターピースカンパニー「昇進記」3',
es='La saga del ascenso de la Corporación III',
option_ids=[303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315],
option_ids=[304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316],
)
The_IPC_Promotion_Saga_Part_4 = RogueEventTitle(
id=91,
id=90,
name='The_IPC_Promotion_Saga_Part_4',
cn='星际和平公司「升职记」(其四)',
cht='星際和平公司「升職記」(其四)',
en='The IPC Promotion Saga (Part 4)',
jp='スターピースカンパニー「昇進記」4',
es='La saga del ascenso de la Corporación IV',
option_ids=[316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327],
option_ids=[317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328],
)
Ka_ching_IPC_Banking_Part_1 = RogueEventTitle(
id=92,
id=91,
name='Ka_ching_IPC_Banking_Part_1',
cn='咔嚓——星际和平银行!(其一)',
cht='喀嚓——星際和平銀行!(其一)',
en='Ka-ching! IPC Banking (Part 1)',
jp='カチャッ――スターピース銀行1',
es='El banco de la Corporación I',
option_ids=[328, 329, 330, 331, 332],
option_ids=[329, 330, 331, 332, 333],
)
Ka_ching_IPC_Banking_Part_2 = RogueEventTitle(
id=93,
id=92,
name='Ka_ching_IPC_Banking_Part_2',
cn='咔嚓——星际和平银行!(其二)',
cht='喀嚓——星際和平銀行!(其二)',
en='Ka-ching! IPC Banking (Part 2)',
jp='カチャッ――スターピース銀行2',
es='El banco de la Corporación II',
option_ids=[333, 334, 335, 336, 337],
option_ids=[334, 335, 336, 337, 338],
)
Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_1 = RogueEventTitle(
id=94,
id=93,
name='Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_1',
cn='孤独,太空美虫,模拟宇宙(其一)',
cht='孤獨,太空美蟲,模擬宇宙(其一)',
en='Loneliness, Costic Beauty Bugs, Simulated Universe (Part 1)',
jp='孤独、宇宙の美虫、模擬宇宙1',
es='Soledad, gusanos espaciales y el Universo Simulado I',
option_ids=[338, 339, 340, 341, 342, 343, 344, 345],
option_ids=[339, 340, 341, 342, 343, 344, 345, 346],
)
Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_2 = RogueEventTitle(
id=95,
id=94,
name='Loneliness_Costic_Beauty_Bugs_Simulated_Universe_Part_2',
cn='孤独,太空美虫,模拟宇宙(其二)',
cht='孤獨,太空美蟲,模擬宇宙(其二)',
en='Loneliness, Costic Beauty Bugs, Simulated Universe (Part 2)',
jp='孤独、宇宙の美虫、模擬宇宙2',
es='Soledad, gusanos espaciales y el Universo Simulado II',
option_ids=[346, 347, 348, 349, 350, 351, 352],
option_ids=[347, 348, 349, 350, 351, 352, 353],
)
Ace_Trash_Digger = RogueEventTitle(
id=96,
id=95,
name='Ace_Trash_Digger',
cn='掏垃圾桶大师',
cht='掏垃圾桶大師',
en='Ace Trash Digger',
jp='ゴミ箱あさりの達人',
es='Gran rebuscador de la basura',
option_ids=[353, 354, 355, 356],
option_ids=[354, 355, 356, 357],
)
Swarm_Slumbering_Overlord_First_Praetorian = RogueEventTitle(
id=97,
id=96,
name='Swarm_Slumbering_Overlord_First_Praetorian',
cn='虫潮•沉睡领主(一级卫戍)',
cht='蟲潮•沉睡領主(一級衛戍)',
en='Swarm: Slumbering Overlord (First Praetorian)',
jp='虫の潮・深眠の領主(一級守備)',
es='Enjambre: Cacique dormido (primer pretoriano)',
option_ids=[357, 358, 359, 360, 361, 362],
option_ids=[358, 359, 360, 361, 362, 363],
)
Swarm_Slumbering_Overlord_Second_Praetorian = RogueEventTitle(
id=98,
id=97,
name='Swarm_Slumbering_Overlord_Second_Praetorian',
cn='虫潮•沉睡领主(二级卫戍)',
cht='蟲潮•沉睡領主(二級衛戍)',
en='Swarm: Slumbering Overlord (Second Praetorian)',
jp='虫の潮・深眠の領主(二級守備)',
es='Enjambre: Cacique dormido (segundo pretoriano)',
option_ids=[363, 364, 365, 366, 367],
option_ids=[364, 365, 366, 367, 368],
)
Swarm_Slumbering_Overlord_Third_Praetorian = RogueEventTitle(
id=99,
id=98,
name='Swarm_Slumbering_Overlord_Third_Praetorian',
cn='虫潮•沉睡领主(三级卫戍)',
cht='蟲潮•沉睡領主(三級衛戍)',
en='Swarm: Slumbering Overlord (Third Praetorian)',
jp='虫の潮・深眠の領主(三級守備)',
es='Enjambre: Cacique dormido (tercer pretoriano)',
option_ids=[368, 369, 370, 371],
option_ids=[369, 370, 371, 372],
)
Propagation_Slumbering_Overlord_First_Praetorian = RogueEventTitle(
id=100,
id=99,
name='Propagation_Slumbering_Overlord_First_Praetorian',
cn='繁育•沉睡领主(一级卫戍)',
cht='繁育•沉睡領主(一級衛戍)',
en='Propagation: Slumbering Overlord (First Praetorian)',
jp='繁殖・深眠の領主(一級守備)',
es='Propagación: Cacique dormido (primer pretoriano)',
option_ids=[372, 373],
option_ids=[373, 374],
)
Propagation_Slumbering_Overlord_Second_Praetorian = RogueEventTitle(
id=101,
id=100,
name='Propagation_Slumbering_Overlord_Second_Praetorian',
cn='繁育•沉睡领主(二级卫戍)',
cht='繁育•沉睡領主(二級衛戍)',
en='Propagation: Slumbering Overlord (Second Praetorian)',
jp='繁殖・深眠の領主(二級守備)',
es='Propagación: Cacique dormido (segundo pretoriano)',
option_ids=[374, 375],
option_ids=[375, 376],
)
Propagation_Slumbering_Overlord_Third_Praetorian = RogueEventTitle(
id=102,
id=101,
name='Propagation_Slumbering_Overlord_Third_Praetorian',
cn='繁育•沉睡领主(三级卫戍)',
cht='繁育•沉睡領主(三級衛戍)',
en='Propagation: Slumbering Overlord (Third Praetorian)',
jp='繁殖・深眠の領主(三級守備)',
es='Propagación: Cacique dormido (tercer pretoriano)',
option_ids=[376, 377],
option_ids=[377, 378],
)
Swarm_Nest_Exploration_First_Praetorian = RogueEventTitle(
id=103,
id=102,
name='Swarm_Nest_Exploration_First_Praetorian',
cn='虫潮•虫巢探险(一级卫戍)',
cht='蟲潮•蟲巢探險(一級衛戍)',
en='Swarm: Nest Exploration (First Praetorian)',
jp='虫の潮・虫の巣探険(一級守備)',
es='Enjambre: Exploración del nido (primer pretoriano)',
option_ids=[378, 379, 380],
option_ids=[379, 380, 381],
)
Swarm_Nest_Exploration_Second_Praetorian = RogueEventTitle(
id=104,
id=103,
name='Swarm_Nest_Exploration_Second_Praetorian',
cn='虫潮•虫巢探险(二级卫戍)',
cht='蟲潮•蟲巢探險(二級衛戍)',
en='Swarm: Nest Exploration (Second Praetorian)',
jp='虫の潮・虫の巣探険(二級守備)',
es='Enjambre: Exploración del nido (segundo pretoriano)',
option_ids=[381, 382, 383],
option_ids=[382, 383, 384],
)
Swarm_Nest_Exploration_Third_Praetorian = RogueEventTitle(
id=105,
id=104,
name='Swarm_Nest_Exploration_Third_Praetorian',
cn='虫潮•虫巢探险(三级卫戍)',
cht='蟲潮•蟲巢探險(三級衛戍)',
en='Swarm: Nest Exploration (Third Praetorian)',
jp='虫の潮・虫の巣探険(三級守備)',
es='Enjambre: Exploración del nido (tercer pretoriano)',
option_ids=[384, 385, 386],
option_ids=[385, 386, 387],
)
Propagation_Nest_Exploration_First_Praetorian = RogueEventTitle(
id=106,
id=105,
name='Propagation_Nest_Exploration_First_Praetorian',
cn='繁育•虫巢探险(一级卫戍)',
cht='繁育•蟲巢探險(一級衛戍)',
en='Propagation: Nest Exploration (First Praetorian)',
jp='繁殖・虫の巣探険(一級守備)',
es='Propagación: Exploración del nido (primer pretoriano)',
option_ids=[387, 388],
option_ids=[388, 389],
)
Propagation_Nest_Exploration_Second_Praetorian = RogueEventTitle(
id=107,
id=106,
name='Propagation_Nest_Exploration_Second_Praetorian',
cn='繁育•虫巢探险(二级卫戍)',
cht='繁育•蟲巢探險(二級衛戍)',
en='Propagation: Nest Exploration (Second Praetorian)',
jp='繁殖・虫の巣探険(二級守備)',
es='Propagación: Exploración del nido (segundo pretoriano)',
option_ids=[389, 390],
option_ids=[390, 391],
)
Swarm_Mind_of_the_Domain_First_Praetorian = RogueEventTitle(
id=108,
id=107,
name='Swarm_Mind_of_the_Domain_First_Praetorian',
cn='虫潮•区域脑体(一级卫戍)',
cht='蟲潮•區域腦體(一級衛戍)',
en='Swarm: Mind of the Domain (First Praetorian)',
jp='虫の潮・区域脳(一級守備)',
es='Enjambre: Mente de zona (primer pretoriano)',
option_ids=[391, 392, 393, 394, 395],
option_ids=[392, 393, 394, 395, 396],
)
Swarm_Mind_of_the_Domain_Second_Praetorian = RogueEventTitle(
id=109,
id=108,
name='Swarm_Mind_of_the_Domain_Second_Praetorian',
cn='虫潮•区域脑体(二级卫戍)',
cht='蟲潮•區域腦體(二級衛戍)',
en='Swarm: Mind of the Domain (Second Praetorian)',
jp='虫の潮・区域脳(二級守備)',
es='Enjambre: Mente de zona (segundo pretoriano)',
option_ids=[396, 397, 398, 399],
option_ids=[397, 398, 399, 400],
)
Swarm_Mind_of_the_Domain_Third_Praetorian = RogueEventTitle(
id=110,
id=109,
name='Swarm_Mind_of_the_Domain_Third_Praetorian',
cn='虫潮•区域脑体(三级卫戍)',
cht='蟲潮•區域腦體(三級衛戍)',
en='Swarm: Mind of the Domain (Third Praetorian)',
jp='虫の潮・区域脳(三級守備)',
es='Enjambre: Mente de zona (tercer pretoriano)',
option_ids=[400, 401, 402],
option_ids=[401, 402, 403],
)
Insights_from_the_Universal_Dancer = RogueEventTitle(
id=111,
id=110,
name='Insights_from_the_Universal_Dancer',
cn='寰宇舞者的启示',
cht='寰宇舞者的啟示',
en='Insights from the Universal Dancer',
jp='世界の踊り手の啓示',
es='Reflexiones del bailarín universal',
option_ids=[403, 404],
option_ids=[404, 405],
)
Pixel_World_Hidden_Stage = RogueEventTitle(
id=112,
id=111,
name='Pixel_World_Hidden_Stage',
cn='像素世界•隐藏关',
cht='像素世界•隱藏關',
en='Pixel World: Hidden Stage',
jp='ピクセルワールド・隠しステージ',
es='Mundo de píxeles: Mecanismo invisible',
option_ids=[405, 406, 407],
option_ids=[406, 407, 408],
)
Mirror_of_Transcendence = RogueEventTitle(
id=113,
id=112,
name='Mirror_of_Transcendence',
cn='超验之镜',
cht='超驗之鏡',
en='Mirror of Transcendence',
jp='超越の鏡',
es='Espejo de la Trascendencia',
option_ids=[408, 409, 410, 411, 412, 413],
option_ids=[409, 410, 411, 412, 413, 414],
)
The_Cuckoo_Clock_Fanatic_Part_1 = RogueEventTitle(
id=114,
id=113,
name='The_Cuckoo_Clock_Fanatic_Part_1',
cn='咕咕钟狂热粉丝(其一)',
cht='咕咕鐘狂熱愛好者(其一)',
en='The Cuckoo Clock Fanatic (Part 1)',
jp='鳩時計の熱狂的ファン1',
es='El fanático del reloj de cuco I',
option_ids=[414, 415, 416],
option_ids=[415, 416, 417],
)
The_Cuckoo_Clock_Fanatic_Part_2 = RogueEventTitle(
id=115,
id=114,
name='The_Cuckoo_Clock_Fanatic_Part_2',
cn='咕咕钟狂热粉丝(其二)',
cht='咕咕鐘狂熱愛好者(其二)',
en='The Cuckoo Clock Fanatic (Part 2)',
jp='鳩時計の熱狂的ファン2',
es='El fanático del reloj de cuco II',
option_ids=[417, 418],
option_ids=[418, 419],
)
The_Cuckoo_Clock_Fanatic_Part_3 = RogueEventTitle(
id=116,
id=115,
name='The_Cuckoo_Clock_Fanatic_Part_3',
cn='咕咕钟狂热粉丝(其三)',
cht='咕咕鐘狂熱愛好者(其三)',
en='The Cuckoo Clock Fanatic (Part 3)',
jp='鳩時計の熱狂的ファン3',
es='El fanático del reloj de cuco III',
option_ids=[419],
option_ids=[420],
)

View File

@ -83,6 +83,7 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent):
out: is_in_main()
"""
logger.info('Clear occurrence')
self.title = None
while 1:
if skip_first_screenshot:
skip_first_screenshot = False