1
0
mirror of https://github.com/0O0o0oOoO00/Alas.git synced 2026-05-14 16:29:25 +08:00
Files
Alas/module/support_build/reward.py

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)