diff --git a/.gitignore b/.gitignore index 1316089de..e24bdb9d3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ config/*.ini !alas_kr.pyw dev_tools/debug_tools .idea +/screenshots # Created by .ignore support plugin (hsz.mobi) diff --git a/README_en.md b/README_en.md index 4ba7eb897..8b08916e9 100644 --- a/README_en.md +++ b/README_en.md @@ -2,7 +2,7 @@ Alas, an Azur Lane automation tool with GUI (For CN server, can support other server). -![gui](doc/README.assets/gui.png) +![gui](doc/README.assets/gui_en.png) ## Features diff --git a/assets/cn/combat/BATTLE_STATUS_C.png b/assets/cn/combat/BATTLE_STATUS_C.png new file mode 100644 index 000000000..3b0066efc Binary files /dev/null and b/assets/cn/combat/BATTLE_STATUS_C.png differ diff --git a/assets/cn/combat/BATTLE_STATUS_D.png b/assets/cn/combat/BATTLE_STATUS_D.png new file mode 100644 index 000000000..3b0066efc Binary files /dev/null and b/assets/cn/combat/BATTLE_STATUS_D.png differ diff --git a/assets/en/handler/LOGIN_ANNOUNCE.png b/assets/en/handler/LOGIN_ANNOUNCE.png index 70685deef..275e7f471 100644 Binary files a/assets/en/handler/LOGIN_ANNOUNCE.png and b/assets/en/handler/LOGIN_ANNOUNCE.png differ diff --git a/assets/en/handler/LOGIN_RETURN_SIGN.png b/assets/en/handler/LOGIN_RETURN_SIGN.png index d05da4f7a..9df7085e9 100644 Binary files a/assets/en/handler/LOGIN_RETURN_SIGN.png and b/assets/en/handler/LOGIN_RETURN_SIGN.png differ diff --git a/assets/en/handler/MAP_WALK_OUT_OF_STEP.png b/assets/en/handler/MAP_WALK_OUT_OF_STEP.png index 8af403340..da19ed4c1 100644 Binary files a/assets/en/handler/MAP_WALK_OUT_OF_STEP.png and b/assets/en/handler/MAP_WALK_OUT_OF_STEP.png differ diff --git a/assets/en/reward/EXP_INFO_S_REWARD.png b/assets/en/reward/EXP_INFO_S_REWARD.png index 2b57b4ed4..8e01b526b 100644 Binary files a/assets/en/reward/EXP_INFO_S_REWARD.png and b/assets/en/reward/EXP_INFO_S_REWARD.png differ diff --git a/assets/en/reward/MISSION_MULTI.png b/assets/en/reward/MISSION_MULTI.png index bdfaadd3d..a1741f727 100644 Binary files a/assets/en/reward/MISSION_MULTI.png and b/assets/en/reward/MISSION_MULTI.png differ diff --git a/assets/en/reward/MISSION_SINGLE.png b/assets/en/reward/MISSION_SINGLE.png index 564ccb1bf..23599df74 100644 Binary files a/assets/en/reward/MISSION_SINGLE.png and b/assets/en/reward/MISSION_SINGLE.png differ diff --git a/assets/en/template/TEMPLATE_MAP_WALK_OUT_OF_STEP.png b/assets/en/template/TEMPLATE_MAP_WALK_OUT_OF_STEP.png index b9d6d2019..9a2bdd7e1 100644 Binary files a/assets/en/template/TEMPLATE_MAP_WALK_OUT_OF_STEP.png and b/assets/en/template/TEMPLATE_MAP_WALK_OUT_OF_STEP.png differ diff --git a/assets/en/ui/EVENT_LIST_CHECK.png b/assets/en/ui/EVENT_LIST_CHECK.png index 9371d0312..a3ed6d3e3 100644 Binary files a/assets/en/ui/EVENT_LIST_CHECK.png and b/assets/en/ui/EVENT_LIST_CHECK.png differ diff --git a/campaign/event_20200521_en/a3.py b/campaign/event_20200521_en/a3.py index 846c0d7f2..d13edd082 100644 --- a/campaign/event_20200521_en/a3.py +++ b/campaign/event_20200521_en/a3.py @@ -28,8 +28,8 @@ MAP.map_data = ''' class Config: POOR_MAP_DATA = True MAP_HAS_AMBUSH = False - MAP_HAS_FLEET_STEP = False - MAP_HAS_MOVABLE_ENEMY = False + MAP_HAS_FLEET_STEP = True + MAP_HAS_MOVABLE_ENEMY = True MAP_HAS_SIREN = True MAP_HAS_DYNAMIC_RED_BORDER = True MAP_SIREN_COUNT = 1 diff --git a/campaign/event_20200521_en/b1.py b/campaign/event_20200521_en/b1.py index b0b21ef8d..ae2156a8b 100644 --- a/campaign/event_20200521_en/b1.py +++ b/campaign/event_20200521_en/b1.py @@ -24,8 +24,8 @@ A6, B6, C6, D6, E6, F6, G6, H6, \ = MAP.flatten() class Config: - SUBMARINE = 1 - FLEET_BOSS = 1 + SUBMARINE = 0 + FLEET_BOSS = 0 POOR_MAP_DATA = True MAP_HAS_AMBUSH = False diff --git a/campaign/event_20200521_en/b2.py b/campaign/event_20200521_en/b2.py index 376a9a211..f8a088fbe 100644 --- a/campaign/event_20200521_en/b2.py +++ b/campaign/event_20200521_en/b2.py @@ -25,9 +25,18 @@ A6, B6, C6, D6, E6, F6, G6, H6, I6, \ A7, B7, C7, D7, E7, F7, G7, H7, I7, \ = MAP.flatten() +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 2}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 1}, + {'battle': 5, 'boss': 1}, +] + class Config: - SUBMARINE = 1 - FLEET_BOSS = 1 + SUBMARINE = 0 + FLEET_BOSS = 0 POOR_MAP_DATA = True MAP_HAS_AMBUSH = False @@ -56,3 +65,14 @@ class Config: class Campaign(CampaignBase): MAP = MAP + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_enemy(scale=(2, 3)): + return True + + return self.battle_default() + + def battle_5(self): + return self.clear_boss() + diff --git a/campaign/event_20200521_en/b3.py b/campaign/event_20200521_en/b3.py index f1f7446d9..c1d2dd764 100644 --- a/campaign/event_20200521_en/b3.py +++ b/campaign/event_20200521_en/b3.py @@ -17,18 +17,71 @@ MAP.map_data = ''' SP -- -- -- ++ -- -- ME -- SP -- MS -- -- ME -- -- -- ''' +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, \ +A9, B9, C9, D9, E9, F9, G9, H9, I9, \ + = MAP.flatten() + +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 2}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 1}, + {'battle': 5, 'boss': 1}, +] class Config: POOR_MAP_DATA = True MAP_HAS_AMBUSH = False - MAP_HAS_FLEET_STEP = False - MAP_HAS_MOVABLE_ENEMY = False + MAP_HAS_FLEET_STEP = True + MAP_HAS_MOVABLE_ENEMY = True MAP_HAS_SIREN = True - MAP_HAS_DYNAMIC_RED_BORDER = False MAP_SIREN_COUNT = 2 + MAP_HAS_DYNAMIC_RED_BORDER = True + MAP_GRID_CENTER_TOLERANCE = 0.3 + MAP_SIREN_TEMPLATE = ['1', '2', '3', 'DD'] + + INTERNAL_LINES_HOUGHLINES_THRESHOLD = 50 + MID_DIFF_RANGE_H = (45, 70) + MID_DIFF_RANGE_V = (97 - 3, 97 + 3) + TRUST_EDGE_LINES = True + + VANISH_POINT_RANGE = ((540, 740), (-4000, -2000)) + DISTANCE_POINT_X_RANGE = ((-2000, -1000),) + INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (80, 255 - 40), + 'width': (0.9, 10), + 'prominence': 10, + 'distance': 35, + 'wlen': 100, + } + EDGE_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (255 - 40, 255), + 'prominence': 10, + 'distance': 50, + 'wlen': 1000 + } class Campaign(CampaignBase): MAP = MAP + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_enemy(scale=(2, 3)): + return True + + return self.battle_default() + + def battle_5(self): + return self.clear_boss() + diff --git a/campaign/event_20200521_en/c1.py b/campaign/event_20200521_en/c1.py index b5c2b1453..1cf1420a3 100644 --- a/campaign/event_20200521_en/c1.py +++ b/campaign/event_20200521_en/c1.py @@ -13,10 +13,22 @@ MAP.map_data = ''' -- ME -- -- ++ ME -- ME -- SP -- -- ME ++ -- ME -- MB ''' +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, \ + = MAP.flatten() +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 2}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'boss': 1}, +] class Config: - SUBMARINE = 1 POOR_MAP_DATA = True MAP_HAS_AMBUSH = False MAP_HAS_FLEET_STEP = True @@ -44,3 +56,14 @@ class Config: class Campaign(CampaignBase): MAP = MAP + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_enemy(scale=(2, 3)): + return True + + return self.battle_default() + + def battle_4(self): + return self.clear_boss() + diff --git a/campaign/event_20200521_en/c3.py b/campaign/event_20200521_en/c3.py index 1e97da481..62f2993db 100644 --- a/campaign/event_20200521_en/c3.py +++ b/campaign/event_20200521_en/c3.py @@ -29,8 +29,8 @@ MAP.map_data = ''' class Config: POOR_MAP_DATA = True MAP_HAS_AMBUSH = False - MAP_HAS_FLEET_STEP = False - MAP_HAS_MOVABLE_ENEMY = False + MAP_HAS_FLEET_STEP = True + MAP_HAS_MOVABLE_ENEMY = True MAP_HAS_SIREN = True # MAP_HAS_DYNAMIC_RED_BORDER = False MAP_SIREN_COUNT = 2 diff --git a/campaign/event_20200521_en/d1.py b/campaign/event_20200521_en/d1.py index ed4b5199b..cc2fc90f5 100644 --- a/campaign/event_20200521_en/d1.py +++ b/campaign/event_20200521_en/d1.py @@ -17,8 +17,8 @@ MAP.map_data = ''' class Config: - SUBMARINE = 1 - FLEET_BOSS = 2 + SUBMARINE = 0 + FLEET_BOSS = 0 POOR_MAP_DATA = True MAP_HAS_AMBUSH = False diff --git a/campaign/event_20200521_en/d2.py b/campaign/event_20200521_en/d2.py index 6420edfb3..89378fd09 100644 --- a/campaign/event_20200521_en/d2.py +++ b/campaign/event_20200521_en/d2.py @@ -36,8 +36,8 @@ class Config: SUBMARINE = 0 FLEET_BOSS = 0 MAP_HAS_AMBUSH = False - MAP_HAS_FLEET_STEP = False - MAP_HAS_MOVABLE_ENEMY = False + MAP_HAS_FLEET_STEP = True + MAP_HAS_MOVABLE_ENEMY = True MAP_HAS_SIREN = True MAP_HAS_DYNAMIC_RED_BORDER = False MAP_SIREN_COUNT = 3 diff --git a/campaign/event_20200521_en/d3.py b/campaign/event_20200521_en/d3.py index 271cd03ab..6558f2cbd 100644 --- a/campaign/event_20200521_en/d3.py +++ b/campaign/event_20200521_en/d3.py @@ -7,7 +7,7 @@ from module.logger import logger MAP = CampaignMap('d3') MAP.shape = 'I9' MAP.map_data = ''' - SP -- ++ ++ -- MS -- ME -- + SP -- ++ ++ -- -- -- ME -- -- ME ++ ++ -- ME -- -- -- -- -- -- -- -- -- ME ME -- ME -- ME ME -- ME ++ ++ ++ @@ -17,27 +17,51 @@ MAP.map_data = ''' SP -- -- -- ++ -- -- ME -- SP -- MS -- -- ME -- -- -- ''' +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, \ +A9, B9, C9, D9, E9, F9, G9, H9, I9, \ + = MAP.flatten() +MAP.spawn_data = [ + {'battle': 0, 'enemy': 2, 'siren': 2}, + {'battle': 1, 'enemy': 1}, + {'battle': 2, 'enemy': 2, 'siren': 1}, + {'battle': 3, 'enemy': 1}, + {'battle': 4, 'enemy': 1}, + {'battle': 5}, + {'battle': 6, 'boss': 1}, +] class Config: - SUBMARINE = 1 - FLEET_BOSS = 2 - POOR_MAP_DATA = True MAP_HAS_AMBUSH = False MAP_HAS_FLEET_STEP = True MAP_HAS_MOVABLE_ENEMY = True MAP_HAS_SIREN = True - MAP_HAS_DYNAMIC_RED_BORDER = True MAP_SIREN_COUNT = 3 + MAP_HAS_DYNAMIC_RED_BORDER = True + MAP_GRID_CENTER_TOLERANCE = 0.3 + MAP_SIREN_TEMPLATE = ['1', '2', '3', 'DD'] + INTERNAL_LINES_HOUGHLINES_THRESHOLD = 50 + MID_DIFF_RANGE_H = (45, 70) + MID_DIFF_RANGE_V = (97 - 3, 97 + 3) TRUST_EDGE_LINES = True + VANISH_POINT_RANGE = ((540, 740), (-4000, -2000)) + DISTANCE_POINT_X_RANGE = ((-2000, -1000),) INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { 'height': (80, 255 - 40), 'width': (0.9, 10), 'prominence': 10, 'distance': 35, + 'wlen': 100, } EDGE_LINES_FIND_PEAKS_PARAMETERS = { 'height': (255 - 40, 255), @@ -50,3 +74,22 @@ class Config: class Campaign(CampaignBase): MAP = MAP + def battle_0(self): + if self.clear_siren(): + return True + if self.clear_enemy(scale=(2, 3)): + return True + + return self.battle_default() + + def battle_5(self): + if self.clear_enemy(scale=(1,)): + return True + if self.clear_enemy(scale=(2,)): + return True + + return self.battle_default() + + def battle_6(self): + return self.fleet_2.clear_boss() + diff --git a/doc/development.assets/BATTLE_PREPARATION_en.png b/doc/development.assets/BATTLE_PREPARATION_en.png new file mode 100644 index 000000000..b1af14363 Binary files /dev/null and b/doc/development.assets/BATTLE_PREPARATION_en.png differ diff --git a/doc/development.assets/ss.png b/doc/development.assets/ss.png new file mode 100644 index 000000000..924f4940c Binary files /dev/null and b/doc/development.assets/ss.png differ diff --git a/doc/development_en.md b/doc/development_en.md new file mode 100644 index 000000000..2f57a129a --- /dev/null +++ b/doc/development_en.md @@ -0,0 +1,443 @@ +**Translation under progress** + +# Participate in development + +- [How to add a button] (#How to add a button) +- [How to adapt to a new map] (#How to adapt to a new map) + +## How to add a asset + +Assets are stored in `./asset` directory, and is defined in each module `asset.py` file. + +For example, the button `BATTLE_PREPARATION` + +![BATTLE_PREPARATION](development.assets/BATTLE_PREPARATION_en.png) + +In `asset.py` it is this: + +``` +BATTLE_PREPARATION = Button(area={'cn': (1043, 607, 1241, 667), 'en': (1045, 607, 1241, 667)}, color={'cn': (234, 179, 97), 'en': (235, 182, 102)}, button={'cn': (1043, 607, 1241, 667), 'en': (1045, 607, 1241, 667)}, file={'cn': './assets/cn/combat/BATTLE_PREPARATION.png', 'en': './assets/en/combat/BATTLE_PREPARATION.png'}) +``` + +Note that all `asset.py` are generate with `./dev_tools/button_extract.py`, not to manually modify. + +Suppose we want to add a `CONFIRM` button, which appears in the submarine signal scanning. + +1. **Screenshot** + + ![screenshot](development.assets/ss.png) + + the best way to take screenshots its using `adb exec-out screencap -p > screenshot.png` + + If you get some output error, maybe you need to add your emulator port like that `adb -s 127.0.0.1:5555 exec-out screencap -p >screenshot.png` + +2. **Copy the picture to the corresponding directory under `./asset`**, and change the file name, for example `EQUIP_CONFIRM.png` + +3. **Drag to Photoshop**, here takes Photoshop CS6 as an example + +4. **Use the selection tool (M) to select the button area** + +5. **Play action** + +In the first operation, you can follow the steps below to add actions. + +In the menu bar `WINDOW`, click on `ACTION` option or ALT+F9 + +Before adding actions, it is best to back-up the current picture, because the next operation that needs to be recorded is irreversible. + +* In the action window, click the icon of the new action, and name it according to your preferences, for example button_image. Click `Begin Recording`, note that the gray circle turns red, which means that action recording has started +* Right-click in the picture area, click `Inverse` or `SHIFT+CTRL+I` +* In the menu bar `Edit`, click `Fill` or `SHIFT+F5` +* In the pop-up fill window, fill content use `Black`, fill mode selection `normal`, opacity select 100, click `Ok` +* In the menu bar `File`, click `Save` +* In the menu bar `File`, click `Close` +* In the action window, click the stop recording icon, the action recording will stop. + +After the recording is completed, you will get the following actions + + ``` + button_image + Inverse + Fill + Using: Black + Opacity: 100% + Mode: normal + Save + Close + ``` + + When adding assets in the future, you can directly click the button of the playback action to complete the image processing. + +6. **(Optional) Add attributes to overlay pictures** + + A asset has three attributes: + + - area, the area identified by the asset + - color, the color of the asset + - button, click area after the asset appears + + If you place `SEARCH_CONFIRM.BUTTON.png` in the same folder, and process it with the method mentioned above. The `button` attribute of `SEARCH_CONFIRM.BUTTON.png` will over-write `button` attribute of `SEARCH_CONFIRM.png` + +This is a very useful feature, because the script usually needs to analyze the elements that appear in the screenshot and click on the button. The location that needs to be analyzed and the location that needs to be clicked may not be in the same position. + +7. **Run button_extract.py under ./dev_tools** + + button_extract.py will automatically extract the attributes of the button, eliminating the trouble of manual input. + + ``` + python -m dev_tools.button_extract + ``` + +8. **Use button** + + Inherit the ModuleBase class under module.base.base, you can call the following methods: + + - appear() + - appear_then_click() + - wait_until_appear() + - wait_until_appear_then_click() + - wait_until_disappear() + + Optional parameters of the method: + + - offset (bool, int, tuple): The default is 0, when it is 0, the average color of the button on the screenshot will be used to identify the button + + After input, it means that the button refers to the preset area offset range, and then use the template matching to identify the button + + - interval (int): The trigger interval of the button, the default is 0. + + Represents the trigger interval of the button. When there is an animation after the button is clicked, this parameter can prevent the button from being frequently clicked. + + - screenshot (bool): Save the screenshot after the button appears + + - genre (str): the name of the subdirectory where the screenshot is saved + + + +## How to adapt to a new map + +The following example is adapted to the simple version of 7-2. The complete logic is in `campaign/campaign_main/7_2.py` + +### Define the map + +1. **New file** + + In `./campaign`if it's a new event, create a new directory, as recommended name the directory `event__`, such as `event_20200326_cn `or `event_20200521_en`. + + Create a new .py file, the file name is the map name, lowercase, starting with a letter, such as sp3, d3. + +2. **Import入** + + ``` + from module.campaign.campaign_base import CampaignBase + from module.map.map_base import CampaignMap + ``` + +3. ``` + MAP = CampaignMap() + ``` + +4. **(Optional) Set the map size** + + When not filled, it is generated according to the sea area information + + ``` + MAP.shape = 'H5' + ``` + +5. **Set sea area information** + + In Azur Lane WIKI you can see the map data, if it is a new map, WIKI may take 1 day or 2 to update... + + ![wiki_7_2](development.assets/wiki_7_2.jpg) + + ``` + MAP.map_data = ''' + ME ++ ME -- ME ME -- SP + MM ++ ++ MM -- -- ME -- + ME -- ME MB ME -- ME MM + -- ME -- MM -- ME ++ ++ + SP -- ME ME -- ME ++ ++ + ''' + ``` + + The map information must contain at least the location of land and sea. There are still some difficulties in identifying land and sea + + If the Spawn point (SP) is relatively remote, you must also include it + + ``` + MAP.map_data = ''' + -- ++ ++ -- -- -- -- SP + -- ++ -- -- -- -- -- -- + -- -- -- -- -- -- -- -- + -- -- -- -- -- -- ++ ++ + SP -- -- -- -- -- ++ ++ + ''' + ``` + + The meaning of these symbols is in `module/map/grid_info.py`. + +| print_name | property_name | description | +|------------|----------------|-------------------------| +| ++ | is_land | fleet can't go to land | +| -- | is_sea | sea | +| __ | | submarine spawn point | +| SP | is_spawn_point | fleet may spawns here | +| ME | may_enemy | enemy may spawns here | +| MB | may_boss | boss may spawns here | +| MM | may_mystery | mystery may spawns here | +| MA | may_ammo | fleet can get ammo here | +| MS | may_siren | Siren/Elite enemy spawn | + +6. **(Optional) Set sea weights** + + The higher the value, the less you want the fleet to go. When not set, all are 10. + + ``` + MAP.weight_data = ''' + 40 30 30 30 30 30 30 30 + 20 20 20 20 20 20 20 20 + 10 10 10 10 10 10 10 10 + 20 20 20 20 20 20 20 20 + 30 30 30 30 30 30 30 30 + ''' + ``` + +7. **(Optional) Set the camera position* + + ``` + MAP.camera_data = ['D3'] + ``` + + When not set, it will be generated according to the map size and camera field of view. + + Manual setting can speed up the map scanning speed. For example, in 7-2, the automatically generated camera position is D2 D3 E2 E3. In fact, you only need to point the camera at D3 to see the entire map (A1 does not matter).. + +8. **(Optional) Set enemy refresh information** + + ``` + MAP.spawn_data = [ + {'battle': 0, 'enemy': 3}, + {'battle': 1, 'enemy': 2, 'mystery': 1}, + {'battle': 2, 'enemy': 2, 'mystery': 1}, + {'battle': 3, 'enemy': 1, 'mystery': 2}, + {'battle': 4, 'enemy': 1}, + {'battle': 5, 'boss': 1}, + ] + ``` + + Here is a logic of what will be refreshed after each battle.This information is not on WIKI and needs to be collected manually. + + In theory, it can be run without filling in. The function of the enemy’s refresh information is to correct the recognition errors and missing, and to capture the camera movement when the BOSS is refreshed. + +9. **Expand the map** + + ``` + 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, \ + = MAP.flatten() + ``` + + This is to prepare for the subsequent writing of the enemy logic, which can be generated using the following code + + ``` + shape = 'H5' + def location2node(location): + return chr(location[0] + 64 + 1) + str(location[1] + 1) + def node2location(node): + return ord(node[0]) % 32 - 1, int(node[1]) - 1 + shape = node2location(shape.upper()) + for y in range(shape[1]+1): + text = ', '.join([location2node((x, y)) for x in range(shape[0]+1)]) + ', \\' + print(text) + print(' = MAP.flatten()') + ``` + The py file can be found at `dev_tools/Flatten_generator.py` + +10. **(Optional) Define map elements** + + Such as defining roadblocks + + ``` + ROAD_MAIN = RoadGrids([A3, [C3, B4, C5], [F1, G2, G3]]) + ``` + + + +### Set map parameters + +The map parameters will override the default parameters and user parameters, with the highest priority. + +If you don't know how to set it, just skip it. But it needs to be defined. + +``` +class Config: + pass +``` + +Refer to module.config.config for properties that can be set + +For example, for the microlayer D3, because the map adds sea fog, different grid recognition parameters are required (the default parameters are for 7-2). + +``` +class Config: + INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (100, 220), + 'width': 1, + 'prominence': 10, + 'distance': 35, + } + EDGE_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (255 - 80, 255), + 'prominence': 2, + 'distance': 50, + 'wlen': 1000 + } +``` + +There should be the following settings for enable siren recognition. + +``` +class Config: + MAP_HAS_AMBUSH = False + MAP_HAS_FLEET_STEP = True + MAP_HAS_MOVABLE_ENEMY = True + MAP_HAS_SIREN = True + MAP_HAS_DYNAMIC_RED_BORDER = True + MAP_SIREN_COUNT = 2 +``` + +If only the least sea area information is entered, or there is no enemy refresh information, it should be noted that the map information is missing, and it will run in `wasteland mode` at this time + +``` +class Config: + POOR_MAP_DATA = True +``` + +For Crimson Echoes, the camera position was raised, the grid was reduced to 0.66. + +``` +class Config: + MAP_GRID_CENTER_TOLERANCE = 0.3 + + INTERNAL_LINES_HOUGHLINES_THRESHOLD = 50 + EDGE_LINES_HOUGHLINES_THRESHOLD = 50 + CAMERA_SWIPE_MULTIPLY_X = 200 * 0.7 + CAMERA_SWIPE_MULTIPLY_Y = 140 * 0.7 + COINCIDENT_POINT_ENCOURAGE_DISTANCE = 1. + MID_DIFF_RANGE_H = (45, 70) + MID_DIFF_RANGE_V = (97 - 3, 97 + 3) + TRUST_EDGE_LINES = True + + VANISH_POINT_RANGE = ((540, 740), (-4000, -2000)) + DISTANCE_POINT_X_RANGE = ((-2000, -1000),) + INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (80, 255 - 40), + 'width': (0.9, 10), + 'prominence': 10, + 'distance': 35, + 'wlen': 100, + } + EDGE_LINES_FIND_PEAKS_PARAMETERS = { + 'height': (255 - 40, 255), + 'prominence': 10, + 'distance': 50, + 'wlen': 1000 + } +``` + + + +### Write search logic + +- Run at default + + ``` + class Campaign(CampaignBase): + MAP = MAP + ``` + +- Simple logic + + Write logic according to the first few battles, when missing, use the logic of the previous battle + + Generally speaking, the logic of each battle should start with a question mark and clear roadblocks, then clear potential roadblocks, and finally return to the default battle logic + + ``` + class Campaign(CampaignBase): + MAP = MAP + + def battle_0(self): + self.clear_all_mystery(nearby=False) + if self.clear_roadblocks([ROAD_MAIN], strongest=True): + return True + if self.clear_potential_roadblocks([ROAD_MAIN], strongest=True): + return True + if self.clear_enemy(strongest=True, weight=True): + return True + + return self.battle_default() + + def battle_5(self): + self.clear_all_mystery(nearby=False) + if self.clear_roadblocks([ROAD_MAIN]): + return True + + return self.fleet_2.brute_clear_boss() + ``` + + + +To be continued + + + +## How to support other server/language + +### GUI + +Copy `./module/config/argparser.py` to `argparser_xx.py` and change the argment. + +Create a dictionary in `./module/config/dictionary.py` that translate your language to english. + +Copy `alas_cn.py` to `alas_xx.py` and import `argparser_xx.py` . Then, edit server name. + +> Format of .pyw file name: _.pyw +> +> Script name is used to load ini file under `./config`, For example, alas_cn.pyw and alas_en.pyw both loads `./config/alas.ini`, but in different languages. + +### Assets + +Copy folder `./assets/cn` to `./assets/`, and replace the image. This will cost a lot of time to find, crop and test. Fortunately, if a image does not contain any charactors, it may works in all servers. + +After replacing an image, don't forget to run `./dev_tools/button_extract.py` + +### Class methods + +Some method may be different in different servers. This decoractor is use to calls different function with a same name according to config (AzurLaneConfig instance). + +``` +from module.base.decorator import Config +from module.base.base import ModuleBase + +class AnotherModule(ModuleBase): + @Config.when(SERVER='en') + def function(self): + # This method will be called only in EN server + pass + + @Config.when(SERVER=None) + def function(self): + # This method will be called in other server + pass +``` + +### Other + +There area also some modules diffcult to change: the commission module. + +In `./module/reward/commission.py`, I use [cnocr](https://github.com/breezedeus/cnocr) to recognize commission name in chinese, it may not works well in other languages. + diff --git a/module/campaign/campaign_ocr.py b/module/campaign/campaign_ocr.py index f36465486..c4e56b5a2 100644 --- a/module/campaign/campaign_ocr.py +++ b/module/campaign/campaign_ocr.py @@ -162,7 +162,7 @@ class CampaignOcr: self.stage_entrance = {} buttons = self.campaign_extract_name_image(image) - ocr = Ocr(buttons, lang='stage', letter=(255, 255, 255), back=(102, 102, 102), threshold=180) + ocr = Ocr(buttons, lang='stage', letter=(255, 255, 255), back=(102, 102, 102), threshold=120) result = ocr.ocr(image) if not isinstance(result, list): result = [result] diff --git a/module/combat/assets.py b/module/combat/assets.py index ef2a4360b..e36a52117 100644 --- a/module/combat/assets.py +++ b/module/combat/assets.py @@ -12,6 +12,8 @@ AUTOMATION_SWITCH = Button(area={'cn': (821, 106, 907, 136), 'en': (823, 109, 90 BATTLE_PREPARATION = Button(area={'cn': (1043, 607, 1241, 667), 'en': (1045, 607, 1241, 667)}, color={'cn': (234, 179, 97), 'en': (235, 182, 102)}, button={'cn': (1043, 607, 1241, 667), 'en': (1045, 607, 1241, 667)}, file={'cn': './assets/cn/combat/BATTLE_PREPARATION.png', 'en': './assets/en/combat/BATTLE_PREPARATION.png'}) BATTLE_PREPARATION_WITH_OVERLAY = Button(area={'cn': (1058, 622, 1226, 652), 'en': (1058, 622, 1226, 652)}, color={'cn': (96, 74, 39), 'en': (96, 74, 39)}, button={'cn': (1058, 622, 1226, 652), 'en': (1058, 622, 1226, 652)}, file={'cn': './assets/cn/combat/BATTLE_PREPARATION_WITH_OVERLAY.png', 'en': './assets/en/combat/BATTLE_PREPARATION_WITH_OVERLAY.png'}) BATTLE_STATUS_A = Button(area={'cn': (622, 266, 732, 288), 'en': (622, 266, 732, 288)}, color={'cn': (235, 227, 111), 'en': (235, 227, 111)}, button={'cn': (1000, 631, 1055, 689), 'en': (999, 630, 1047, 691)}, file={'cn': './assets/cn/combat/BATTLE_STATUS_A.png', 'en': './assets/en/combat/BATTLE_STATUS_A.png'}) +BATTLE_STATUS_C = Button(area={'cn': (431, 257, 514, 329), 'en': (431, 257, 514, 329)}, color={'cn': (169, 161, 164), 'en': (169, 161, 164)}, button={'cn': (431, 257, 514, 329), 'en': (431, 257, 514, 329)}, file={'cn': './assets/cn/combat/BATTLE_STATUS_C.png', 'en': './assets/en/combat/BATTLE_STATUS_C.png'}) +BATTLE_STATUS_D = Button(area={'cn': (431, 257, 514, 329), 'en': (431, 257, 514, 329)}, color={'cn': (169, 161, 164), 'en': (169, 161, 164)}, button={'cn': (431, 257, 514, 329), 'en': (431, 257, 514, 329)}, file={'cn': './assets/cn/combat/BATTLE_STATUS_D.png', 'en': './assets/en/combat/BATTLE_STATUS_D.png'}) BATTLE_STATUS_S = Button(area={'cn': (633, 297, 722, 320), 'en': (629, 297, 722, 318)}, color={'cn': (233, 241, 127), 'en': (233, 241, 127)}, button={'cn': (1000, 631, 1055, 689), 'en': (999, 630, 1047, 691)}, file={'cn': './assets/cn/combat/BATTLE_STATUS_S.png', 'en': './assets/en/combat/BATTLE_STATUS_S.png'}) COMBAT_AUTO = Button(area={'cn': (136, 573, 167, 604), 'en': (136, 573, 167, 604)}, color={'cn': (229, 242, 255), 'en': (229, 242, 255)}, button={'cn': (136, 573, 167, 604), 'en': (136, 573, 167, 604)}, file={'cn': './assets/cn/combat/COMBAT_AUTO.png', 'en': './assets/en/combat/COMBAT_AUTO.png'}) COMBAT_AUTO_SWITCH = Button(area={'cn': (18, 38, 36, 56), 'en': (16, 31, 140, 62)}, color={'cn': (179, 198, 235), 'en': (105, 137, 189)}, button={'cn': (18, 38, 36, 56), 'en': (16, 31, 140, 62)}, file={'cn': './assets/cn/combat/COMBAT_AUTO_SWITCH.png', 'en': './assets/en/combat/COMBAT_AUTO_SWITCH.png'}) diff --git a/module/config/argparser_en.py b/module/config/argparser_en.py index f495f06e0..7e4f20898 100644 --- a/module/config/argparser_en.py +++ b/module/config/argparser_en.py @@ -53,7 +53,7 @@ def update_config_from_template(config, file): sidebar_title='Function', terminal_font_family='Consolas', language='english', - default_size=(1000, 720), + default_size=(1110, 720), navigation='SIDEBAR', tabbed_groups=True, show_success_modal=False, @@ -119,7 +119,7 @@ def main(ini_name=''): # 选择关卡 stage = setting_parser.add_argument_group('Level settings', 'Need to run once to save options') stage.add_argument('--enable_stop_condition', default=default('--enable_stop_condition'), choices=['yes', 'no']) - stage.add_argument('--enable_fast_forward', default=default('--enable_fast_forward'), choices=['yes', 'no']) + stage.add_argument('--enable_fast_forward', default=default('--enable_fast_forward'), choices=['yes', 'no'], help='Enable or disable clearing mode') stop = stage.add_argument_group('Stop condition', 'After triggering, it will not stop immediately. It will complete the current attack first, and fill in 0 if it is not needed.') stop.add_argument('--if_count_greater_than', default=default('--if_count_greater_than'), help='The previous setting will be used, and the number\n of deductions will be deducted after completion of the attack until it is cleared.') @@ -133,7 +133,7 @@ def main(ini_name=''): fleet.add_argument('--enable_fleet_control', default=default('--enable_fleet_control'), choices=['yes', 'no']) fleet.add_argument('--enable_map_fleet_lock', default=default('--enable_map_fleet_lock'), choices=['yes', 'no']) - f1 = fleet.add_argument_group('Road Fleet', 'Players can choose a formation before battle. Though it has no effect appearance-wise, the formations applies buffs to certain stats.\nLine Ahead: Increases Firepower and Torpedo by 15%, but reduces Evasion by 10% (Applies only to Vanguard fleet)\nDouble Line: Increases Evasion by 30%, but decreases Firepower and Torpedo by 5% (Applies only to Vanguard fleet)\nDiamond: Increases Anti-Air by 20% (no penalties, applies to entire fleet)') + f1 = fleet.add_argument_group('Mob Fleet', 'Players can choose a formation before battle. Though it has no effect appearance-wise, the formations applies buffs to certain stats.\nLine Ahead: Increases Firepower and Torpedo by 15%, but reduces Evasion by 10% (Applies only to Vanguard fleet)\nDouble Line: Increases Evasion by 30%, but decreases Firepower and Torpedo by 5% (Applies only to Vanguard fleet)\nDiamond: Increases Anti-Air by 20% (no penalties, applies to entire fleet)') f1.add_argument('--fleet_index_1', default=default('--fleet_index_1'), choices=['1', '2', '3', '4', '5', '6']) f1.add_argument('--fleet_formation_1', default=default('--fleet_formation_1'), choices=['Line Ahead', 'Double Line', 'Diamond']) f1.add_argument('--fleet_step_1', default=default('--fleet_step_1'), choices=['1', '2', '3', '4', '5', '6'], help='In event map, fleet has limit on moving, so fleet_step is how far can a fleet goes in one operation, if map cleared, it will be ignored') @@ -143,7 +143,7 @@ def main(ini_name=''): f2.add_argument('--fleet_formation_2', default=default('--fleet_formation_2'), choices=['Line Ahead', 'Double Line', 'Diamond']) f2.add_argument('--fleet_step_2', default=default('--fleet_step_2'), choices=['1', '2', '3', '4', '5', '6'], help='In event map, fleet has limit on moving, so fleet_step is how far can a fleet goes in one operation, if map cleared, it will be ignored') - f3 = fleet.add_argument_group('Alternate Road Fleet') + f3 = fleet.add_argument_group('Alternate Mob Fleet') f3.add_argument('--fleet_index_3', default=default('--fleet_index_3'), choices=['do_not_use', '1', '2', '3', '4', '5', '6']) f3.add_argument('--fleet_formation_3', default=default('--fleet_formation_3'), choices=['Line Ahead', 'Double Line', 'Diamond']) f3.add_argument('--fleet_step_3', default=default('--fleet_step_3'), choices=['1', '2', '3', '4', '5', '6'], help='In event map, fleet has limit on moving, so fleet_step is how far can a fleet goes in one operation, if map cleared, it will be ignored') @@ -152,7 +152,7 @@ def main(ini_name=''): f4.add_argument('--combat_auto_mode', default=default('--combat_auto_mode'), choices=['combat_auto', 'combat_manual', 'stand_still_in_the_middle']) # 潜艇设置 - submarine = setting_parser.add_argument_group('Submarine settings', 'Only supported: hunt_only, do_not_use every_combat') + submarine = setting_parser.add_argument_group('Submarine settings', 'Only supported: hunt_only, do_not_use and every_combat') submarine.add_argument('--fleet_index_4', default=default('--fleet_index_4'), choices=['do_not_use', '1', '2']) submarine.add_argument('--submarine_mode', default=default('--submarine_mode'), choices=['do_not_use', 'hunt_only', 'every_combat', 'when_no_ammo', 'when_boss_combat', 'when_boss_combat_boss_appear']) @@ -161,7 +161,7 @@ def main(ini_name=''): emotion.add_argument('--enable_emotion_reduce', default=default('--enable_emotion_reduce'), choices=['yes', 'no']) emotion.add_argument('--ignore_low_emotion_warn', default=default('--ignore_low_emotion_warn'), choices=['yes', 'no']) - e1 = emotion.add_argument_group('Road Fleet') + e1 = emotion.add_argument_group('Mob Fleet') e1.add_argument('--emotion_recover_1', default=default('--emotion_recover_1'), choices=['not_in_dormitory', 'dormitory_floor_1', 'dormitory_floor_2']) e1.add_argument('--emotion_control_1', default=default('--emotion_control_1'), choices=['keep_high_emotion', 'avoid_green_face', 'avoid_yellow_face', 'avoid_red_face']) e1.add_argument('--hole_fleet_married_1', default=default('--hole_fleet_married_1'), choices=['yes', 'no']) @@ -171,7 +171,7 @@ def main(ini_name=''): e2.add_argument('--emotion_control_2', default=default('--emotion_control_2'), choices=['keep_high_emotion', 'avoid_green_face', 'avoid_yellow_face', 'avoid_red_face']) e2.add_argument('--hole_fleet_married_2', default=default('--hole_fleet_married_2'), choices=['yes', 'no']) - e3 = emotion.add_argument_group('Alternate Road Fleet', 'Will be used when the home team triggers mood control') + e3 = emotion.add_argument_group('Alternate Mob Fleet', 'Will be used when the first team triggers mood control') e3.add_argument('--emotion_recover_3', default=default('--emotion_recover_3'), choices=['not_in_dormitory', 'dormitory_floor_1', 'dormitory_floor_2']) e3.add_argument('--emotion_control_3', default=default('--emotion_control_3'), choices=['keep_high_emotion', 'avoid_green_face', 'avoid_yellow_face', 'avoid_red_face']) e3.add_argument('--hole_fleet_married_3', default=default('--hole_fleet_married_3'), choices=['yes', 'no']) @@ -182,7 +182,7 @@ def main(ini_name=''): hp.add_argument('--enable_low_hp_withdraw', default=default('--enable_low_hp_withdraw'), choices=['yes', 'no']) hp_balance = hp.add_argument_group('HP Balance', '') hp_balance.add_argument('--scout_hp_difference_threshold', default=default('--scout_hp_difference_threshold'), help='When the difference in HP volume is greater than the threshold, transpose') - hp_balance.add_argument('--scout_hp_weights', default=default('--scout_hp_weights'), help='Pioneer flesh should be modified when there is a difference, the format 1000,1000,1000') + hp_balance.add_argument('--scout_hp_weights', default=default('--scout_hp_weights'), help='Should be repaired when there is a difference in Vanguard, format 1000,1000,1000') hp_add = hp.add_argument_group('Emergency repair', '') hp_add.add_argument('--emergency_repair_single_threshold', default=default('--emergency_repair_single_threshold'), help='Used when single shipgirl is below the threshold') hp_add.add_argument('--emergency_repair_hole_threshold', default=default('--emergency_repair_hole_threshold'), help='Used when all front rows or all back rows are below the threshold') @@ -250,23 +250,23 @@ def main(ini_name=''): priority4.add_argument('--urgent_part', default=default('--urgent_part'), help='Support Vila Vela Island, support terror Banner') priority4.add_argument('--urgent_cube', default=default('--urgent_cube'), help='Rescue merchant ship, enemy attack') priority4.add_argument('--urgent_book', default=default('--urgent_book'), help='Support Tuhaoer Island, support Moe Island') - priority4.add_argument('--urgent_box', default=default('--urgent_box'), help='BIW equipment transportation, NYB equipment research and development') - priority4.add_argument('--urgent_gem', default=default('--urgent_gem'), help='BIW VIP guard, NYB patrol guard') - priority4.add_argument('--urgent_ship', default=default('--urgent_ship'), help='Small ship watching ceremony, alliance ship watching ceremony') + priority4.add_argument('--urgent_box', default=default('--urgent_box'), help='BIW Gear Transport, NYB Gear Transport') + priority4.add_argument('--urgent_gem', default=default('--urgent_gem'), help='BIW VIP Escort, NYB VIP Escort') + priority4.add_argument('--urgent_ship', default=default('--urgent_ship'), help='Small Launch Ceremony, Fleet Launch Ceremony, Alliance Launch Ceremony') reward_tactical = reward_parser.add_argument_group('Classroom', 'Only support continuation of skill books, not new skills') reward_tactical.add_argument('--enable_tactical_reward', default=default('--enable_tactical_reward'), choices=['yes', 'no']) reward_tactical.add_argument('--tactical_night_range', default=default('--tactical_night_range'), help='Format 23:30-06:30') - reward_tactical.add_argument('--tactical_book_tier', default=default('--tactical_book_tier'), choices=['3', '2', '1'], help='Skill book that uses at most T a few \nT3 is a gold book, T2 is a purple book, T1 is a blue book') + reward_tactical.add_argument('--tactical_book_tier', default=default('--tactical_book_tier'), choices=['3', '2', '1'], help='Wich skill book will use first\nT3 is a gold book, T2 is a purple book, T1 is a blue book') reward_tactical.add_argument('--tactical_exp_first', default=default('--tactical_exp_first'), choices=['yes', 'no'], help='Choose Yes, give priority to the 150% bonus \nSelect No, give priority to the skills book with the same rarity') reward_tactical.add_argument('--tactical_book_tier_night', default=default('--tactical_book_tier_night'), choices=['3', '2', '1']) reward_tactical.add_argument('--tactical_exp_first_night', default=default('--tactical_exp_first_night'), choices=['yes', 'no']) # ==========emulator========== emulator_parser = subs.add_parser('emulator') - emulator = emulator_parser.add_argument_group('Emulator', 'Need to run once to save the options, it will check whether the game is started \nIf the game is started, trigger a collection') + emulator = emulator_parser.add_argument_group('Emulator', 'Need to run once to save the options, it will check whether the game is started \nIf the game has not started, it will be started') emulator.add_argument('--serial', default=default('--serial'), help='Bluestacks 127.0.0.1:5555 \nNox 127.0.0.1:62001') - emulator.add_argument('--package_name', default=default('--package_name'), help='') + emulator.add_argument('--package_name', default='com.YoStarEN.AzurLane', help='') debug = emulator_parser.add_argument_group('Debug settings', '') debug.add_argument('--enable_error_log_and_screenshot_save', default=default('--enable_error_log_and_screenshot_save'), choices=['yes', 'no']) @@ -274,7 +274,7 @@ def main(ini_name=''): adb = emulator_parser.add_argument_group('ADB settings', '') adb.add_argument('--use_adb_screenshot', default=default('--use_adb_screenshot'), choices=['yes', 'no'], help='It is recommended to enable it to reduce CPU usage') - adb.add_argument('--use_adb_control', default=default('--use_adb_control'), choices=['yes', 'no'], help='Suggest to close, can speed up the click speed') + adb.add_argument('--use_adb_control', default=default('--use_adb_control'), choices=['yes', 'no'], help='Recommended off, can speed up the click speed') adb.add_argument('--combat_screenshot_interval', default=default('--combat_screenshot_interval'), help='Slow down the screenshot speed during battle and reduce CPU') # ==========每日任务========== @@ -296,7 +296,7 @@ def main(ini_name=''): daily_task.add_argument('--daily_equipment', default=default('--daily_equipment'), help='Change equipment before playing, unload equipment after playing, do not need to fill in 0 \ncomma, such as 3, 1, 0, 1, 1, 0') # 困难设置 - hard = daily_parser.add_argument_group('Difficult setting', 'Need to turn on weekly mode, only support 10-4 temporarily') + hard = daily_parser.add_argument_group('Difficult setting', 'Need to turn on weekly mode, only support 10-1, 10-2 and 10-4 temporarily') hard.add_argument('--hard_campaign', default=default('--hard_campaign'), help='For example 10-4') hard.add_argument('--hard_fleet', default=default('--hard_fleet'), choices=['1', '2']) hard.add_argument('--hard_equipment', default=default('--hard_equipment'), help='Change equipment before playing, unload equipment after playing, do not need to fill in 0 \ncomma, such as 3, 1, 0, 1, 1, 0') @@ -311,14 +311,15 @@ def main(ini_name=''): exercise.add_argument('--exercise_equipment', default=default('--exercise_equipment'), help='Change equipment before playing, unload equipment after playing, do not need to fill in 0 \ncomma, such as 3, 1, 0, 1, 1, 0') # ==========event_daily_ab========== - event_ab_parser = subs.add_parser('event_daily_ab') + event_ab_parser = subs.add_parser('event_daily_bonus') event_name = event_ab_parser.add_argument_group('Choose an event', 'bonus for first clear each day') event_name.add_argument('--event_name_ab', default=default('--event_name_ab'), choices=event_folder, help='There a dropdown menu with many options') + # event_name.add_argument('--enable_hard_bonus', default=default('--enable_hard_bonus'), choices=['yes', 'no'], help='Will enable Daily bonus for Event hard maps') # Trying implement all event maps # ==========main========== main_parser = subs.add_parser('main') # 选择关卡 - stage = main_parser.add_argument_group('Choose a level', 'The main line chart strikes, currently only supports the first six chapters and 7-2') + stage = main_parser.add_argument_group('Choose a level', 'Main campaign, currently only supports the first six chapters and 7-2') stage.add_argument('--main_stage', default=default('--main_stage'), help='E.g 7-2') # ==========event========== @@ -356,9 +357,9 @@ def main(ini_name=''): # ==========c124_leveling========== c_12_4_parser = subs.add_parser('c12-4_leveling') c_12_4 = c_12_4_parser.add_argument_group('12-4 Search enemy settings', 'Need to ensure that the team has a certain strength') - c_12_4.add_argument('--non_s3_enemy_enter_tolerance', default=default('--non_s3_enemy_enter_tolerance'), choices=['0', '1', '2'], help='Endure how many battles to enter without big') + c_12_4.add_argument('--non_s3_enemy_enter_tolerance', default=default('--non_s3_enemy_enter_tolerance'), choices=['0', '1', '2'], help='Avoid enemy too strong') c_12_4.add_argument('--non_s3_enemy_withdraw_tolerance', default=default('--non_s3_enemy_withdraw_tolerance'), choices=['0', '1', '2', '10'], help='How many battles will be fought after there is no large scale') - c_12_4.add_argument('--ammo_pick_up_124', default=default('--ammo_pick_up_124'), choices=['2', '3', '4', '5'], help='How much ammunition to pick after the war') + c_12_4.add_argument('--ammo_pick_up_124', default=default('--ammo_pick_up_124'), choices=['2', '3', '4', '5'], help='How much ammunition to pick after the battle') args = parser.parse_args() diff --git a/module/config/dictionary.py b/module/config/dictionary.py index 3830ca73e..8ea286081 100644 --- a/module/config/dictionary.py +++ b/module/config/dictionary.py @@ -28,7 +28,7 @@ dic_true_eng_to_eng = { 'reward': 'reward', 'emulator': 'emulator', 'daily': 'daily', - 'event_daily_ab': 'event_daily_ab', + 'event_daily_bonus': 'event_daily_ab', 'main': 'main', 'event': 'event', 'semi_auto': 'semi_auto', @@ -162,7 +162,7 @@ dic_true_eng_to_eng = { 'no': 'no', 'Line Ahead': 'formation_1', 'Double Line': 'formation_2', - 'formation_3': 'formation_3', + 'Diamond': 'formation_3', 'combat_auto': 'combat_auto', 'combat_manual': 'combat_manual', 'stand_still_in_the_middle': 'stand_still_in_the_middle', diff --git a/module/event/campaign_ab.py b/module/event/campaign_ab.py index 62f2c55ab..fca97e84b 100644 --- a/module/event/campaign_ab.py +++ b/module/event/campaign_ab.py @@ -3,6 +3,8 @@ from module.campaign.run import CampaignRun RECORD_SINCE = (0,) CAMPAIGN_NAME = ['a1', 'a2', 'a3', 'b1', 'b2', 'b3'] +# CAMPAIGN_ALL = ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3', 'd1', 'd2', 'd3'] # Trying implement all event maps + class CampaignAB(CampaignRun): diff --git a/module/handler/assets.py b/module/handler/assets.py index b9112a755..badb64344 100644 --- a/module/handler/assets.py +++ b/module/handler/assets.py @@ -20,10 +20,10 @@ INFO_BAR_2 = Button(area={'cn': (194, 234, 1086, 236), 'en': (194, 234, 1086, 23 INFO_BAR_3 = Button(area={'cn': (194, 171, 1086, 173), 'en': (194, 171, 1086, 173)}, color={'cn': (107, 158, 255), 'en': (107, 158, 255)}, button={'cn': (194, 171, 1086, 173), 'en': (194, 171, 1086, 173)}, file={'cn': './assets/cn/handler/INFO_BAR_3.png', 'en': './assets/en/handler/INFO_BAR_3.png'}) IN_MAP = Button(area={'cn': (749, 654, 921, 707), 'en': (748, 652, 922, 702)}, color={'cn': (213, 124, 124), 'en': (211, 124, 124)}, button={'cn': (749, 654, 921, 707), 'en': (748, 652, 922, 702)}, file={'cn': './assets/cn/handler/IN_MAP.png', 'en': './assets/en/handler/IN_MAP.png'}) IN_STAGE = Button(area={'cn': (122, 16, 172, 39), 'en': (120, 18, 208, 40)}, color={'cn': (149, 167, 207), 'en': (104, 118, 157)}, button={'cn': (122, 16, 172, 39), 'en': (120, 18, 208, 40)}, file={'cn': './assets/cn/handler/IN_STAGE.png', 'en': './assets/en/handler/IN_STAGE.png'}) -LOGIN_ANNOUNCE = Button(area={'cn': (1160, 45, 1227, 90), 'en': (1160, 45, 1227, 90)}, color={'cn': (174, 61, 56), 'en': (174, 61, 56)}, button={'cn': (1160, 45, 1227, 90), 'en': (1160, 45, 1227, 90)}, file={'cn': './assets/cn/handler/LOGIN_ANNOUNCE.png', 'en': './assets/en/handler/LOGIN_ANNOUNCE.png'}) +LOGIN_ANNOUNCE = Button(area={'cn': (1160, 45, 1227, 90), 'en': (1159, 44, 1228, 91)}, color={'cn': (174, 61, 56), 'en': (193, 79, 73)}, button={'cn': (1160, 45, 1227, 90), 'en': (1159, 44, 1228, 91)}, file={'cn': './assets/cn/handler/LOGIN_ANNOUNCE.png', 'en': './assets/en/handler/LOGIN_ANNOUNCE.png'}) LOGIN_CHECK = Button(area={'cn': (77, 655, 154, 711), 'en': (77, 655, 154, 711)}, color={'cn': (33, 36, 33), 'en': (33, 36, 33)}, button={'cn': (416, 294, 534, 400), 'en': (416, 294, 534, 400)}, file={'cn': './assets/cn/handler/LOGIN_CHECK.png', 'en': './assets/en/handler/LOGIN_CHECK.png'}) LOGIN_GAME_UPDATE = Button(area={'cn': (700, 471, 873, 529), 'en': (700, 471, 873, 529)}, color={'cn': (238, 170, 78), 'en': (238, 170, 78)}, button={'cn': (700, 471, 873, 529), 'en': (700, 471, 873, 529)}, file={'cn': './assets/cn/handler/LOGIN_GAME_UPDATE.png', 'en': './assets/en/handler/LOGIN_GAME_UPDATE.png'}) -LOGIN_RETURN_SIGN = Button(area={'cn': (1, 7, 104, 47), 'en': (1, 7, 104, 47)}, color={'cn': (158, 214, 229), 'en': (158, 214, 229)}, button={'cn': (1, 7, 104, 47), 'en': (1, 7, 104, 47)}, file={'cn': './assets/cn/handler/LOGIN_RETURN_SIGN.png', 'en': './assets/en/handler/LOGIN_RETURN_SIGN.png'}) +LOGIN_RETURN_SIGN = Button(area={'cn': (1, 7, 104, 47), 'en': (1195, 524, 1272, 547)}, color={'cn': (158, 214, 229), 'en': (202, 202, 203)}, button={'cn': (1, 7, 104, 47), 'en': (1195, 524, 1272, 547)}, file={'cn': './assets/cn/handler/LOGIN_RETURN_SIGN.png', 'en': './assets/en/handler/LOGIN_RETURN_SIGN.png'}) MAP_AIR_RAID = Button(area={'cn': (350, 447, 1280, 472), 'en': (350, 447, 1280, 472)}, color={'cn': (154, 43, 46), 'en': (154, 43, 46)}, button={'cn': (350, 447, 1280, 472), 'en': (350, 447, 1280, 472)}, file={'cn': './assets/cn/handler/MAP_AIR_RAID.png', 'en': './assets/en/handler/MAP_AIR_RAID.png'}) MAP_AMBUSH = Button(area={'cn': (261, 433, 1280, 449), 'en': (261, 433, 1280, 449)}, color={'cn': (161, 41, 43), 'en': (161, 41, 43)}, button={'cn': (261, 433, 1280, 449), 'en': (261, 433, 1280, 449)}, file={'cn': './assets/cn/handler/MAP_AMBUSH.png', 'en': './assets/en/handler/MAP_AMBUSH.png'}) MAP_AMBUSH_EVADE = Button(area={'cn': (325, 393, 1280, 395), 'en': (325, 393, 1280, 395)}, color={'cn': (255, 255, 255), 'en': (255, 255, 255)}, button={'cn': (979, 444, 1152, 502), 'en': (979, 444, 1152, 502)}, file={'cn': './assets/cn/handler/MAP_AMBUSH_EVADE.png', 'en': './assets/en/handler/MAP_AMBUSH_EVADE.png'}) @@ -34,7 +34,7 @@ MAP_GREEN = Button(area={'cn': (195, 260, 349, 292), 'en': (201, 259, 341, 290)} MAP_STAR_1 = Button(area={'cn': (245, 377, 254, 384), 'en': (232, 381, 240, 389)}, color={'cn': (251, 233, 143), 'en': (252, 234, 146)}, button={'cn': (245, 377, 254, 384), 'en': (232, 381, 240, 389)}, file={'cn': './assets/cn/handler/MAP_STAR_1.png', 'en': './assets/en/handler/MAP_STAR_1.png'}) MAP_STAR_2 = Button(area={'cn': (532, 377, 540, 384), 'en': (518, 382, 526, 389)}, color={'cn': (251, 233, 144), 'en': (252, 234, 144)}, button={'cn': (532, 377, 540, 384), 'en': (518, 382, 526, 389)}, file={'cn': './assets/cn/handler/MAP_STAR_2.png', 'en': './assets/en/handler/MAP_STAR_2.png'}) MAP_STAR_3 = Button(area={'cn': (818, 377, 827, 384), 'en': (804, 382, 812, 389)}, color={'cn': (251, 233, 143), 'en': (252, 234, 144)}, button={'cn': (818, 377, 827, 384), 'en': (804, 382, 812, 389)}, file={'cn': './assets/cn/handler/MAP_STAR_3.png', 'en': './assets/en/handler/MAP_STAR_3.png'}) -MAP_WALK_OUT_OF_STEP = Button(area={'cn': (654, 312, 704, 335), 'en': (654, 312, 704, 335)}, color={'cn': (109, 113, 120), 'en': (109, 113, 120)}, button={'cn': (654, 312, 704, 335), 'en': (654, 312, 704, 335)}, file={'cn': './assets/cn/handler/MAP_WALK_OUT_OF_STEP.png', 'en': './assets/en/handler/MAP_WALK_OUT_OF_STEP.png'}) +MAP_WALK_OUT_OF_STEP = Button(area={'cn': (654, 312, 704, 335), 'en': (654, 312, 704, 335)}, color={'cn': (109, 113, 120), 'en': (112, 113, 120)}, button={'cn': (654, 312, 704, 335), 'en': (654, 312, 704, 335)}, file={'cn': './assets/cn/handler/MAP_WALK_OUT_OF_STEP.png', 'en': './assets/en/handler/MAP_WALK_OUT_OF_STEP.png'}) MYSTERY_ITEM = Button(area={'cn': (589, 294, 691, 427), 'en': (589, 294, 691, 427)}, color={'cn': (144, 127, 83), 'en': (144, 127, 83)}, button={'cn': (589, 294, 691, 427), 'en': (589, 294, 691, 427)}, file={'cn': './assets/cn/handler/MYSTERY_ITEM.png', 'en': './assets/en/handler/MYSTERY_ITEM.png'}) POPUP_CANCEL = Button(area={'cn': (404, 493, 576, 550), 'en': (403, 481, 577, 541)}, color={'cn': (166, 169, 172), 'en': (170, 172, 174)}, button={'cn': (404, 493, 576, 550), 'en': (403, 481, 577, 541)}, file={'cn': './assets/cn/handler/POPUP_CANCEL.png', 'en': './assets/en/handler/POPUP_CANCEL.png'}) POPUP_CONFIRM = Button(area={'cn': (704, 493, 876, 550), 'en': (703, 481, 877, 541)}, color={'cn': (94, 144, 204), 'en': (107, 152, 207)}, button={'cn': (704, 493, 876, 550), 'en': (703, 481, 877, 541)}, file={'cn': './assets/cn/handler/POPUP_CONFIRM.png', 'en': './assets/en/handler/POPUP_CONFIRM.png'}) diff --git a/module/reward/assets.py b/module/reward/assets.py index ba2e24d16..c4a002b42 100644 --- a/module/reward/assets.py +++ b/module/reward/assets.py @@ -12,10 +12,10 @@ COMMISSION_NOTICE_AT_CAMPAIGN = Button(area={'cn': (1054, 647, 1061, 654), 'en': COMMISSION_START = Button(area={'cn': (1028, 322, 1156, 383), 'en': (1031, 333, 1147, 383)}, color={'cn': (229, 175, 113), 'en': (227, 169, 108)}, button={'cn': (1028, 322, 1156, 383), 'en': (1031, 333, 1147, 383)}, file={'cn': './assets/cn/reward/COMMISSION_START.png', 'en': './assets/en/reward/COMMISSION_START.png'}) COMMISSION_STOP_SCROLLING = Button(area={'cn': (115, 236, 179, 487), 'en': (115, 236, 179, 487)}, color={'cn': (50, 55, 74), 'en': (50, 55, 74)}, button={'cn': (115, 236, 179, 487), 'en': (115, 236, 179, 487)}, file={'cn': './assets/cn/reward/COMMISSION_STOP_SCROLLING.png', 'en': './assets/en/reward/COMMISSION_STOP_SCROLLING.png'}) COMMISSION_URGENT = Button(area={'cn': (35, 231, 68, 281), 'en': (28, 221, 76, 283)}, color={'cn': (215, 188, 124), 'en': (169, 138, 95)}, button={'cn': (35, 231, 68, 281), 'en': (28, 221, 76, 283)}, file={'cn': './assets/cn/reward/COMMISSION_URGENT.png', 'en': './assets/en/reward/COMMISSION_URGENT.png'}) -EXP_INFO_S_REWARD = Button(area={'cn': (498, 140, 557, 154), 'en': (498, 140, 557, 154)}, color={'cn': (233, 241, 127), 'en': (105, 119, 139)}, button={'cn': (498, 140, 557, 154), 'en': (498, 140, 557, 154)}, file={'cn': './assets/cn/reward/EXP_INFO_S_REWARD.png', 'en': './assets/en/reward/EXP_INFO_S_REWARD.png'}) -MISSION_MULTI = Button(area={'cn': (1041, 8, 1101, 39), 'en': (1041, 8, 1101, 39)}, color={'cn': (226, 192, 142), 'en': (226, 192, 142)}, button={'cn': (1041, 8, 1101, 39), 'en': (1041, 8, 1101, 39)}, file={'cn': './assets/cn/reward/MISSION_MULTI.png', 'en': './assets/en/reward/MISSION_MULTI.png'}) +EXP_INFO_S_REWARD = Button(area={'cn': (498, 140, 557, 154), 'en': (477, 132, 521, 144)}, color={'cn': (233, 241, 127), 'en': (233, 241, 126)}, button={'cn': (498, 140, 557, 154), 'en': (477, 132, 521, 144)}, file={'cn': './assets/cn/reward/EXP_INFO_S_REWARD.png', 'en': './assets/en/reward/EXP_INFO_S_REWARD.png'}) +MISSION_MULTI = Button(area={'cn': (1041, 8, 1101, 39), 'en': (1041, 8, 1101, 39)}, color={'cn': (226, 192, 142), 'en': (221, 179, 96)}, button={'cn': (1041, 8, 1101, 39), 'en': (1041, 8, 1101, 39)}, file={'cn': './assets/cn/reward/MISSION_MULTI.png', 'en': './assets/en/reward/MISSION_MULTI.png'}) MISSION_NOTICE = Button(area={'cn': (940, 670, 945, 681), 'en': (940, 670, 945, 681)}, color={'cn': (183, 83, 66), 'en': (183, 83, 66)}, button={'cn': (940, 670, 945, 681), 'en': (940, 670, 945, 681)}, file={'cn': './assets/cn/reward/MISSION_NOTICE.png', 'en': './assets/en/reward/MISSION_NOTICE.png'}) -MISSION_SINGLE = Button(area={'cn': (1093, 118, 1179, 177), 'en': (1093, 118, 1179, 177)}, color={'cn': (115, 155, 218), 'en': (115, 155, 218)}, button={'cn': (1093, 118, 1179, 177), 'en': (1093, 118, 1179, 177)}, file={'cn': './assets/cn/reward/MISSION_SINGLE.png', 'en': './assets/en/reward/MISSION_SINGLE.png'}) +MISSION_SINGLE = Button(area={'cn': (1093, 118, 1179, 177), 'en': (1093, 118, 1179, 177)}, color={'cn': (115, 155, 218), 'en': (106, 147, 215)}, button={'cn': (1093, 118, 1179, 177), 'en': (1093, 118, 1179, 177)}, file={'cn': './assets/cn/reward/MISSION_SINGLE.png', 'en': './assets/en/reward/MISSION_SINGLE.png'}) OIL = Button(area={'cn': (162, 64, 182, 91), 'en': (162, 64, 182, 91)}, color={'cn': (71, 72, 71), 'en': (71, 72, 71)}, button={'cn': (162, 64, 182, 91), 'en': (162, 64, 182, 91)}, file={'cn': './assets/cn/reward/OIL.png', 'en': './assets/en/reward/OIL.png'}) REWARD_1 = Button(area={'cn': (383, 285, 503, 297), 'en': (383, 283, 503, 294)}, color={'cn': (238, 168, 81), 'en': (241, 187, 120)}, button={'cn': (383, 285, 503, 297), 'en': (383, 283, 503, 294)}, file={'cn': './assets/cn/reward/REWARD_1.png', 'en': './assets/en/reward/REWARD_1.png'}) REWARD_2 = Button(area={'cn': (383, 404, 503, 444), 'en': (382, 403, 504, 445)}, color={'cn': (233, 165, 67), 'en': (236, 177, 92)}, button={'cn': (383, 404, 503, 444), 'en': (382, 403, 504, 445)}, file={'cn': './assets/cn/reward/REWARD_2.png', 'en': './assets/en/reward/REWARD_2.png'}) diff --git a/module/reward/commission.py b/module/reward/commission.py index c2202b0a6..de375c9ad 100644 --- a/module/reward/commission.py +++ b/module/reward/commission.py @@ -37,7 +37,7 @@ dictionary_en = { 'extra_drill': ['Sailing', 'Defense Patrol', 'Buoy'], 'extra_part': ['veinprotectoncommisionll', 'Forestprtectoncommisionl', 'Forestprotectoncommisionll'], 'extra_cube': ['Exercise'], - 'extra_oil': ['Large-saleoilExtractionlll', 'FleetCargoTransport', 'Large-saleoilExtractianl', 'Large-saleoilExtractionl', 'Large-saleoilExtractiaonll'], + 'extra_oil': ['oilextraction', 'FleetCargoTransport', 'oilExtractianl', '', 'oilExtractiaonll'], 'extra_book': ['LargeMerchantEscort'], 'urgent_drill': ['Cargo Defense', 'Scouts', 'Force', 'Elites', 'FrontierDefensePatrol'], 'urgent_part': ['Lavella', 'Maui', 'Rendova', 'AidingWongbanna'], @@ -181,7 +181,7 @@ class Commission: Returns: timedelta: datetime.timedelta instance. """ - string = string.replace('D', '0') # Poor OCR + string = string.replace('D', '0').replace(' ', '').replace('-', '') # Poor OCR result = re.search('(\d+):(\d+):(\d+)', string) if not result: logger.warning(f'Invalid time string: {string}') diff --git a/module/ui/assets.py b/module/ui/assets.py index 7509177f1..b4f9dbf55 100644 --- a/module/ui/assets.py +++ b/module/ui/assets.py @@ -12,7 +12,7 @@ CAMPAIGN_GOTO_EXERCISE = Button(area={'cn': (1166, 648, 1248, 703), 'en': (1150, COMMISSION_CHECK = Button(area={'cn': (122, 16, 175, 39), 'en': (120, 14, 301, 41)}, color={'cn': (157, 173, 210), 'en': (98, 112, 150)}, button={'cn': (122, 16, 175, 39), 'en': (120, 14, 301, 41)}, file={'cn': './assets/cn/ui/COMMISSION_CHECK.png', 'en': './assets/en/ui/COMMISSION_CHECK.png'}) DAILY_CHECK = Button(area={'cn': (23, 656, 67, 698), 'en': (23, 656, 67, 698)}, color={'cn': (84, 139, 210), 'en': (84, 139, 210)}, button={'cn': (23, 656, 67, 698), 'en': (23, 656, 67, 698)}, file={'cn': './assets/cn/ui/DAILY_CHECK.png', 'en': './assets/en/ui/DAILY_CHECK.png'}) EVENT_CHECK = Button(area={'cn': (123, 63, 206, 109), 'en': (123, 63, 206, 109)}, color={'cn': (88, 104, 138), 'en': (88, 104, 138)}, button={'cn': (123, 63, 206, 109), 'en': (123, 63, 206, 109)}, file={'cn': './assets/cn/ui/EVENT_CHECK.png', 'en': './assets/en/ui/EVENT_CHECK.png'}) -EVENT_LIST_CHECK = Button(area={'cn': (123, 15, 232, 39), 'en': (123, 15, 232, 39)}, color={'cn': (151, 166, 206), 'en': (151, 166, 206)}, button={'cn': (123, 15, 232, 39), 'en': (123, 15, 232, 39)}, file={'cn': './assets/cn/ui/EVENT_LIST_CHECK.png', 'en': './assets/en/ui/EVENT_LIST_CHECK.png'}) +EVENT_LIST_CHECK = Button(area={'cn': (123, 15, 232, 39), 'en': (123, 15, 223, 39)}, color={'cn': (151, 166, 206), 'en': (109, 122, 163)}, button={'cn': (123, 15, 232, 39), 'en': (123, 15, 223, 39)}, file={'cn': './assets/cn/ui/EVENT_LIST_CHECK.png', 'en': './assets/en/ui/EVENT_LIST_CHECK.png'}) EXERCISE_CHECK = Button(area={'cn': (1065, 340, 1204, 382), 'en': (1078, 343, 1190, 382)}, color={'cn': (129, 166, 220), 'en': (138, 174, 225)}, button={'cn': (1065, 340, 1204, 382), 'en': (1078, 343, 1190, 382)}, file={'cn': './assets/cn/ui/EXERCISE_CHECK.png', 'en': './assets/en/ui/EXERCISE_CHECK.png'}) FLEET_CHECK = Button(area={'cn': (1044, 641, 1243, 702), 'en': (1042, 640, 1244, 703)}, color={'cn': (237, 186, 112), 'en': (236, 187, 113)}, button={'cn': (1044, 641, 1243, 702), 'en': (1042, 640, 1244, 703)}, file={'cn': './assets/cn/ui/FLEET_CHECK.png', 'en': './assets/en/ui/FLEET_CHECK.png'}) GOTO_MAIN = Button(area={'cn': (1230, 17, 1253, 45), 'en': (1230, 17, 1253, 45)}, color={'cn': (112, 132, 159), 'en': (112, 132, 159)}, button={'cn': (1228, 18, 1255, 49), 'en': (1228, 18, 1255, 49)}, file={'cn': './assets/cn/ui/GOTO_MAIN.png', 'en': './assets/en/ui/GOTO_MAIN.png'})