1
0
mirror of https://gitee.com/sui-feng-cb/AzurLaneAutoScript1 synced 2026-04-18 17:17:18 +08:00

Add: 15图开荒/周回 (#3563)

* Add: W15 maps extracted

* Add: template for Special Carrier in W15

* Add: method mob_move

* Fix: MapDetectionError in strategy mob move

* Fix: adjacent grid judge condition

* Fix: should focus on location before moving

* Fix: should update view before further operation

* Fix: wait for STRATEGY_OPENED after executing mob move

* Fix: offset for assets in _mob_move()

* Opt: judge if movable before moving camera

* Add: W15 mechanism

* Opt: Rename Special Carrier asset name

* Fix: offset for MOB_MOVE_1/MOB_MOVE_2

* Fix: separate MOB_MOVE_1 and MOB_MOVE_2

* Fix: should use appear_then_click in strategy_mob_move_enter

* Fix: function import in campaign_15_base.py

* Fix: missing assets import

* Fix: missing offset in strategy_mob_move_cancel()

* Fix: should move only once in a campaign

* Temp: modify special carrier filter string to 3E

* Fix: missing self. before 'moved' variable

* Revert "Fix: missing self. before 'moved' variable"

This reverts commit 00f70e0ab55e422898cb90c5d5e54d4e7c989511.

* Revert "Fix: should move only once in a campaign"

This reverts commit b588f5bb07dfc4511f39fa0797fbe160f356d604.

* Fix: force goto special carrier

* Fix: missing return True in battle function

* Fix: enlarge offset of MOB_MOVE_ICON

* Fix: typo in campaing_15_3

* Fix: update view after moving mob

* Fix: should use full_scan_movable since mob moved

* Fix: missing map_data_init() in campaign_15_4.py

* Fix: battle 4 should be done by mob fleet

* Revert "Fix: battle 4 should be done by mob fleet"

This reverts commit 0e2af1ec817b7bc89fe123f03a33ea9ad955973f.

* Fix: should switch to fleet_1 after battle_3

* Add: battle function when using clear mode

* Fix: missing import

* Fix: colliding Config class

* Fix: Config.when should contain all cases

* Opt: pick ammo after third battle in clear mode of 15-4

* Del: old assets CarrierSpecial

* Fix: remake of CarrierSpecial template

* Add: UI mask for W15

* Fix: missing ASSETS import

* Fix: change full_scan_movable() to predict()

* Fix: predict should be done after each move

* Opt: camera_data in W15

* Del: remove predict

* Add: map info process after mob move

* Add: support for multi bosses in _expected_end() for W15

* Opt: show map after moving

* Del: remove redundant import in fleet.py

* Opt: using clear_chosen_enemy() instead of goto() directly

* Fix: should first take screenshot before strategy enter/confirm/cancel

* Add: asset TEMPLATE_SIREN_BOSS

* Opt: Handle first stages of BOSS as Siren in 15-3/15-4

* Fix: missing override map_data

* Add: ignore is_boss prediction for siren boss in 15-3/15-4

* Fix: should not use decorator Config with battle_x functions

* Opt: camera data in 15-4

* Opt: directly overwrite map info into original map_data

* Fix: missing indent block in campaign_15_4.py

* Fix: expect 15-3/15-4 first bosses as siren

* Revert "Add: ignore is_boss prediction for siren boss in 15-3/15-4"

This reverts commit 1104631f92e5df0672dce8c7acaa1eb122731746.

* Revert "Add: asset TEMPLATE_SIREN_BOSS"

This reverts commit a29d6b6b9bfb9d79963adb404ce2091cbfafb810.

* Revert "Add: support for multi bosses in _expected_end() for W15"

This reverts commit 8d357abe5bab79a643e23e8513cefa87d31cb3e8.

* Del: redundent map config

* Fix: recover boss grids

* Del: redundant clear_siren()

* Del: redundant clear_siren() in battle_6

* Add: template for mob move icon

* Opt: enlarge reinforcement fleet mask area for W15

* Opt: method _mob_move

* Upd: TEMPLATE_MOB_MOVE_ICON

* Fix: should have cool time between clicks of grid

* Revert "Upd: TEMPLATE_MOB_MOVE_ICON"

This reverts commit b3f2dcbc88dbe166470905f33d041b91c2192f57.

* Upd: TEMPLATE_MOB_MOVE_ICON

* Upd: TEMPLATE_MOB_MOVE_ICON

* Upd: predict_mob_move_icon

* Fix: 15-2 camera spawn point

* Fix: should update view using self.device.image

* Revert "Upd: TEMPLATE_MOB_MOVE_ICON"

This reverts commit 92a12596a8f271ec64e249ecb58779d9b64ecea6.

* Del: redundant assets MOB_MOVE_ICON.png

* Fix: using map_is_clear_mode to get real value of clear mode

* Opt: check mob_movable before moving

* Opt: Refactor _mob_move

* Fix: camera_sight in W15

* Opt: move sight to further point in _mob_move
This commit is contained in:
guoh064
2024-04-19 01:29:17 +08:00
committed by GitHub
parent e110ec40ed
commit 27693a6762
23 changed files with 692 additions and 14 deletions

View File

@@ -0,0 +1,92 @@
from module.logger import logger
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from .campaign_15_base import CampaignBase
from .campaign_15_base import Config as ConfigBase
MAP = CampaignMap('15-1')
MAP.shape = 'H7'
MAP.camera_data = ['C2', 'C5', 'E2', 'E5']
MAP.camera_data_spawn_point = ['D5']
MAP.camera_sight = (-2, -1, 3, 2)
MAP.map_data = """
Me Me ME ++ ME MB ++ ++
ME ME Me ME Me -- MB ++
++ Me ME -- Me -- -- MB
++ ME -- -- -- __ Me --
-- ME -- ME ME Me -- ME
ME -- -- ME ++ -- ME --
-- SP SP -- Me -- ME --
"""
MAP.weight_data = """
50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50
"""
MAP.spawn_data = [
{'battle': 0, 'enemy': 5},
{'battle': 1, 'enemy': 2},
{'battle': 2, 'enemy': 1},
{'battle': 3},
{'battle': 4},
{'battle': 5},
{'battle': 6, 'boss': 1},
]
A1, B1, C1, D1, E1, F1, G1, H1, \
A2, B2, C2, D2, E2, F2, G2, H2, \
A3, B3, C3, D3, E3, F3, G3, H3, \
A4, B4, C4, D4, E4, F4, G4, H4, \
A5, B5, C5, D5, E5, F5, G5, H5, \
A6, B6, C6, D6, E6, F6, G6, H6, \
A7, B7, C7, D7, E7, F7, G7, H7, \
= MAP.flatten()
class Config:
# ===== Start of generated config =====
# MAP_SIREN_TEMPLATE = ['0']
# MOVABLE_ENEMY_TURN = (2,)
# MAP_HAS_SIREN = True
# MAP_HAS_MOVABLE_ENEMY = True
MAP_HAS_MAP_STORY = False
MAP_HAS_FLEET_STEP = False
MAP_HAS_AMBUSH = True
# MAP_HAS_MYSTERY = True
# ===== End of generated config =====
MAP_WALK_USE_CURRENT_FLEET = True
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
if not self.map_is_clear_mode:
self.mob_move(B3, C3)
self.clear_chosen_enemy(B1)
return True
else:
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1):
return True
return self.battle_default()
def battle_1(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1):
return True
return self.battle_default()
def battle_5(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_6(self):
return self.fleet_boss.clear_boss()

View File

@@ -0,0 +1,94 @@
from module.logger import logger
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from .campaign_15_base import CampaignBase
from .campaign_15_base import Config as ConfigBase
MAP = CampaignMap('15-2')
MAP.shape = 'I8'
MAP.camera_data = ['C2', 'C6', 'F2', 'F6']
MAP.camera_data_spawn_point = ['E5']
MAP.camera_sight = (-2, -1, 3, 2)
MAP.map_data = """
ME -- ME ME Me -- ++ ++ ++
ME -- -- ++ ME ME ME SP SP
-- ME ME Me -- -- -- -- --
-- -- -- -- -- ME ME Me --
ME -- ++ ME Me -- ME ME --
Me -- ME __ ME ++ ++ ++ Me
++ MB -- ME ME ++ Me MB --
++ MB ME -- ME Me -- -- ME
"""
MAP.weight_data = """
50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50
"""
MAP.spawn_data = [
{'battle': 0, 'enemy': 6},
{'battle': 1, 'enemy': 2},
{'battle': 2, 'enemy': 1},
{'battle': 3},
{'battle': 4},
{'battle': 5},
{'battle': 6, 'boss': 1},
]
A1, B1, C1, D1, E1, F1, G1, H1, I1, \
A2, B2, C2, D2, E2, F2, G2, H2, I2, \
A3, B3, C3, D3, E3, F3, G3, H3, I3, \
A4, B4, C4, D4, E4, F4, G4, H4, I4, \
A5, B5, C5, D5, E5, F5, G5, H5, I5, \
A6, B6, C6, D6, E6, F6, G6, H6, I6, \
A7, B7, C7, D7, E7, F7, G7, H7, I7, \
A8, B8, C8, D8, E8, F8, G8, H8, I8, \
= MAP.flatten()
class Config(ConfigBase):
# ===== Start of generated config =====
# MAP_SIREN_TEMPLATE = ['0']
# MOVABLE_ENEMY_TURN = (2,)
# MAP_HAS_SIREN = True
# MAP_HAS_MOVABLE_ENEMY = True
MAP_HAS_MAP_STORY = False
MAP_HAS_FLEET_STEP = False
MAP_HAS_AMBUSH = True
# MAP_HAS_MYSTERY = True
# ===== End of generated config =====
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
if not self.map_is_clear_mode:
self.mob_move(I6, I7)
self.mob_move(I7, H7)
self.clear_chosen_enemy(G7)
return True
else:
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1):
return True
return self.battle_default()
def battle_1(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1):
return True
return self.battle_default()
def battle_5(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_6(self):
return self.fleet_boss.clear_boss()

View File

@@ -0,0 +1,103 @@
from module.logger import logger
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from .campaign_15_base import CampaignBase
from .campaign_15_base import Config as ConfigBase
MAP = CampaignMap('15-3')
MAP.shape = 'J8'
MAP.camera_data = ['C2', 'C6', 'G2', 'G6']
MAP.camera_data_spawn_point = ['G6']
MAP.camera_sight = (-2, -1, 3, 2)
MAP.map_data = """
Me -- ++ ME ME ME -- ME -- ME
-- ME ++ Me -- Me ME Me ME --
ME Me ME ME Me -- ++ MB -- ME
++ -- -- ME ME Me ++ ++ __ ME
Me ME -- ++ Me -- ME MB -- Me
ME ME -- -- ME ME ME -- -- ME
Me -- __ -- -- ME -- -- ++ ++
++ ++ ++ Me -- -- SP SP ++ ++
"""
MAP.weight_data = """
50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50
"""
MAP.spawn_data = [
{'battle': 0, 'enemy': 5},
{'battle': 1, 'enemy': 2},
{'battle': 2, 'enemy': 1},
{'battle': 3, 'enemy': 1, 'siren': 1},
{'battle': 4, 'enemy': 2},
{'battle': 5},
{'battle': 6, 'boss': 1},
]
A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, \
A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, \
A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, \
A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, \
A5, B5, C5, D5, E5, F5, G5, H5, I5, J5, \
A6, B6, C6, D6, E6, F6, G6, H6, I6, J6, \
A7, B7, C7, D7, E7, F7, G7, H7, I7, J7, \
A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, \
= MAP.flatten()
class Config(ConfigBase):
# ===== Start of generated config =====
# MAP_SIREN_TEMPLATE = ['BOSS']
# MOVABLE_ENEMY_TURN = (2,)
# MAP_HAS_SIREN = True
# MAP_HAS_MOVABLE_ENEMY = True
MAP_HAS_MAP_STORY = False
MAP_HAS_FLEET_STEP = False
MAP_HAS_AMBUSH = True
# MAP_HAS_MYSTERY = True
# ===== End of generated config =====
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
if not self.map_is_clear_mode:
self.mob_move(B3, B4)
self.clear_chosen_enemy(A1)
return True
else:
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1):
return True
return self.battle_default()
def battle_1(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1):
return True
return self.battle_default()
def battle_3(self):
self.clear_chosen_enemy(H5, expected='siren')
return True
def battle_4(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=1):
return True
return self.battle_default()
def battle_5(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_6(self):
return self.fleet_boss.clear_boss()

View File

@@ -0,0 +1,130 @@
from module.logger import logger
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from .campaign_15_base import CampaignBase
from .campaign_15_base import Config as ConfigBase
MAP = CampaignMap('15-4')
MAP.shape = 'K9'
MAP.camera_data = ['C2', 'C5', 'C7', 'F2', 'F5', 'F7', 'H2', 'H5', 'H7']
MAP.camera_data_spawn_point = ['H2']
MAP.camera_sight = (-2, -1, 3, 2)
MAP.map_data = """
Me -- ME ME Me -- ME ++ ++ ME ME
ME -- -- -- -- ME -- ++ ++ -- ME
++ -- -- MB -- -- ME SP SP ME Me
++ ME -- ++ ++ -- -- -- -- ME --
-- Me ME MA ++ ME -- MB -- -- ME
ME ME ME -- -- -- -- ++ ME -- Me
ME -- __ -- ME ME -- ME ME -- ++
-- -- ++ -- Me -- ME ME ME Me ME
MB Me -- ME ME Me ++ ++ ++ -- Me
"""
MAP.weight_data = """
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
50 50 50 50 50 50 50 50 50 50 50
"""
MAP.spawn_data = [
{'battle': 0, 'enemy': 8},
{'battle': 1, 'enemy': 1},
{'battle': 2, 'enemy': 1},
{'battle': 3, 'enemy': 1, 'siren': 1},
{'battle': 4, 'enemy': 2},
{'battle': 5},
{'battle': 6, 'siren': 1},
{'battle': 7, 'enemy': 1},
{'battle': 8, 'boss': 1},
]
A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, \
A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, K2, \
A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, K3, \
A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, K4, \
A5, B5, C5, D5, E5, F5, G5, H5, I5, J5, K5, \
A6, B6, C6, D6, E6, F6, G6, H6, I6, J6, K6, \
A7, B7, C7, D7, E7, F7, G7, H7, I7, J7, K7, \
A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, K8, \
A9, B9, C9, D9, E9, F9, G9, H9, I9, J9, K9, \
= MAP.flatten()
class Config(ConfigBase):
# ===== Start of generated config =====
# MAP_SIREN_TEMPLATE = ['BOSS']
# MOVABLE_ENEMY_TURN = (2,)
# MAP_HAS_SIREN = True
# MAP_HAS_MOVABLE_ENEMY = True
MAP_HAS_MAP_STORY = False
MAP_HAS_FLEET_STEP = False
MAP_HAS_AMBUSH = True
# MAP_HAS_MYSTERY = True
# ===== End of generated config =====
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
if not self.map_is_clear_mode:
self.clear_chosen_enemy(A1)
return True
else:
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_1(self):
if not self.map_is_clear_mode:
self.mob_move(J8, J7)
self.clear_chosen_enemy(K9)
return True
else:
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_2(self):
self.pick_up_ammo()
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_3(self):
if not self.map_is_clear_mode:
self.fleet_boss.clear_chosen_enemy(H5, expected='siren')
self.fleet_1.switch_to()
return True
else:
self.clear_chosen_enemy(H5, expected='siren')
return True
def battle_4(self):
self.pick_up_ammo()
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_6(self):
self.clear_chosen_enemy(D3, expected='siren')
return True
def battle_7(self):
if self.clear_filter_enemy(self.ENEMY_FILTER, preserve=0):
return True
return self.battle_default()
def battle_8(self):
return self.fleet_boss.clear_boss()

View File

@@ -0,0 +1,177 @@
from module.base.mask import Mask
from module.base.timer import Timer
from module.campaign.campaign_base import CampaignBase as CampaignBase_
from module.handler.assets import STRATEGY_OPENED
from module.map_detection.utils_assets import ASSETS
from module.logger import logger
from module.map.map_grids import SelectedGrids
from module.map.utils import location_ensure
MASK_MAP_UI_W15 = Mask(file='./assets/mask/MASK_MAP_UI_W15.png')
class Config:
# Disabled because having errors
MAP_SWIPE_PREDICT_WITH_SEA_GRIDS = False
# Ambushes can be avoid by having more DDs.
MAP_WALK_OPTIMIZE = False
MAP_ENEMY_TEMPLATE = ['Light', 'Main', 'Carrier', 'CarrierSpecial']
class CampaignBase(CampaignBase_):
ENEMY_FILTER = '1T > 1L > 1E > 1M > 2T > 2L > 2E > 2M > 3T > 3L > 3E > 3M'
def map_data_init(self, map_):
super().map_data_init(map_)
# Patch ui_mask, get rid of supporting fleet
_ = ASSETS.ui_mask
ASSETS.ui_mask = MASK_MAP_UI_W15.image
def mob_movable(self, location, target):
"""
Check if mob is movable from location to target.
This requires that:
1. both location and target are grids in the map (not exceeding the boundaries)
2. Manhattan distance between location and target is 1.
3. location is a mob fleet
4. target is a sea grid
Args:
location (tuple): Location of mob.
target (tuple): Destination.
Returns:
bool: if movable.
"""
location = location_ensure(location)
target = location_ensure(target)
movable = True
try:
logger.info(f'location: {self.map[location]}, target: {self.map[target]}')
except KeyError as e:
logger.exception(f'Given coordinates are outside the map.')
raise e
if abs(location[0] - target[0]) + abs(location[1] - target[1]) != 1:
logger.error(f'{self.map[target]} is not adjacent from {self.map[location]}.')
movable = False
if not self.map[location].is_enemy:
logger.error(f'{self.map[location]} is not a mob fleet.')
movable = False
if not self.map[target].is_sea:
logger.error(f'{self.map[target]} is not a sea grid.')
movable = False
if not movable:
logger.error(f'Cannot move from {self.map[location]} to {self.map[target]}.')
return movable
def _mob_move(self, location, target):
"""
Move mob from location to target, and confirm if successfully moved.
Args:
location (tuple, str, GridInfo): Location of mob.
target (tuple, str, GridInfo): Destination.
Returns:
bool: If mob moved.
Pages:
in: MOB_MOVE_CANCEL
out: STRATEGY_OPENED
"""
location = location_ensure(location)
target = location_ensure(target)
moved = False
while 1:
view_target = SelectedGrids([self.map[location], self.map[target]]) \
.sort_by_camera_distance(self.camera)[1]
self.in_sight(view_target)
grid = self.convert_global_to_local(location)
grid.__str__ = location
grid_2 = self.convert_global_to_local(target)
grid_2.__str__ = target
confirm_timer = Timer(1)
click_timeout = Timer(2, count=6).start()
while 1:
self.device.screenshot()
if self.appear(STRATEGY_OPENED, offset=(120, 120)):
moved = True
break
if self.handle_popup_confirm('MOB_MOVE'):
confirm_timer.reset()
continue
else:
self.view.update(image=self.device.image)
if not grid.predict_mob_move_icon():
if confirm_timer.reached():
self.device.click(grid)
confirm_timer.reset()
continue
if confirm_timer.reached():
self.device.click(grid_2)
confirm_timer.reset()
if click_timeout.reached():
logger.warning('Click timeout. Retrying.')
self.predict()
self.ensure_edge_insight(skip_first_update=False)
break
if moved:
break
return moved
def _mob_move_info_change(self, location, target):
location = location_ensure(location)
target = location_ensure(target)
self.map[target].enemy_scale = self.map[location].enemy_scale
self.map[location].enemy_scale = 0
self.map[target].enemy_genre = self.map[location].enemy_genre
self.map[location].enemy_genre = None
self.map[target].is_boss = self.map[location].is_boss
self.map[location].is_boss = False
self.map[target].is_enemy = True
self.map[location].is_enemy = False
def mob_move(self, location, target):
"""
Open strategy, move mob fleet from location to target, close strategy.
Args:
location (tuple, str, GridInfo): Location of mob.
target (tuple, str, GridInfo): Destination.
Returns:
bool: If mob moved
Pages:
in: IN_MAP
out: IN_MAP
"""
if not self.mob_movable(location, target):
return False
self.strategy_open()
remain = self.strategy_get_mob_move_remain()
if remain == 0:
logger.warning(f'No remain mob move trials, will abandon moving')
self.strategy_close()
return False
self.strategy_mob_move_enter()
result = self._mob_move(location, target)
self.strategy_close(skip_first_screenshot=False)
if result:
self._mob_move_info_change(location, target)
self.map.show()
return result