1
0
mirror of https://github.com/0O0o0oOoO00/Alas.git synced 2026-05-14 07:39:25 +08:00

Add: Cross zone scanning device reset(Part of story_skip handler)

This commit is contained in:
Zuosizhu
2026-02-18 21:20:40 +08:00
parent 5cdf050432
commit b2ec71a880
4 changed files with 315 additions and 2 deletions

View File

@@ -571,4 +571,74 @@ class InfoHandler(ModuleBase):
if manjuu_timer.reached():
break
return handled
return handled
def story_skip_with_option(self, drop=None, option=0):
"""
2023.09.14 Story options changed with big white options in the middle,
Check STORY_SKIP_3 but click the original STORY_SKIP.
Returns:
[skipped, story_choice_clicked]
"""
if self.story_popup_timeout.started() and not self.story_popup_timeout.reached():
if self.handle_popup_confirm('STORY_SKIP'):
self.story_popup_timeout = Timer(10)
self.interval_reset(STORY_SKIP_3)
self.interval_reset(STORY_LETTERS_ONLY)
return [True , False]
if self._is_story_black():
if self.appear_then_click(STORY_LETTERS_ONLY, offset=(20, 20), interval=2):
self.story_popup_timeout.reset()
return [True , False]
if self._story_option_timer.reached() and self.appear(STORY_SKIP_3, offset=(20, 20), interval=0):
options = self._story_option_buttons_2()
options_count = len(options)
logger.attr('Story_options', options_count)
if not options_count:
self._story_option_record = 0
self._story_option_confirm.reset()
elif options_count == self._story_option_record:
if self._story_option_confirm.reached():
try:
select = options[option]
_op = option
except IndexError:
select = options[0]
_op = option
self.device.click(select)
self._story_option_timer.reset()
self.story_popup_timeout.reset()
self.interval_reset(STORY_SKIP_3)
self.interval_reset(STORY_LETTERS_ONLY)
self._story_option_record = 0
self._story_option_confirm.reset()
return [True , _op]
else:
self._story_option_record = options_count
self._story_option_confirm.reset()
if self.appear(STORY_SKIP_3, offset=(20, 20), interval=2):
# Confirm it's story
# When story play speed is Very Fast, Alas clicked story skip but story disappeared
# This click will interrupt auto search
self.interval_reset([STORY_SKIP_3])
if self._story_confirm.reached():
if drop:
drop.handle_add(self, before=2)
if self.config.STORY_ALLOW_SKIP:
logger.info(f'{STORY_SKIP_3} -> {STORY_SKIP}')
self.device.click(STORY_SKIP)
else:
logger.info(f'{STORY_SKIP_3} -> {OS_CLICK_SAFE_AREA}')
self.device.click(OS_CLICK_SAFE_AREA)
self._story_confirm.reset()
self.story_popup_timeout.reset()
return [True , False]
else:
self.interval_clear(STORY_SKIP_3)
else:
self._story_confirm.reset()
if self.appear_then_click(STORY_CLOSE, offset=(10, 10), interval=2):
self.story_popup_timeout.reset()
return [True , False]
return [False , False]

View File

@@ -941,3 +941,166 @@ class OSFleet(OSCamera, Combat, Fleet, OSAsh):
return False
self.device.click(nearest)
self._nearest_object_click_timer.reset()
def _story_for_cross_zone_reset(self, drop=None):
"""
Wait until homo_loca stabled.
DETECTION_BACKEND must be 'homography'.
Args:
drop (DropImage):
Returns
str: Things that fleet met on its way,
'event', 'search', 'akashi', 'combat',
or their combinations like 'event_akashi', 'event_combat',
or an empty string '' if nothing met.
Raises:
MapWalkError: If unable to goto such grid.
"""
logger.hr('Wait until walk stable')
record = None
enemy_searching_appear = False
self.device.screenshot_interval_set(0.35)
confirm_timer = Timer(1.5, count=4)
result = set()
# Record story history to clear click record
clicked_story = False
stuck_timer = Timer(20, count=5).start()
clicked_middle = 0
for _ in self.loop(skip_first=False):
# Map event
# If clicked Middle for twice, means it's a scanning device, which need to quit to save it.
if clicked_middle >1:
option = -1
result.add ("siren_scanning_device")
else:
option = -2
event = self.story_skip_with_option(drop=drop, option=option)
if event[1] == -2:
clicked_middle += 1
event = event[0]
if event:
confirm_timer.reset()
stuck_timer.reset()
result.add('event')
if event == 'story_skip':
clicked_story = True
elif event == 'map_get_items':
# story_skip -> map_get_items means abyssal progress reward is received
if clicked_story:
logger.info('Got items from story')
self.device.click_record_clear()
clicked_story = False
else:
# Handled other events, clear history
clicked_story = False
continue
if self.handle_retirement():
confirm_timer.reset()
stuck_timer.reset()
continue
if self.handle_popup_confirm('WALK_UNTIL_STABLE'):
# Confirm to submit items, in siren scanning devices
confirm_timer.reset()
stuck_timer.reset()
continue
# Accident click
if self.is_in_globe():
self.os_globe_goto_map()
confirm_timer.reset()
stuck_timer.reset()
continue
if self.is_in_storage():
self.storage_quit()
confirm_timer.reset()
stuck_timer.reset()
continue
if self.is_in_os_mission():
self.os_mission_quit()
confirm_timer.reset()
stuck_timer.reset()
continue
if self.handle_os_game_tips():
confirm_timer.reset()
stuck_timer.reset()
continue
if self.is_in_map_order():
self.order_quit()
confirm_timer.reset()
stuck_timer.reset()
continue
# Combat
if self.combat_appear():
# Use ui_back() for testing, because there are too few abyssal loggers every month.
# self.ui_back(check_button=self.is_in_map)
self.combat(expected_end=self.is_in_map, fleet_index=self.fleet_show_index, save_get_items=drop)
confirm_timer.reset()
stuck_timer.reset()
result.add('event')
continue
# Akashi shop
if self.appear(PORT_SUPPLY_CHECK, offset=(20, 20)):
self.interval_clear(PORT_SUPPLY_CHECK)
self.handle_akashi_supply_buy(CLICK_SAFE_AREA)
confirm_timer.reset()
stuck_timer.reset()
result.add('akashi')
continue
# A game bug that AUTO_SEARCH_REWARD from the last cleared zone popups
if self.appear_then_click(AUTO_SEARCH_REWARD, offset=(50, 50), interval=3):
confirm_timer.reset()
stuck_timer.reset()
continue
# Enemy searching
if not enemy_searching_appear and self.enemy_searching_appear():
enemy_searching_appear = True
confirm_timer.reset()
stuck_timer.reset()
continue
else:
if enemy_searching_appear:
self.handle_enemy_flashing()
self.device.sleep(0.3)
logger.info('Enemy searching appeared.')
enemy_searching_appear = False
confirm_timer.reset()
stuck_timer.reset()
result.add('search')
if self.is_in_map():
self.enemy_searching_color_initial()
# Arrive
# Check colors, because screen goes black when something is unlocking.
# A direct use of IN_MAP, basically `self.is_in_map() and IN_MAP.match_template_color()`
if self.match_template_color(IN_MAP, offset=(200, 5)):
self.update_os()
current = self.view.backend.homo_loca
logger.attr('homo_loca', current)
# Max known distance is 4.48px, homo_loca between ( 56, 60) and ( 52, 58)
if record is None or (current is not None and np.linalg.norm(np.subtract(current, record)) < 5.5):
if confirm_timer.reached():
break
else:
if stuck_timer.reached():
logger.warning(f"homo_loca stuck at current view, try reset.")
if self.fleet_reset_view():
stuck_timer.reset()
confirm_timer.reset()
record = current
else:
confirm_timer.reset()
stuck_timer.reset()
result = '_'.join(result)
logger.info(f'Walk stabled, result: {result}')
self.device.screenshot_interval_set()
return result

View File

@@ -4,6 +4,7 @@ from sys import maxsize
import inflection
import scheduler_watcher
from encodings.punycode import selective_find
from module.base.timer import Timer
from module.combat_ui.assets import PAUSE
from module.config.utils import get_os_reset_remain
@@ -767,7 +768,13 @@ class OSMap(OSFleet, Map, GlobeCamera, StrategicSearchHandler):
self._solved_map_event = set()
self._solved_fleet_mechanism = False
if self.config.full_config.OpsiCrossZoneScanningDeviceReset_Scheduler_Enable:
self.map_rescan()
if self.zone.hazard_level>=5:
self.clear_question_for_cross_zone_reset(drop=drop)
else:
self.clear_question(drop=drop)
self.map_rescan(rescan_mode=rescan, drop=drop)
self.config.task_call("OpsiCrossZoneScanningDeviceReset")
self.config.task_stop()
else:
if question:
self.clear_question(drop=drop)
@@ -956,3 +963,50 @@ class OSMap(OSFleet, Map, GlobeCamera, StrategicSearchHandler):
logger.warning('Too many trial on map rescan, stop')
self.fleet_set(self.config.OpsiFleet_Fleet)
return False
def clear_question_for_cross_zone_reset(self, drop):
"""
Clear nearly (and 3 grids from above) question marks on radar.
Try 3 times at max to avoid loop tries on 2 adjacent fleet mechanism.
Args:
drop:
Returns:
bool: If cleared
"""
logger.hr('Clear question', level=2)
for _ in range(3):
grid = self.radar.predict_question(self.device.image, in_port=self.zone.is_port)
if grid is None:
logger.info('No question mark above current fleet on this radar')
return False
logger.info(f'Found question mark on {grid}')
self.handle_info_bar()
self.update_os()
self.view.predict()
self.view.show()
grid = self.convert_radar_to_local(grid)
self.device.click(grid)
with self.config.temporary(STORY_ALLOW_SKIP=False):
result = self._story_for_cross_zone_reset(drop=drop)
if 'akashi' in result:
self._solved_map_event.add('is_akashi')
return True
elif 'event' in result and grid.is_logging_tower:
self._solved_map_event.add('is_logging_tower')
return True
elif 'event' in result and (grid.is_scanning_device or "siren_scanning_device" in result):
self._solved_map_event.add('is_scanning_device')
self.os_auto_search_run_exit_combat(drop=drop)
return "is_scanning_device"
else:
logger.warning(f'Arrive question with unexpected result: {result}, expected: {grid.str}')
continue
logger.warning('Failed to goto question mark after 5 trail, '
'this might be 2 adjacent fleet mechanism, stopped')
return False

View File

@@ -273,3 +273,29 @@ class MapEventHandler(EnemySearchingHandler):
changed = fleet_lock.set(state, main=self)
return changed
def handle_map_event_for_cross_zone_reset(self, drop=None, option=0):
"""
Args:
drop (DropImage):
option (int):
Returns:
str: Event that handled
"""
if self.handle_map_get_items(drop=drop):
return 'map_get_items'
if self.handle_os_game_tips():
return 'os_game_tips'
if self.handle_map_archives(drop=drop):
return 'map_archives'
if self.handle_guild_popup_cancel():
return 'guild_popup_cancel'
if self.handle_ash_popup():
return 'ash_popup'
if self.handle_urgent_commission(drop=drop):
return 'urgent_commission'
if self.story_skip_with_option(option=option):
return 'story_skip'
return ''