mirror of
https://github.com/0O0o0oOoO00/Alas.git
synced 2026-05-14 16:29:25 +08:00
345 lines
14 KiB
Python
345 lines
14 KiB
Python
from datetime import datetime, timedelta
|
|
from module.base.timer import Timer
|
|
from module.combat.assets import GET_SHIP
|
|
from module.handler.assets import POPUP_CONFIRM
|
|
from module.logger import logger
|
|
from module.notify import handle_notify
|
|
from module.ocr.ocr import Digit
|
|
from module.retire.enhancement import Enhancement, OCR_DOCK_AMOUNT
|
|
from module.retire.retirement import Retirement
|
|
|
|
from module.support_build.assets import *
|
|
from module.support_build.ui import SupportBuildUI
|
|
from module.ui.page import page_dock
|
|
|
|
# Import Enhancement separately for OCR_DOCK_AMOUNT but don't inherit from it
|
|
# because Retirement already inherits from Enhancement
|
|
|
|
OCR_SUPPORT_BUILD_MEDAL_COUNT = Digit(SUPPORT_BUILD_MEDAL_COUNT, letter=(220, 220, 220), threshold=150)
|
|
OCR_SUPPORT_BUILD_SUBMIT_COUNT = Digit(SUPPORT_BUILD_SUBMIT_NUMBER, letter=(220, 220, 220), threshold=150)
|
|
|
|
|
|
class RewardSupportBuild(Retirement, SupportBuildUI):
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.fail_count = 0
|
|
self.medal_count = 0
|
|
self.build_count = 0
|
|
|
|
def support_build_prep(self, target, skip_first_screenshot=False):
|
|
"""
|
|
Initiate preparation to submit support build orders.
|
|
|
|
Args:
|
|
target (int): Number of build orders to submit
|
|
skip_first_screenshot (bool):
|
|
|
|
Returns:
|
|
bool: True if prep complete otherwise False.
|
|
|
|
Pages:
|
|
in: page_support_build
|
|
out: submit pop up
|
|
"""
|
|
# Nothing to prep if 'target' = 0
|
|
if not target:
|
|
return False
|
|
|
|
# Ensure correct page to be able to prep in
|
|
if not self.appear(SUPPORT_BUILD_SUBMIT_ORDERS, offset=(20, 20)):
|
|
return False
|
|
|
|
# Click submit orders to enter quantity selection page
|
|
confirm_timer = Timer(1, count=2).start()
|
|
while 1:
|
|
if skip_first_screenshot:
|
|
skip_first_screenshot = False
|
|
else:
|
|
self.device.screenshot()
|
|
|
|
if self.appear_then_click(SUPPORT_BUILD_SUBMIT_ORDERS, interval=3):
|
|
confirm_timer.reset()
|
|
continue
|
|
|
|
# Continue support build even if dock is full
|
|
if self.handle_popup_confirm('SUPPORT_BUILD_PREP'):
|
|
confirm_timer.reset()
|
|
continue
|
|
|
|
# End - check for MAX button to confirm we're in quantity selection page
|
|
if self.appear(SUPPORT_BUILD_MAX, offset=(20, 20)):
|
|
if confirm_timer.reached():
|
|
break
|
|
|
|
# Use 'appear' to update actual position of assets
|
|
# for ui_ensure_index
|
|
area = OCR_SUPPORT_BUILD_SUBMIT_COUNT.buttons[0]
|
|
OCR_SUPPORT_BUILD_SUBMIT_COUNT.buttons = [
|
|
(SUPPORT_BUILD_MINUS.button[2] + 3, area[1], SUPPORT_BUILD_PLUS.button[0] - 3, area[3])]
|
|
|
|
# If target is 10 (max), click MAX button instead of clicking PLUS 9 times
|
|
if target == 10:
|
|
self.device.click(SUPPORT_BUILD_MAX)
|
|
self.device.sleep((0.3, 0.5))
|
|
self.device.screenshot()
|
|
else:
|
|
self.ui_ensure_index(target, letter=OCR_SUPPORT_BUILD_SUBMIT_COUNT, prev_button=SUPPORT_BUILD_MINUS,
|
|
next_button=SUPPORT_BUILD_PLUS, skip_first_screenshot=True)
|
|
|
|
# Verify the current count matches target
|
|
current_count = OCR_SUPPORT_BUILD_SUBMIT_COUNT.ocr(self.device.image)
|
|
logger.info(f'Current build count: {current_count}, Target: {target}')
|
|
if current_count != target:
|
|
logger.warning(f'Build count mismatch: {current_count} != {target}, retrying')
|
|
return False
|
|
|
|
# Click confirm at (789, 480)
|
|
self.device.click(Button(area=(), color=(), button=(789, 480, 789, 480), name='SUPPORT_BUILD_CONFIRM'))
|
|
self.device.sleep((0.3, 0.5))
|
|
|
|
return True
|
|
|
|
def support_build_skip_loop(self):
|
|
"""
|
|
Handle the ship acquisition and skip loop during support build.
|
|
|
|
This method continuously clicks to skip ship acquisition animations
|
|
until the build completion screen appears.
|
|
|
|
Returns:
|
|
str: 'success' or 'monthly_limit_reached'
|
|
"""
|
|
confirm_timer = Timer(5, count=10).start()
|
|
end_seen = False
|
|
skip_click_timer = Timer(1, count=2).start() # Timer to control skip click interval (1-2 seconds)
|
|
|
|
while 1:
|
|
self.device.screenshot()
|
|
|
|
# Handle monthly limit popup
|
|
if self.appear(SUPPORT_BUILD_MONTHLY_LIMIT, offset=(20, 20)):
|
|
logger.info('Monthly limit popup detected')
|
|
# Click confirm to close popup
|
|
if self.appear(POPUP_CONFIRM, offset=(20, 80), interval=3):
|
|
self.device.click(POPUP_CONFIRM)
|
|
continue
|
|
return 'monthly_limit_reached'
|
|
|
|
# Handle popup confirm (lock ship confirmation)
|
|
if self.appear(POPUP_CONFIRM, offset=(20, 80), interval=3):
|
|
self.device.click(POPUP_CONFIRM)
|
|
continue
|
|
|
|
# Handle retirement if dock is full
|
|
if self.handle_retirement():
|
|
confirm_timer.reset()
|
|
continue
|
|
|
|
# Click at (1150, 300) to skip ship acquisition animations
|
|
# Only click when timer is reached (1-2 seconds interval)
|
|
if skip_click_timer.reached():
|
|
self.device.click(Button(area=(), color=(), button=(1150, 300, 1150, 300), name='SUPPORT_BUILD_SKIP'))
|
|
skip_click_timer.reset()
|
|
|
|
# Check for end screen
|
|
if self.appear(SUPPORT_BUILD_END, offset=(20, 20)):
|
|
end_seen = True
|
|
# Extra click at (150, 300) in case END was clicked through
|
|
self.device.click(
|
|
Button(area=(), color=(), button=(150, 300, 150, 300), name='SUPPORT_BUILD_END_EXTRA'))
|
|
self.device.sleep((0.3, 0.5))
|
|
confirm_timer.reset()
|
|
|
|
# End - back to support build page
|
|
if self.appear(SUPPORT_BUILD_SUBMIT_ORDERS, offset=(20, 20)):
|
|
if end_seen:
|
|
break
|
|
# If we see submit orders without seeing end, might have missed it
|
|
# Give it one more chance
|
|
if confirm_timer.reached():
|
|
break
|
|
|
|
return 'success'
|
|
|
|
def check_dock_full(self):
|
|
"""
|
|
Check if dock is full by checking dock capacity.
|
|
|
|
Returns:
|
|
bool: True if dock is full, False otherwise
|
|
"""
|
|
# Enter dock
|
|
self.ui_goto(page_dock)
|
|
|
|
# Check dock capacity 3 times
|
|
dock_full_count = 0
|
|
for _ in range(3):
|
|
self.device.screenshot()
|
|
current, _, total = OCR_DOCK_AMOUNT.ocr(self.device.image)
|
|
logger.info(f'Dock capacity: {current}/{total}')
|
|
if current == total:
|
|
dock_full_count += 1
|
|
else:
|
|
break
|
|
|
|
# Back to support build page
|
|
self.ui_goto_support_build()
|
|
|
|
# If dock is full for 3 times, send notification and return True
|
|
if dock_full_count == 3:
|
|
logger.warning('Dock is full, unable to continue support build')
|
|
handle_notify(
|
|
self.config.Error_OnePushConfig,
|
|
title=f"Alas <{self.config_name}>: SupportBuild",
|
|
content='Dock is full, unable to continue support build. Please handle dock manually.',
|
|
)
|
|
return True
|
|
|
|
return False
|
|
|
|
def support_build_run(self):
|
|
"""
|
|
Run support build operations.
|
|
|
|
Returns:
|
|
bool: True if run successful otherwise False
|
|
|
|
Pages:
|
|
in: any
|
|
out: page_support_build
|
|
"""
|
|
# Enter support build page and OCR medal count
|
|
self.ui_goto_support_build()
|
|
self.device.screenshot()
|
|
self.medal_count = OCR_SUPPORT_BUILD_MEDAL_COUNT.ocr(self.device.image)
|
|
|
|
# Check if medal count info is available
|
|
if not self.medal_count:
|
|
logger.info('Medal count not available')
|
|
return False
|
|
|
|
logger.info(f'Medal count: {self.medal_count}')
|
|
|
|
# Check daily execution limit
|
|
daily_limit = self.config.SupportBuild_DailyTimes
|
|
daily_used = 0 # Initialize daily_used as local variable, not saved to config
|
|
|
|
# Calculate build count (6 medals per build)
|
|
# Amount is the number of builds per execution
|
|
amount = self.config.SupportBuild_Amount
|
|
|
|
# Check if we have enough medals (need amount * 6 * 2 to ensure sufficient)
|
|
required_medals = amount * 6 * 2
|
|
if self.medal_count < required_medals:
|
|
logger.info(
|
|
f'Insufficient medals: {self.medal_count} < {required_medals} (required), delaying to next month')
|
|
# Set next run to next month 1st noon (12:00)
|
|
next_month = datetime.now().replace(day=1) + timedelta(days=32)
|
|
next_month = next_month.replace(day=1, hour=12, minute=0, second=0, microsecond=0)
|
|
self.config.task_delay(target=next_month)
|
|
return False
|
|
|
|
# Check if month has changed and reset monthly counter if needed
|
|
current_date = datetime.now()
|
|
if self.config.SupportBuild_LastRunDate:
|
|
last_date = self.config.SupportBuild_LastRunDate
|
|
if current_date.month != last_date.month or current_date.year != last_date.year:
|
|
logger.info(f'Month changed from {last_date.strftime("%Y-%m")} to {current_date.strftime("%Y-%m")}, resetting monthly counter')
|
|
self.config.SupportBuild_MonthlyUsed = 0
|
|
self.config.SupportBuild_LastRunDate = current_date
|
|
|
|
# Calculate how many builds we can do this run
|
|
monthly_used = self.config.SupportBuild_MonthlyUsed
|
|
monthly_total = self.config.SupportBuild_MonthlyTotal
|
|
remaining_monthly = monthly_total - monthly_used
|
|
self.build_count = min(amount, remaining_monthly)
|
|
|
|
if self.build_count == 0:
|
|
logger.info('No builds available for this run')
|
|
return False
|
|
|
|
# Check if dock is full
|
|
if self.check_dock_full():
|
|
return False
|
|
|
|
# Submit build orders in a loop until daily limit is reached
|
|
success = False
|
|
|
|
# Enter support build page to click submit orders button before loop
|
|
# This ensures we're in the correct page to start building
|
|
self.ui_goto_support_build()
|
|
self.device.screenshot()
|
|
|
|
while daily_used < daily_limit:
|
|
# Recalculate remaining monthly builds
|
|
remaining_monthly = monthly_total - self.config.SupportBuild_MonthlyUsed
|
|
if remaining_monthly <= 0:
|
|
logger.info('Monthly limit reached, stopping')
|
|
break
|
|
|
|
# Calculate build count for this execution
|
|
self.build_count = min(amount, remaining_monthly)
|
|
|
|
# Check if we have enough medals (need amount * 6 * 2 to ensure sufficient)
|
|
required_medals = self.build_count * 6 * 2
|
|
if self.medal_count < required_medals:
|
|
logger.info(
|
|
f'Insufficient medals: {self.medal_count} < {required_medals} (required), stopping')
|
|
break
|
|
|
|
# Submit build with retry
|
|
for retry in range(3): # Retry up to 3 times
|
|
if self.support_build_prep(self.build_count):
|
|
# Record execution count immediately after confirm button click
|
|
# This ensures count is recorded even if skip loop encounters button count errors
|
|
self.config.SupportBuild_MonthlyUsed += self.build_count
|
|
logger.info(f'Monthly builds: {self.config.SupportBuild_MonthlyUsed}/{monthly_total}')
|
|
|
|
daily_used += 1
|
|
logger.info(f'Daily executions: {daily_used}/{daily_limit}')
|
|
|
|
result = self.support_build_skip_loop()
|
|
if result == 'monthly_limit_reached':
|
|
logger.info('Monthly support build limit reached, stopping')
|
|
# Reset monthly used counter
|
|
self.config.SupportBuild_MonthlyUsed = 0
|
|
# Set next run to next month 1st noon (12:00)
|
|
next_month = datetime.now().replace(day=1) + timedelta(days=32)
|
|
next_month = next_month.replace(day=1, hour=12, minute=0, second=0, microsecond=0)
|
|
self.config.task_delay(target=next_month)
|
|
return True
|
|
|
|
success = True
|
|
self.fail_count = 0 # Reset fail count on success
|
|
break
|
|
else:
|
|
logger.warning(f'Support build prep failed, retry {retry + 1}/3')
|
|
if retry == 2: # Last retry
|
|
self.fail_count += 1
|
|
if self.fail_count >= 3:
|
|
logger.warning('Failed to submit support build 3 times, stopping')
|
|
# Set next run to next month 1st noon (12:00)
|
|
next_month = datetime.now().replace(day=1) + timedelta(days=32)
|
|
next_month = next_month.replace(day=1, hour=12, minute=0, second=0, microsecond=0)
|
|
self.config.task_delay(target=next_month)
|
|
return success
|
|
|
|
# Re-enter support build page for next iteration
|
|
self.ui_goto_support_build()
|
|
self.device.screenshot()
|
|
self.medal_count = OCR_SUPPORT_BUILD_MEDAL_COUNT.ocr(self.device.image)
|
|
logger.info(f'Medal count: {self.medal_count}')
|
|
|
|
return success
|
|
|
|
def run(self):
|
|
"""
|
|
Handle support build operations if configured to do so.
|
|
|
|
Pages:
|
|
in: Any page
|
|
out: page_support_build
|
|
"""
|
|
self.support_build_run()
|
|
self.config.task_delay(server_update=True)
|