AzurLaneAutoScript/module/map/map_fleet_preparation.py
LmeSzinc 46d8d2fadb Refactor: Rename main configs
- Faster chapter selection and page_campaign
- Rename some old Chinglish variables in map info
2021-09-15 23:32:31 +08:00

207 lines
7.3 KiB
Python

import numpy as np
from PIL import ImageStat
from scipy import signal
from module.base.base import ModuleBase
from module.base.button import Button
from module.base.utils import area_offset, color_similarity_2d
from module.logger import logger
from module.map.assets import *
class FleetOperator:
FLEET_BAR_SHAPE_Y = 33
FLEET_BAR_MARGIN_Y = 9
FLEET_BAR_ACTIVE_STD = 45 # Active: 67, inactive: 12.
FLEET_IN_USE_STD = 27 # In use 52, not in use (3, 6).
FLEET_PREPARE_OPERATION_SLEEP = (0.25, 0.35)
def __init__(self, choose, bar, clear, in_use, main):
"""
Args:
choose(Button):
bar(Button):
clear(Button):
"""
self._choose = choose
self._bar = bar
self._clear = clear
self._in_use = in_use
self.main = main
def __str__(self):
return str(self._choose)[:-7]
def parse_fleet_bar(self, image):
"""
Args:
image(PIL.Image.Image): Image of fleet choosing bar.
Returns:
list: List of int. Chosen fleet range from 1 to 6.
"""
result = []
for index, y in enumerate(range(0, image.size[1], self.FLEET_BAR_SHAPE_Y + self.FLEET_BAR_MARGIN_Y)):
area = (0, y, image.size[0], y + self.FLEET_BAR_SHAPE_Y)
stat = ImageStat.Stat(image.crop(area))
if np.std(stat.mean, ddof=1) > self.FLEET_BAR_ACTIVE_STD:
result.append(index + 1)
logger.info('Current selected: %s' % str(result))
return result
def get_button(self, index):
"""
Args:
index(int): Fleet index, 1-6.
Returns:
Button: Button instance.
"""
area = area_offset(area=(
0,
(self.FLEET_BAR_SHAPE_Y + self.FLEET_BAR_MARGIN_Y) * (index - 1),
self._bar.area[2] - self._bar.area[0],
(self.FLEET_BAR_SHAPE_Y + self.FLEET_BAR_MARGIN_Y) * (index - 1) + self.FLEET_BAR_SHAPE_Y
), offset=(self._bar.area[0:2]))
return Button(area=(), color=(), button=area, name='%s_INDEX_%s' % (str(self._bar), str(index)))
def allow(self):
return self.main.appear(self._choose)
def clear(self):
while 1:
if not self.in_use():
break
self.main.device.click(self._clear)
# Call sleep() to avoid double-clicking.
self.main.device.sleep(self.FLEET_PREPARE_OPERATION_SLEEP)
self.main.device.screenshot()
def open(self):
while 1:
if self.bar_opened():
break
self.main.device.click(self._choose)
# The fleet bar won't open or close immediately after the click,
# so we need to sleep a while and wait for it.
# Call sleep() in close() and click() below for the same reason.
self.main.device.sleep(self.FLEET_PREPARE_OPERATION_SLEEP)
self.main.device.screenshot()
def close(self):
while 1:
if not self.bar_opened():
break
self.main.device.click(self._choose)
self.main.device.sleep(self.FLEET_PREPARE_OPERATION_SLEEP)
self.main.device.screenshot()
def click(self, index):
while 1:
if not self.bar_opened():
if self.in_use():
break
self.open()
self.main.device.click(self.get_button(index))
self.main.device.sleep(self.FLEET_PREPARE_OPERATION_SLEEP)
self.main.device.screenshot()
def selected(self):
data = self.parse_fleet_bar(self.main.device.image.crop(self._bar.area))
return data
def in_use(self):
# Handle the info bar of auto search info.
# if area_cross_area(self._in_use.area, INFO_BAR_1.area):
# self.main.handle_info_bar()
# Cropping FLEET_*_IN_USE to avoid detecting info_bar, also do the trick.
# It also avoids wasting time on handling the info_bar.
image = np.array(self.main.device.image.crop(self._in_use.area).convert('L'))
return np.std(image.flatten(), ddof=1) > self.FLEET_IN_USE_STD
def bar_opened(self):
# Check the brightness of the rightest column of the bar area.
luma = np.array(self.main.device.image.crop(self._bar.area).convert('L'))[:, -1]
return np.sum(luma > 127) / luma.size > 0.5
def ensure_to_be(self, index):
self.open()
if index in self.selected():
self.close()
else:
self.click(index)
class FleetPreparation(ModuleBase):
map_fleet_checked = False
map_is_hard_mode = False
def get_map_is_hard_mode(self):
"""
Detect how many light orange lines are there.
Having lines means current map has stat limits and user has satisfied at least one of them,
so this is a hard map.
Returns:
bool:
"""
area = (208, 130, 226, 551)
image = color_similarity_2d(self.image_area(area), color=(249, 199, 0))
height = np.max(image, axis=1)
parameters = {'height': 180, 'distance': 5}
peaks, _ = signal.find_peaks(height, **parameters)
lines = len(peaks)
logger.attr('Light_orange_line', lines)
return lines > 0
def fleet_preparation(self):
"""Change fleets.
Returns:
bool: True if changed.
"""
logger.info(f'Using fleet: {[self.config.Fleet_Fleet1, self.config.Fleet_Fleet2, self.config.Submarine_Fleet]}')
if self.map_fleet_checked:
return False
self.map_is_hard_mode = self.get_map_is_hard_mode()
if self.map_is_hard_mode:
logger.info('Hard Campaign. No fleet preparation')
return False
fleet_1 = FleetOperator(
choose=FLEET_1_CHOOSE, bar=FLEET_1_BAR, clear=FLEET_1_CLEAR, in_use=FLEET_1_IN_USE, main=self)
fleet_2 = FleetOperator(
choose=FLEET_2_CHOOSE, bar=FLEET_2_BAR, clear=FLEET_2_CLEAR, in_use=FLEET_2_IN_USE, main=self)
submarine = FleetOperator(
choose=SUBMARINE_CHOOSE, bar=SUBMARINE_BAR, clear=SUBMARINE_CLEAR, in_use=SUBMARINE_IN_USE, main=self)
# Submarine.
if submarine.allow():
if self.config.Submarine_Fleet:
submarine.ensure_to_be(self.config.Submarine_Fleet)
else:
submarine.clear()
# No need, this may clear FLEET_2 by mistake, clear FLEET_2 in map config.
# if not fleet_2.allow():
# self.config.FLEET_2 = 0
# Not using fleet 2.
if not self.config.Fleet_Fleet2:
if fleet_2.allow():
fleet_2.clear()
fleet_1.ensure_to_be(self.config.Fleet_Fleet1)
self.map_fleet_checked = True
return True
# Using both fleets.
# Force to set it again.
# Fleets may reversed, because AL no longer treat the fleet with smaller index as first fleet
fleet_2.clear()
fleet_1.ensure_to_be(self.config.Fleet_Fleet1)
fleet_2.ensure_to_be(self.config.Fleet_Fleet2)
self.map_fleet_checked = True
return True